1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=78: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
24 * Johnny Stenback <jst@netscape.com>
25 * L. David Baron <dbaron@dbaron.org>
26 * Pierre Phaneuf <pp@ludusdesign.com>
27 * Pete Collins <petejc@collab.net>
28 * James Ross <silver@warwickcompsoc.co.uk>
29 * Ryan Jones <sciguyryan@gmail.com>
31 * Alternatively, the contents of this file may be used under the terms of
32 * either of the GNU General Public License Version 2 or later (the "GPL"),
33 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
34 * in which case the provisions of the GPL or the LGPL are applicable instead
35 * of those above. If you wish to allow use of your version of this file only
36 * under the terms of either the GPL or the LGPL, and not to allow others to
37 * use your version of this file under the terms of the MPL, indicate your
38 * decision by deleting the provisions above and replace them with the notice
39 * and other provisions required by the GPL or the LGPL. If you do not delete
40 * the provisions above, a recipient may use your version of this file under
41 * the terms of any one of the MPL, the GPL or the LGPL.
43 * ***** END LICENSE BLOCK ***** */
46 * Base class for all our document implementations.
52 #include "nsIInterfaceRequestor.h"
53 #include "nsIInterfaceRequestorUtils.h"
54 #include "nsDocument.h"
55 #include "nsUnicharUtils.h"
56 #include "nsIPrivateDOMEvent.h"
57 #include "nsIEventStateManager.h"
58 #include "nsIFocusController.h"
59 #include "nsContentList.h"
60 #include "nsIObserver.h"
61 #include "nsIBaseWindow.h"
62 #include "nsIDocShell.h"
63 #include "nsIDocShellTreeItem.h"
64 #include "nsIScriptRuntime.h"
65 #include "nsCOMArray.h"
67 #include "nsGUIEvent.h"
69 #include "nsIDOMStyleSheet.h"
70 #include "nsDOMAttribute.h"
71 #include "nsIDOMDOMStringList.h"
72 #include "nsIDOMDOMImplementation.h"
73 #include "nsIDOMDocumentView.h"
74 #include "nsIDOMAbstractView.h"
75 #include "nsIDOMDocumentXBL.h"
76 #include "nsGenericElement.h"
77 #include "nsGenericHTMLElement.h"
78 #include "nsIDOMEventGroup.h"
79 #include "nsIDOMCDATASection.h"
80 #include "nsIDOMProcessingInstruction.h"
81 #include "nsDOMString.h"
82 #include "nsNodeUtils.h"
83 #include "nsLayoutUtils.h" // for GetFrameForPoint
87 #include "nsIDOMText.h"
88 #include "nsIDOMComment.h"
89 #include "nsDOMDocumentType.h"
90 #include "nsNodeIterator.h"
91 #include "nsTreeWalker.h"
93 #include "nsIServiceManager.h"
95 #include "nsContentCID.h"
96 #include "nsDOMError.h"
97 #include "nsIPresShell.h"
98 #include "nsPresContext.h"
99 #include "nsThreadUtils.h"
100 #include "nsNodeInfoManager.h"
101 #include "nsIXBLService.h"
102 #include "nsIXPointer.h"
103 #include "nsIFileChannel.h"
104 #include "nsIMultiPartChannel.h"
105 #include "nsIRefreshURI.h"
106 #include "nsIWebNavigation.h"
107 #include "nsIScriptError.h"
109 #include "nsNetUtil.h" // for NS_MakeAbsoluteURI
111 #include "nsIScriptSecurityManager.h"
112 #include "nsIPrincipal.h"
113 #include "nsIPrivateDOMImplementation.h"
115 #include "nsIDOMWindowInternal.h"
116 #include "nsPIDOMWindow.h"
117 #include "nsIDOMElement.h"
119 // for radio group stuff
120 #include "nsIDOMHTMLInputElement.h"
121 #include "nsIRadioVisitor.h"
122 #include "nsIFormControl.h"
124 #include "nsXMLEventsManager.h"
126 #include "nsBidiUtils.h"
128 static NS_DEFINE_CID(kDOMEventGroupCID
, NS_DOMEVENTGROUP_CID
);
130 #include "nsIDOMUserDataHandler.h"
131 #include "nsScriptEventManager.h"
132 #include "nsIDOMXPathEvaluator.h"
133 #include "nsIXPathEvaluatorInternal.h"
134 #include "nsIParserService.h"
135 #include "nsContentCreatorFunctions.h"
137 #include "nsIScriptContext.h"
138 #include "nsBindingManager.h"
139 #include "nsIDOMHTMLDocument.h"
140 #include "nsIDOMHTMLFormElement.h"
141 #include "nsIRequest.h"
144 #include "nsICharsetAlias.h"
145 #include "nsIParser.h"
146 #include "nsIContentSink.h"
148 #include "nsDateTimeFormatCID.h"
149 #include "nsIDateTimeFormat.h"
150 #include "nsEventDispatcher.h"
151 #include "nsMutationEvent.h"
152 #include "nsIDOMXPathEvaluator.h"
153 #include "nsDOMCID.h"
155 #include "nsIJSContextStack.h"
156 #include "nsIXPConnect.h"
157 #include "nsCycleCollector.h"
158 #include "nsCCUncollectableMarker.h"
159 #include "nsIContentPolicy.h"
160 #include "nsContentPolicyUtils.h"
161 #include "nsICategoryManager.h"
162 #include "nsIDocumentLoaderFactory.h"
163 #include "nsIContentViewer.h"
164 #include "nsIXMLContentSink.h"
165 #include "nsContentErrors.h"
166 #include "nsIXULDocument.h"
167 #include "nsIPrompt.h"
168 #include "nsIPropertyBag2.h"
170 #include "nsFrameLoader.h"
172 #include "mozAutoDocUpdate.h"
176 // so we can get logging even in release builds
177 #define FORCE_PR_LOG 1
182 static PRLogModuleInfo
* gDocumentLeakPRLog
;
186 nsUint32ToContentHashEntry::Destroy()
188 HashSet
* set
= GetHashSet();
192 nsIContent
* content
= GetContent();
193 NS_IF_RELEASE(content
);
198 nsUint32ToContentHashEntry::PutContent(nsIContent
* aVal
)
200 // Add the value to the hash if it is there
201 HashSet
* set
= GetHashSet();
203 nsISupportsHashKey
* entry
= set
->PutEntry(aVal
);
204 return entry
? NS_OK
: NS_ERROR_OUT_OF_MEMORY
;
207 // If an element is already there, create a hashtable and both of these to it
208 nsIContent
* oldVal
= GetContent();
210 nsresult rv
= InitHashSet(&set
);
211 NS_ENSURE_SUCCESS(rv
, rv
);
213 nsISupportsHashKey
* entry
= set
->PutEntry(oldVal
);
215 // OOM - we can't insert aVal, but we can at least put oldVal back (even
216 // if we didn't, we'd still have to release oldVal so that we don't leak)
219 // SetContent adds another reference, so release the one we had
221 return NS_ERROR_OUT_OF_MEMORY
;
223 // The hashset adds its own reference, so release the one we had
226 entry
= set
->PutEntry(aVal
);
227 return entry
? NS_OK
: NS_ERROR_OUT_OF_MEMORY
;
230 // Nothing exists in the hash right now, so just set the single pointer
231 return SetContent(aVal
);
235 nsUint32ToContentHashEntry::RemoveContent(nsIContent
* aVal
)
237 // Remove from the hash if the hash is there
238 HashSet
* set
= GetHashSet();
240 set
->RemoveEntry(aVal
);
241 if (set
->Count() == 0) {
248 // Remove the ptr if there is just a ptr
249 nsIContent
* v
= GetContent();
257 nsUint32ToContentHashEntry::InitHashSet(HashSet
** aSet
)
259 HashSet
* newSet
= new HashSet();
261 return NS_ERROR_OUT_OF_MEMORY
;
264 nsresult rv
= newSet
->Init();
265 NS_ENSURE_SUCCESS(rv
, rv
);
272 static PLDHashOperator
273 nsUint32ToContentHashEntryVisitorCallback(nsISupportsHashKey
* aEntry
,
276 nsUint32ToContentHashEntry::Visitor
* visitor
=
277 static_cast<nsUint32ToContentHashEntry::Visitor
*>(aClosure
);
278 visitor
->Visit(static_cast<nsIContent
*>(aEntry
->GetKey()));
279 return PL_DHASH_NEXT
;
283 nsUint32ToContentHashEntry::VisitContent(Visitor
* aVisitor
)
285 HashSet
* set
= GetHashSet();
287 set
->EnumerateEntries(nsUint32ToContentHashEntryVisitorCallback
, aVisitor
);
288 if (set
->Count() == 0) {
295 nsIContent
* v
= GetContent();
301 #define ID_NOT_IN_DOCUMENT ((nsIContent *)2)
302 #define NAME_NOT_VALID ((nsBaseContentList*)1)
304 nsIdentifierMapEntry::~nsIdentifierMapEntry()
306 if (mNameContentList
&& mNameContentList
!= NAME_NOT_VALID
) {
307 NS_RELEASE(mNameContentList
);
312 nsIdentifierMapEntry::Traverse(nsCycleCollectionTraversalCallback
* aCallback
)
314 if (mNameContentList
!= NAME_NOT_VALID
) {
315 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback
,
316 "mIdentifierMap mNameContentList");
317 aCallback
->NoteXPCOMChild(static_cast<nsIDOMNodeList
*>(mNameContentList
));
320 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback
, "mIdentifierMap mDocAllList");
321 aCallback
->NoteXPCOMChild(static_cast<nsIDOMNodeList
*>(mDocAllList
));
325 nsIdentifierMapEntry::SetInvalidName()
327 mNameContentList
= NAME_NOT_VALID
;
331 nsIdentifierMapEntry::IsInvalidName()
333 return mNameContentList
== NAME_NOT_VALID
;
337 nsIdentifierMapEntry::CreateNameContentList()
339 mNameContentList
= new nsBaseContentList();
340 NS_ENSURE_TRUE(mNameContentList
, NS_ERROR_OUT_OF_MEMORY
);
341 NS_ADDREF(mNameContentList
);
346 nsIdentifierMapEntry::GetIdContent(PRBool
* aNotInDocument
)
348 nsIContent
* c
= static_cast<nsIContent
*>(mIdContentList
.SafeElementAt(0));
349 if (aNotInDocument
) {
350 *aNotInDocument
= c
== ID_NOT_IN_DOCUMENT
;
352 return c
!= ID_NOT_IN_DOCUMENT
? c
: nsnull
;
356 nsIdentifierMapEntry::AppendAllIdContent(nsCOMArray
<nsIContent
>* aElements
)
358 for (PRInt32 i
= 0; i
< mIdContentList
.Count(); ++i
) {
359 aElements
->AppendObject(static_cast<nsIContent
*>(mIdContentList
[i
]));
364 nsIdentifierMapEntry::AddContentChangeCallback(nsIDocument::IDTargetObserver aCallback
,
367 if (!mChangeCallbacks
) {
368 mChangeCallbacks
= new nsTHashtable
<ChangeCallbackEntry
>;
369 if (!mChangeCallbacks
)
371 mChangeCallbacks
->Init();
374 ChangeCallback cc
= { aCallback
, aData
};
375 mChangeCallbacks
->PutEntry(cc
);
379 nsIdentifierMapEntry::RemoveContentChangeCallback(nsIDocument::IDTargetObserver aCallback
,
382 if (!mChangeCallbacks
)
384 ChangeCallback cc
= { aCallback
, aData
};
385 mChangeCallbacks
->RemoveEntry(cc
);
386 if (mChangeCallbacks
->Count() == 0) {
387 mChangeCallbacks
= nsnull
;
391 struct FireChangeArgs
{
396 static PLDHashOperator
397 FireChangeEnumerator(nsIdentifierMapEntry::ChangeCallbackEntry
*aEntry
, void *aArg
)
399 FireChangeArgs
* args
= static_cast<FireChangeArgs
*>(aArg
);
400 return aEntry
->mKey
.mCallback(args
->mFrom
, args
->mTo
, aEntry
->mKey
.mData
)
401 ? PL_DHASH_NEXT
: PL_DHASH_REMOVE
;
405 nsIdentifierMapEntry::FireChangeCallbacks(nsIContent
* aOldContent
,
406 nsIContent
* aNewContent
)
408 if (!mChangeCallbacks
)
411 FireChangeArgs args
= { aOldContent
, aNewContent
};
412 mChangeCallbacks
->EnumerateEntries(FireChangeEnumerator
, &args
);
416 nsIdentifierMapEntry::AddIdContent(nsIContent
* aContent
)
418 NS_PRECONDITION(aContent
, "Must have content");
419 NS_PRECONDITION(mIdContentList
.IndexOf(nsnull
) < 0,
420 "Why is null in our list?");
421 NS_PRECONDITION(aContent
!= ID_NOT_IN_DOCUMENT
,
422 "Bogus content pointer");
424 nsIContent
* currentContent
= static_cast<nsIContent
*>(mIdContentList
.SafeElementAt(0));
425 if (currentContent
== ID_NOT_IN_DOCUMENT
) {
426 NS_ASSERTION(mIdContentList
.Count() == 1, "Bogus count");
427 mIdContentList
.ReplaceElementAt(aContent
, 0);
428 FireChangeCallbacks(nsnull
, aContent
);
433 if (mIdContentList
.Count() == 0) {
434 if (!mIdContentList
.AppendElement(aContent
))
436 FireChangeCallbacks(nsnull
, aContent
);
440 // We seem to have multiple content nodes for the same id, or we're doing our
441 // top-down registration when the id table is going live. Search for the
442 // right place to insert the content.
444 PRInt32 end
= mIdContentList
.Count();
446 NS_ASSERTION(start
< end
, "Bogus start/end");
448 PRInt32 cur
= (start
+ end
) / 2;
449 NS_ASSERTION(cur
>= start
&& cur
< end
, "What happened here?");
451 nsIContent
* curContent
= static_cast<nsIContent
*>(mIdContentList
[cur
]);
452 if (curContent
== aContent
) {
453 // Already in the list, so already in the right spot. Get out of here.
457 if (nsContentUtils::PositionIsBefore(aContent
, curContent
)) {
462 } while (start
!= end
);
464 if (!mIdContentList
.InsertElementAt(aContent
, start
))
467 FireChangeCallbacks(currentContent
, aContent
);
473 nsIdentifierMapEntry::RemoveIdContent(nsIContent
* aContent
)
475 // This should only be called while the document is in an update.
476 // Assertions near the call to this method guarantee this.
478 // XXXbz should this ever Compact() I guess when all the content is gone
479 // we'll just get cleaned up in the natural order of things...
480 nsIContent
* currentContent
= static_cast<nsIContent
*>(mIdContentList
.SafeElementAt(0));
481 if (!mIdContentList
.RemoveElement(aContent
))
483 if (currentContent
== aContent
) {
484 FireChangeCallbacks(currentContent
,
485 static_cast<nsIContent
*>(mIdContentList
.SafeElementAt(0)));
487 return mIdContentList
.Count() == 0 && !mNameContentList
&& !mChangeCallbacks
;
491 nsIdentifierMapEntry::FlagIDNotInDocument()
493 NS_ASSERTION(mIdContentList
.Count() == 0,
494 "Flagging ID not in document when we have content?");
495 // Note that if this fails that's OK; this is just an optimization
496 mIdContentList
.AppendElement(ID_NOT_IN_DOCUMENT
);
500 nsIdentifierMapEntry::AddNameContent(nsIContent
* aContent
)
502 if (!mNameContentList
|| mNameContentList
== NAME_NOT_VALID
)
505 // NOTE: this indexof is absolutely needed, since we don't flush
506 // content notifications when we do document.foo resolution. So
507 // aContent may be in our list already and just now getting notified
509 if (mNameContentList
->IndexOf(aContent
, PR_FALSE
) < 0) {
510 mNameContentList
->AppendElement(aContent
);
515 nsIdentifierMapEntry::RemoveNameContent(nsIContent
* aContent
)
517 if (mNameContentList
&& mNameContentList
!= NAME_NOT_VALID
) {
518 mNameContentList
->RemoveElement(aContent
);
522 // Helper structs for the content->subdoc map
524 class SubDocMapEntry
: public PLDHashEntryHdr
527 // Both of these are strong references
528 nsIContent
*mKey
; // must be first, to look like PLDHashEntryStub
529 nsIDocument
*mSubDocument
;
532 struct FindContentData
534 FindContentData(nsIDocument
*aSubDoc
)
535 : mSubDocument(aSubDoc
), mResult(nsnull
)
539 nsISupports
*mSubDocument
;
545 * A struct that holds all the information about a radio group.
547 struct nsRadioGroupStruct
550 * A strong pointer to the currently selected radio button.
552 nsCOMPtr
<nsIDOMHTMLInputElement
> mSelectedRadioButton
;
553 nsCOMArray
<nsIFormControl
> mRadioButtons
;
557 nsDOMStyleSheetList::nsDOMStyleSheetList(nsIDocument
*aDocument
)
560 // Not reference counted to avoid circular references.
561 // The document will tell us when its going away.
562 mDocument
= aDocument
;
563 mDocument
->AddObserver(this);
566 nsDOMStyleSheetList::~nsDOMStyleSheetList()
569 mDocument
->RemoveObserver(this);
573 // XXX couldn't we use the GetIIDs method from CSSStyleSheetList here?
574 // QueryInterface implementation for nsDOMStyleSheetList
575 NS_INTERFACE_TABLE_HEAD(nsDOMStyleSheetList
)
576 NS_INTERFACE_TABLE3(nsDOMStyleSheetList
,
577 nsIDOMStyleSheetList
,
580 NS_INTERFACE_TABLE_TO_MAP_SEGUE
581 NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(DocumentStyleSheetList
)
585 NS_IMPL_ADDREF(nsDOMStyleSheetList
)
586 NS_IMPL_RELEASE(nsDOMStyleSheetList
)
590 nsDOMStyleSheetList::GetLength(PRUint32
* aLength
)
593 // XXX Find the number and then cache it. We'll use the
594 // observer notification to figure out if new ones have
595 // been added or removed.
597 mLength
= mDocument
->GetNumberOfStyleSheets();
601 for (i
= 0; i
< mLength
; i
++) {
602 nsIStyleSheet
*sheet
= mDocument
->GetStyleSheetAt(i
);
603 nsCOMPtr
<nsIDOMStyleSheet
> domss(do_QueryInterface(sheet
));
604 NS_ASSERTION(domss
, "All \"normal\" sheets implement nsIDOMStyleSheet");
618 nsDOMStyleSheetList::GetItemAt(PRUint32 aIndex
)
620 if (!mDocument
|| aIndex
>= (PRUint32
)mDocument
->GetNumberOfStyleSheets()) {
624 nsIStyleSheet
*sheet
= mDocument
->GetStyleSheetAt(aIndex
);
625 NS_ASSERTION(sheet
, "Must have a sheet");
631 nsDOMStyleSheetList::Item(PRUint32 aIndex
, nsIDOMStyleSheet
** aReturn
)
633 nsIStyleSheet
*sheet
= GetItemAt(aIndex
);
640 return CallQueryInterface(sheet
, aReturn
);
644 nsDOMStyleSheetList::NodeWillBeDestroyed(const nsINode
*aNode
)
650 nsDOMStyleSheetList::StyleSheetAdded(nsIDocument
*aDocument
,
651 nsIStyleSheet
* aStyleSheet
,
652 PRBool aDocumentSheet
)
654 if (aDocumentSheet
&& -1 != mLength
) {
655 nsCOMPtr
<nsIDOMStyleSheet
> domss(do_QueryInterface(aStyleSheet
));
663 nsDOMStyleSheetList::StyleSheetRemoved(nsIDocument
*aDocument
,
664 nsIStyleSheet
* aStyleSheet
,
665 PRBool aDocumentSheet
)
667 if (aDocumentSheet
&& -1 != mLength
) {
668 nsCOMPtr
<nsIDOMStyleSheet
> domss(do_QueryInterface(aStyleSheet
));
675 // nsOnloadBlocker implementation
676 NS_IMPL_ISUPPORTS1(nsOnloadBlocker
, nsIRequest
)
679 nsOnloadBlocker::GetName(nsACString
&aResult
)
681 aResult
.AssignLiteral("about:document-onload-blocker");
686 nsOnloadBlocker::IsPending(PRBool
*_retval
)
693 nsOnloadBlocker::GetStatus(nsresult
*status
)
700 nsOnloadBlocker::Cancel(nsresult status
)
705 nsOnloadBlocker::Suspend(void)
710 nsOnloadBlocker::Resume(void)
716 nsOnloadBlocker::GetLoadGroup(nsILoadGroup
* *aLoadGroup
)
718 *aLoadGroup
= nsnull
;
723 nsOnloadBlocker::SetLoadGroup(nsILoadGroup
* aLoadGroup
)
729 nsOnloadBlocker::GetLoadFlags(nsLoadFlags
*aLoadFlags
)
731 *aLoadFlags
= nsIRequest::LOAD_NORMAL
;
736 nsOnloadBlocker::SetLoadFlags(nsLoadFlags aLoadFlags
)
741 // ==================================================================
743 nsExternalResourceMap::nsExternalResourceMap()
744 : mHaveShutDown(PR_FALSE
)
747 mPendingLoads
.Init();
751 nsExternalResourceMap::RequestResource(nsIURI
* aURI
,
752 nsINode
* aRequestingNode
,
753 nsDocument
* aDisplayDocument
,
754 ExternalResourceLoad
** aPendingLoad
)
756 // If we ever start allowing non-same-origin loads here, we might need to do
757 // something interesting with aRequestingPrincipal even for the hashtable
759 NS_PRECONDITION(aURI
, "Must have a URI");
760 NS_PRECONDITION(aRequestingNode
, "Must have a node");
761 *aPendingLoad
= nsnull
;
766 // First, make sure we strip the ref from aURI.
767 nsCOMPtr
<nsIURI
> clone
;
768 aURI
->Clone(getter_AddRefs(clone
));
772 nsCOMPtr
<nsIURL
> url(do_QueryInterface(clone
));
774 url
->SetRef(EmptyCString());
777 ExternalResource
* resource
;
778 mMap
.Get(clone
, &resource
);
780 return resource
->mDocument
;
783 nsRefPtr
<PendingLoad
> load
;
784 mPendingLoads
.Get(clone
, getter_AddRefs(load
));
786 NS_ADDREF(*aPendingLoad
= load
);
790 load
= new PendingLoad(aDisplayDocument
);
795 if (!mPendingLoads
.Put(clone
, load
)) {
799 if (NS_FAILED(load
->StartLoad(clone
, aRequestingNode
))) {
800 // Make sure we don't thrash things by trying this load again, since
801 // chances are it failed for good reasons (security check, etc).
802 AddExternalResource(clone
, nsnull
, nsnull
, aDisplayDocument
);
804 NS_ADDREF(*aPendingLoad
= load
);
811 nsExternalResourceEnumArgs
813 nsIDocument::nsSubDocEnumFunc callback
;
817 static PLDHashOperator
818 ExternalResourceEnumerator(nsIURI
* aKey
,
819 nsExternalResourceMap::ExternalResource
* aData
,
822 nsExternalResourceEnumArgs
* args
=
823 static_cast<nsExternalResourceEnumArgs
*>(aClosure
);
825 aData
->mDocument
? args
->callback(aData
->mDocument
, args
->data
) : PR_TRUE
;
826 return next
? PL_DHASH_NEXT
: PL_DHASH_STOP
;
830 nsExternalResourceMap::EnumerateResources(nsIDocument::nsSubDocEnumFunc aCallback
,
833 nsExternalResourceEnumArgs args
= { aCallback
, aData
};
834 mMap
.EnumerateRead(ExternalResourceEnumerator
, &args
);
837 static PLDHashOperator
838 ExternalResourceTraverser(nsIURI
* aKey
,
839 nsExternalResourceMap::ExternalResource
* aData
,
842 nsCycleCollectionTraversalCallback
*cb
=
843 static_cast<nsCycleCollectionTraversalCallback
*>(aClosure
);
845 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
846 "mExternalResourceMap.mMap entry"
848 cb
->NoteXPCOMChild(aData
->mDocument
);
850 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
851 "mExternalResourceMap.mMap entry"
853 cb
->NoteXPCOMChild(aData
->mViewer
);
855 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
856 "mExternalResourceMap.mMap entry"
858 cb
->NoteXPCOMChild(aData
->mLoadGroup
);
860 return PL_DHASH_NEXT
;
864 nsExternalResourceMap::Traverse(nsCycleCollectionTraversalCallback
* aCallback
) const
866 // mPendingLoads will get cleared out as the requests complete, so
867 // no need to worry about those here.
868 mMap
.EnumerateRead(ExternalResourceTraverser
, aCallback
);
872 nsExternalResourceMap::AddExternalResource(nsIURI
* aURI
,
873 nsIDocumentViewer
* aViewer
,
874 nsILoadGroup
* aLoadGroup
,
875 nsIDocument
* aDisplayDocument
)
877 NS_PRECONDITION(aURI
, "Unexpected call");
878 NS_PRECONDITION((aViewer
&& aLoadGroup
) || (!aViewer
&& !aLoadGroup
),
879 "Must have both or neither");
881 nsRefPtr
<PendingLoad
> load
;
882 mPendingLoads
.Get(aURI
, getter_AddRefs(load
));
883 mPendingLoads
.Remove(aURI
);
887 nsCOMPtr
<nsIDocument
> doc
;
889 aViewer
->GetDocument(getter_AddRefs(doc
));
890 NS_ASSERTION(doc
, "Must have a document");
892 nsCOMPtr
<nsIXULDocument
> xulDoc
= do_QueryInterface(doc
);
894 // We don't handle XUL stuff here yet.
895 rv
= NS_ERROR_NOT_AVAILABLE
;
897 doc
->SetDisplayDocument(aDisplayDocument
);
899 rv
= aViewer
->Init(nsnull
, nsRect(0, 0, 0, 0));
900 if (NS_SUCCEEDED(rv
)) {
901 rv
= aViewer
->Open(nsnull
, nsnull
);
912 ExternalResource
* newResource
= new ExternalResource();
913 if (newResource
&& !mMap
.Put(aURI
, newResource
)) {
915 newResource
= nsnull
;
916 if (NS_SUCCEEDED(rv
)) {
917 rv
= NS_ERROR_OUT_OF_MEMORY
;
922 newResource
->mDocument
= doc
;
923 newResource
->mViewer
= aViewer
;
924 newResource
->mLoadGroup
= aLoadGroup
;
927 const nsTArray
< nsCOMPtr
<nsIObserver
> > & obs
= load
->Observers();
928 for (PRUint32 i
= 0; i
< obs
.Length(); ++i
) {
929 obs
[i
]->Observe(doc
, "external-resource-document-created", nsnull
);
935 NS_IMPL_ISUPPORTS2(nsExternalResourceMap::PendingLoad
,
940 nsExternalResourceMap::PendingLoad::OnStartRequest(nsIRequest
*aRequest
,
941 nsISupports
*aContext
)
943 nsExternalResourceMap
& map
= mDisplayDocument
->ExternalResourceMap();
944 if (map
.HaveShutDown()) {
945 return NS_BINDING_ABORTED
;
948 nsCOMPtr
<nsIDocumentViewer
> viewer
;
949 nsCOMPtr
<nsILoadGroup
> loadGroup
;
950 nsresult rv
= SetupViewer(aRequest
, getter_AddRefs(viewer
),
951 getter_AddRefs(loadGroup
));
953 // Make sure to do this no matter what
954 nsresult rv2
= map
.AddExternalResource(mURI
, viewer
, loadGroup
,
959 if (NS_FAILED(rv2
)) {
960 mTargetListener
= nsnull
;
964 return mTargetListener
->OnStartRequest(aRequest
, aContext
);
968 nsExternalResourceMap::PendingLoad::SetupViewer(nsIRequest
* aRequest
,
969 nsIDocumentViewer
** aViewer
,
970 nsILoadGroup
** aLoadGroup
)
972 NS_PRECONDITION(!mTargetListener
, "Unexpected call to OnStartRequest");
974 *aLoadGroup
= nsnull
;
976 nsCOMPtr
<nsIChannel
> chan(do_QueryInterface(aRequest
));
977 NS_ENSURE_TRUE(chan
, NS_ERROR_UNEXPECTED
);
979 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aRequest
));
981 PRBool requestSucceeded
;
982 if (NS_FAILED(httpChannel
->GetRequestSucceeded(&requestSucceeded
)) ||
984 // Bail out on this load, since it looks like we have an HTTP error page
985 return NS_BINDING_ABORTED
;
990 chan
->GetContentType(type
);
992 nsCOMPtr
<nsILoadGroup
> loadGroup
;
993 chan
->GetLoadGroup(getter_AddRefs(loadGroup
));
995 // Give this document its own loadgroup
996 nsCOMPtr
<nsILoadGroup
> newLoadGroup
=
997 do_CreateInstance(NS_LOADGROUP_CONTRACTID
);
998 NS_ENSURE_TRUE(newLoadGroup
, NS_ERROR_OUT_OF_MEMORY
);
999 newLoadGroup
->SetLoadGroup(loadGroup
);
1001 nsCOMPtr
<nsIInterfaceRequestor
> callbacks
;
1002 loadGroup
->GetNotificationCallbacks(getter_AddRefs(callbacks
));
1004 nsCOMPtr
<nsIInterfaceRequestor
> newCallbacks
=
1005 new LoadgroupCallbacks(callbacks
);
1006 newLoadGroup
->SetNotificationCallbacks(newCallbacks
);
1008 // This is some serious hackery cribbed from docshell
1009 nsCOMPtr
<nsICategoryManager
> catMan
=
1010 do_GetService(NS_CATEGORYMANAGER_CONTRACTID
);
1011 NS_ENSURE_TRUE(catMan
, NS_ERROR_NOT_AVAILABLE
);
1012 nsXPIDLCString contractId
;
1013 nsresult rv
= catMan
->GetCategoryEntry("Gecko-Content-Viewers", type
.get(),
1014 getter_Copies(contractId
));
1015 NS_ENSURE_SUCCESS(rv
, rv
);
1016 nsCOMPtr
<nsIDocumentLoaderFactory
> docLoaderFactory
=
1017 do_GetService(contractId
);
1018 NS_ENSURE_TRUE(docLoaderFactory
, NS_ERROR_NOT_AVAILABLE
);
1020 nsCOMPtr
<nsIContentViewer
> viewer
;
1021 nsCOMPtr
<nsIStreamListener
> listener
;
1022 rv
= docLoaderFactory
->CreateInstance("external-resource", chan
, newLoadGroup
,
1023 type
.get(), nsnull
, nsnull
,
1024 getter_AddRefs(listener
),
1025 getter_AddRefs(viewer
));
1026 NS_ENSURE_SUCCESS(rv
, rv
);
1028 nsCOMPtr
<nsIDocumentViewer
> docViewer
= do_QueryInterface(viewer
);
1029 NS_ENSURE_TRUE(docViewer
, NS_ERROR_UNEXPECTED
);
1031 nsCOMPtr
<nsIParser
> parser
= do_QueryInterface(listener
);
1033 /// We don't want to deal with the various fake documents yet
1034 return NS_ERROR_NOT_IMPLEMENTED
;
1037 // We can't handle HTML and other weird things here yet.
1038 nsIContentSink
* sink
= parser
->GetContentSink();
1039 nsCOMPtr
<nsIXMLContentSink
> xmlSink
= do_QueryInterface(sink
);
1041 return NS_ERROR_NOT_IMPLEMENTED
;
1044 listener
.swap(mTargetListener
);
1045 docViewer
.swap(*aViewer
);
1046 newLoadGroup
.swap(*aLoadGroup
);
1051 nsExternalResourceMap::PendingLoad::OnDataAvailable(nsIRequest
* aRequest
,
1052 nsISupports
* aContext
,
1053 nsIInputStream
* aStream
,
1057 NS_PRECONDITION(mTargetListener
, "Shouldn't be getting called!");
1058 if (mDisplayDocument
->ExternalResourceMap().HaveShutDown()) {
1059 return NS_BINDING_ABORTED
;
1061 return mTargetListener
->OnDataAvailable(aRequest
, aContext
, aStream
, aOffset
,
1066 nsExternalResourceMap::PendingLoad::OnStopRequest(nsIRequest
* aRequest
,
1067 nsISupports
* aContext
,
1070 // mTargetListener might be null if SetupViewer or AddExternalResource failed
1071 if (mTargetListener
) {
1072 nsCOMPtr
<nsIStreamListener
> listener
;
1073 mTargetListener
.swap(listener
);
1074 return listener
->OnStopRequest(aRequest
, aContext
, aStatus
);
1081 nsExternalResourceMap::PendingLoad::StartLoad(nsIURI
* aURI
,
1082 nsINode
* aRequestingNode
)
1084 NS_PRECONDITION(aURI
, "Must have a URI");
1085 NS_PRECONDITION(aRequestingNode
, "Must have a node");
1087 // Time to start a load. First, the security checks.
1089 nsIPrincipal
* requestingPrincipal
= aRequestingNode
->NodePrincipal();
1091 nsresult rv
= nsContentUtils::GetSecurityManager()->
1092 CheckLoadURIWithPrincipal(requestingPrincipal
, aURI
,
1093 nsIScriptSecurityManager::STANDARD
);
1094 NS_ENSURE_SUCCESS(rv
, rv
);
1096 rv
= requestingPrincipal
->CheckMayLoad(aURI
, PR_TRUE
);
1097 NS_ENSURE_SUCCESS(rv
, rv
);
1099 PRInt16 shouldLoad
= nsIContentPolicy::ACCEPT
;
1100 rv
= NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OTHER
,
1102 requestingPrincipal
,
1104 EmptyCString(), //mime guess
1107 nsContentUtils::GetContentPolicy(),
1108 nsContentUtils::GetSecurityManager());
1109 if (NS_FAILED(rv
)) return rv
;
1110 if (NS_CP_REJECTED(shouldLoad
)) {
1111 // Disallowed by content policy
1112 return NS_ERROR_CONTENT_BLOCKED
;
1115 nsIDocument
* doc
= aRequestingNode
->GetOwnerDoc();
1117 return NS_ERROR_NOT_AVAILABLE
;
1120 nsCOMPtr
<nsIInterfaceRequestor
> req
= nsContentUtils::GetSameOriginChecker();
1121 NS_ENSURE_TRUE(req
, NS_ERROR_OUT_OF_MEMORY
);
1123 nsCOMPtr
<nsILoadGroup
> loadGroup
= doc
->GetDocumentLoadGroup();
1124 nsCOMPtr
<nsIChannel
> channel
;
1125 rv
= NS_NewChannel(getter_AddRefs(channel
), aURI
, nsnull
, loadGroup
, req
);
1126 NS_ENSURE_SUCCESS(rv
, rv
);
1130 return channel
->AsyncOpen(this, nsnull
);
1133 NS_IMPL_ISUPPORTS1(nsExternalResourceMap::LoadgroupCallbacks
,
1134 nsIInterfaceRequestor
)
1136 #define IMPL_SHIM(_i) \
1137 NS_IMPL_ISUPPORTS1(nsExternalResourceMap::LoadgroupCallbacks::_i##Shim, _i)
1139 IMPL_SHIM(nsILoadContext
)
1140 IMPL_SHIM(nsIProgressEventSink
)
1141 IMPL_SHIM(nsIChannelEventSink
)
1142 IMPL_SHIM(nsISecurityEventSink
)
1143 IMPL_SHIM(nsIApplicationCacheContainer
)
1147 #define IID_IS(_i) aIID.Equals(NS_GET_IID(_i))
1149 #define TRY_SHIM(_i) \
1152 nsCOMPtr<_i> real = do_GetInterface(mCallbacks); \
1154 return NS_NOINTERFACE; \
1156 nsCOMPtr<_i> shim = new _i##Shim(this, real); \
1158 return NS_ERROR_OUT_OF_MEMORY; \
1160 *aSink = shim.forget().get(); \
1166 nsExternalResourceMap::LoadgroupCallbacks::GetInterface(const nsIID
& aIID
,
1170 (IID_IS(nsIPrompt
) || IID_IS(nsIAuthPrompt
) || IID_IS(nsIAuthPrompt2
))) {
1171 return mCallbacks
->GetInterface(aIID
, aSink
);
1176 TRY_SHIM(nsILoadContext
);
1177 TRY_SHIM(nsIProgressEventSink
);
1178 TRY_SHIM(nsIChannelEventSink
);
1179 TRY_SHIM(nsISecurityEventSink
);
1180 TRY_SHIM(nsIApplicationCacheContainer
);
1182 return NS_NOINTERFACE
;
1188 nsExternalResourceMap::ExternalResource::~ExternalResource()
1191 mViewer
->Close(nsnull
);
1196 // ==================================================================
1198 // ==================================================================
1200 // If we ever have an nsIDocumentObserver notification for stylesheet title
1201 // changes, we could make this inherit from nsDOMStringList instead of
1202 // reimplementing nsIDOMDOMStringList.
1203 class nsDOMStyleSheetSetList
: public nsIDOMDOMStringList
1209 NS_DECL_NSIDOMDOMSTRINGLIST
1211 nsDOMStyleSheetSetList(nsIDocument
* aDocument
);
1219 // Rebuild our list of style sets
1220 nsresult
GetSets(nsStringArray
& aStyleSets
);
1222 nsIDocument
* mDocument
; // Our document; weak ref. It'll let us know if it
1226 NS_IMPL_ADDREF(nsDOMStyleSheetSetList
)
1227 NS_IMPL_RELEASE(nsDOMStyleSheetSetList
)
1228 NS_INTERFACE_TABLE_HEAD(nsDOMStyleSheetSetList
)
1229 NS_OFFSET_AND_INTERFACE_TABLE_BEGIN(nsDOMStyleSheetSetList
)
1230 NS_INTERFACE_TABLE_ENTRY(nsDOMStyleSheetSetList
, nsIDOMDOMStringList
)
1231 NS_OFFSET_AND_INTERFACE_TABLE_END
1232 NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
1233 NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(DOMStringList
)
1234 NS_INTERFACE_MAP_END
1236 nsDOMStyleSheetSetList::nsDOMStyleSheetSetList(nsIDocument
* aDocument
)
1237 : mDocument(aDocument
)
1239 NS_ASSERTION(mDocument
, "Must have document!");
1243 nsDOMStyleSheetSetList::Item(PRUint32 aIndex
, nsAString
& aResult
)
1245 nsStringArray styleSets
;
1246 nsresult rv
= GetSets(styleSets
);
1247 NS_ENSURE_SUCCESS(rv
, rv
);
1249 if (aIndex
>= (PRUint32
)styleSets
.Count()) {
1250 SetDOMStringToNull(aResult
);
1252 styleSets
.StringAt(aIndex
, aResult
);
1259 nsDOMStyleSheetSetList::GetLength(PRUint32
*aLength
)
1261 nsStringArray styleSets
;
1262 nsresult rv
= GetSets(styleSets
);
1263 NS_ENSURE_SUCCESS(rv
, rv
);
1265 *aLength
= (PRUint32
)styleSets
.Count();
1271 nsDOMStyleSheetSetList::Contains(const nsAString
& aString
, PRBool
*aResult
)
1273 nsStringArray styleSets
;
1274 nsresult rv
= GetSets(styleSets
);
1275 NS_ENSURE_SUCCESS(rv
, rv
);
1277 *aResult
= styleSets
.IndexOf(aString
) != -1;
1283 nsDOMStyleSheetSetList::GetSets(nsStringArray
& aStyleSets
)
1286 return NS_OK
; // Spec says "no exceptions", and we have no style sets if we
1287 // have no document, for sure
1290 PRInt32 count
= mDocument
->GetNumberOfStyleSheets();
1293 for (PRInt32 index
= 0; index
< count
; index
++) {
1294 nsIStyleSheet
* sheet
= mDocument
->GetStyleSheetAt(index
);
1295 NS_ASSERTION(sheet
, "Null sheet in sheet list!");
1296 sheet
->GetTitle(title
);
1297 if (!title
.IsEmpty() && aStyleSets
.IndexOf(title
) == -1 &&
1298 !aStyleSets
.AppendString(title
)) {
1299 return NS_ERROR_OUT_OF_MEMORY
;
1306 // ==================================================================
1308 // ==================================================================
1310 class nsDOMImplementation
: public nsIDOMDOMImplementation
,
1311 public nsIPrivateDOMImplementation
1314 nsDOMImplementation(nsIScriptGlobalObject
* aScriptObject
,
1315 nsIURI
* aDocumentURI
,
1317 nsIPrincipal
* aPrincipal
);
1318 virtual ~nsDOMImplementation();
1322 // nsIDOMDOMImplementation
1323 NS_DECL_NSIDOMDOMIMPLEMENTATION
1325 // nsIPrivateDOMImplementation
1326 NS_IMETHOD
Init(nsIURI
* aDocumentURI
, nsIURI
* aBaseURI
,
1327 nsIPrincipal
* aPrincipal
);
1330 nsWeakPtr mScriptObject
;
1331 nsCOMPtr
<nsIURI
> mDocumentURI
;
1332 nsCOMPtr
<nsIURI
> mBaseURI
;
1333 nsCOMPtr
<nsIPrincipal
> mPrincipal
;
1338 NS_NewDOMImplementation(nsIDOMDOMImplementation
** aInstancePtrResult
)
1340 *aInstancePtrResult
= new nsDOMImplementation(nsnull
, nsnull
, nsnull
, nsnull
);
1341 if (!*aInstancePtrResult
) {
1342 return NS_ERROR_OUT_OF_MEMORY
;
1345 NS_ADDREF(*aInstancePtrResult
);
1350 nsDOMImplementation::nsDOMImplementation(nsIScriptGlobalObject
* aScriptObject
,
1351 nsIURI
* aDocumentURI
,
1353 nsIPrincipal
* aPrincipal
)
1354 : mScriptObject(do_GetWeakReference(aScriptObject
)),
1355 mDocumentURI(aDocumentURI
),
1357 mPrincipal(aPrincipal
)
1361 nsDOMImplementation::~nsDOMImplementation()
1365 // QueryInterface implementation for nsDOMImplementation
1366 NS_INTERFACE_MAP_BEGIN(nsDOMImplementation
)
1367 NS_INTERFACE_MAP_ENTRY(nsIDOMDOMImplementation
)
1368 NS_INTERFACE_MAP_ENTRY(nsIPrivateDOMImplementation
)
1369 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIDOMDOMImplementation
)
1370 NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(DOMImplementation
)
1371 NS_INTERFACE_MAP_END
1374 NS_IMPL_ADDREF(nsDOMImplementation
)
1375 NS_IMPL_RELEASE(nsDOMImplementation
)
1379 nsDOMImplementation::HasFeature(const nsAString
& aFeature
,
1380 const nsAString
& aVersion
,
1383 return nsGenericElement::InternalIsSupported(
1384 static_cast<nsIDOMDOMImplementation
*>(this),
1385 aFeature
, aVersion
, aReturn
);
1389 nsDOMImplementation::CreateDocumentType(const nsAString
& aQualifiedName
,
1390 const nsAString
& aPublicId
,
1391 const nsAString
& aSystemId
,
1392 nsIDOMDocumentType
** aReturn
)
1396 nsresult rv
= nsContentUtils::CheckQName(aQualifiedName
);
1397 NS_ENSURE_SUCCESS(rv
, rv
);
1399 nsCOMPtr
<nsIAtom
> name
= do_GetAtom(aQualifiedName
);
1400 NS_ENSURE_TRUE(name
, NS_ERROR_OUT_OF_MEMORY
);
1402 // Indicate that there is no internal subset (not just an empty one)
1403 nsAutoString voidString
;
1404 voidString
.SetIsVoid(PR_TRUE
);
1405 return NS_NewDOMDocumentType(aReturn
, nsnull
, mPrincipal
, name
, nsnull
,
1406 nsnull
, aPublicId
, aSystemId
, voidString
);
1410 nsDOMImplementation::CreateDocument(const nsAString
& aNamespaceURI
,
1411 const nsAString
& aQualifiedName
,
1412 nsIDOMDocumentType
* aDoctype
,
1413 nsIDOMDocument
** aReturn
)
1418 if (!aQualifiedName
.IsEmpty()) {
1419 nsIParserService
*parserService
= nsContentUtils::GetParserService();
1420 NS_ENSURE_TRUE(parserService
, NS_ERROR_FAILURE
);
1422 const nsAFlatString
& qName
= PromiseFlatString(aQualifiedName
);
1423 const PRUnichar
*colon
;
1424 rv
= parserService
->CheckQName(qName
, PR_TRUE
, &colon
);
1425 NS_ENSURE_SUCCESS(rv
, rv
);
1428 (DOMStringIsNull(aNamespaceURI
) ||
1429 (Substring(qName
.get(), colon
).EqualsLiteral("xml") &&
1430 !aNamespaceURI
.EqualsLiteral("http://www.w3.org/XML/1998/namespace")))) {
1431 return NS_ERROR_DOM_NAMESPACE_ERR
;
1434 else if (DOMStringIsNull(aQualifiedName
) &&
1435 !DOMStringIsNull(aNamespaceURI
)) {
1436 return NS_ERROR_DOM_NAMESPACE_ERR
;
1440 nsCOMPtr
<nsIDOMDocument
> owner
;
1441 aDoctype
->GetOwnerDocument(getter_AddRefs(owner
));
1443 return NS_ERROR_DOM_WRONG_DOCUMENT_ERR
;
1447 nsCOMPtr
<nsIScriptGlobalObject
> scriptHandlingObject
=
1448 do_QueryReferent(mScriptObject
);
1450 return nsContentUtils::CreateDocument(aNamespaceURI
, aQualifiedName
, aDoctype
,
1451 mDocumentURI
, mBaseURI
, mPrincipal
,
1452 scriptHandlingObject
, aReturn
);
1456 nsDOMImplementation::Init(nsIURI
* aDocumentURI
, nsIURI
* aBaseURI
,
1457 nsIPrincipal
* aPrincipal
)
1459 // Note: can't require that the args be non-null, since at least one
1460 // caller (XMLHttpRequest) doesn't have decent args to pass in.
1461 mDocumentURI
= aDocumentURI
;
1462 mBaseURI
= aBaseURI
;
1463 mPrincipal
= aPrincipal
;
1467 // ==================================================================
1469 // ==================================================================
1471 // NOTE! nsDocument::operator new() zeroes out all members, so don't
1472 // bother initializing members to 0.
1474 nsDocument::nsDocument(const char* aContentType
)
1478 mContentType
= aContentType
;
1481 if (!gDocumentLeakPRLog
)
1482 gDocumentLeakPRLog
= PR_NewLogModule("DocumentLeak");
1484 if (gDocumentLeakPRLog
)
1485 PR_LOG(gDocumentLeakPRLog
, PR_LOG_DEBUG
,
1486 ("DOCUMENT %p created", this));
1489 // Start out mLastStyleSheetSet as null, per spec
1490 SetDOMStringToNull(mLastStyleSheetSet
);
1493 static PLDHashOperator
1494 ClearAllBoxObjects(const void* aKey
, nsPIBoxObject
* aBoxObject
, void* aUserArg
)
1497 aBoxObject
->Clear();
1499 return PL_DHASH_NEXT
;
1502 nsDocument::~nsDocument()
1505 if (gDocumentLeakPRLog
)
1506 PR_LOG(gDocumentLeakPRLog
, PR_LOG_DEBUG
,
1507 ("DOCUMENT %p destroyed", this));
1511 nsCycleCollector_DEBUG_wasFreed(static_cast<nsIDocument
*>(this));
1514 mInDestructor
= PR_TRUE
;
1516 // Clear mObservers to keep it in sync with the mutationobserver list
1519 if (mStyleSheetSetList
) {
1520 mStyleSheetSetList
->Disconnect();
1523 mParentDocument
= nsnull
;
1525 // Kill the subdocument map, doing this will release its strong
1526 // references, if any.
1527 if (mSubDocuments
) {
1528 PL_DHashTableDestroy(mSubDocuments
);
1530 mSubDocuments
= nsnull
;
1533 // Destroy link map now so we don't waste time removing
1537 nsAutoScriptBlocker scriptBlocker
;
1539 PRInt32 indx
; // must be signed
1540 PRUint32 count
= mChildren
.ChildCount();
1541 for (indx
= PRInt32(count
) - 1; indx
>= 0; --indx
) {
1542 mChildren
.ChildAt(indx
)->UnbindFromTree();
1543 mChildren
.RemoveChildAt(indx
);
1545 mCachedRootContent
= nsnull
;
1547 // Let the stylesheets know we're going away
1548 indx
= mStyleSheets
.Count();
1549 while (--indx
>= 0) {
1550 mStyleSheets
[indx
]->SetOwningDocument(nsnull
);
1552 indx
= mCatalogSheets
.Count();
1553 while (--indx
>= 0) {
1554 mCatalogSheets
[indx
]->SetOwningDocument(nsnull
);
1556 if (mAttrStyleSheet
)
1557 mAttrStyleSheet
->SetOwningDocument(nsnull
);
1558 if (mStyleAttrStyleSheet
)
1559 mStyleAttrStyleSheet
->SetOwningDocument(nsnull
);
1561 if (mListenerManager
) {
1562 mListenerManager
->Disconnect();
1565 if (mScriptLoader
) {
1566 mScriptLoader
->DropDocumentReference();
1570 // Could be null here if Init() failed
1571 mCSSLoader
->DropDocumentReference();
1572 NS_RELEASE(mCSSLoader
);
1575 // XXX Ideally we'd do this cleanup in the nsIDocument destructor.
1576 if (mNodeInfoManager
) {
1577 mNodeInfoManager
->DropDocumentReference();
1578 NS_RELEASE(mNodeInfoManager
);
1581 if (mAttrStyleSheet
) {
1582 mAttrStyleSheet
->SetOwningDocument(nsnull
);
1585 if (mStyleAttrStyleSheet
) {
1586 mStyleAttrStyleSheet
->SetOwningDocument(nsnull
);
1591 if (mBoxObjectTable
) {
1592 mBoxObjectTable
->EnumerateRead(ClearAllBoxObjects
, nsnull
);
1593 delete mBoxObjectTable
;
1597 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocument
)
1599 NS_INTERFACE_TABLE_HEAD(nsDocument
)
1600 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
1601 NS_DOCUMENT_INTERFACE_TABLE_BEGIN(nsDocument
)
1602 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsINode
)
1603 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIDocument
)
1604 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIDOM3DocumentEvent
)
1605 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIDOMDocumentStyle
)
1606 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIDOMNSDocumentStyle
)
1607 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIDOMDocumentRange
)
1608 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIDOMDocumentXBL
)
1609 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIScriptObjectPrincipal
)
1610 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIDOM3EventTarget
)
1611 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIDOMNSEventTarget
)
1612 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsPIDOMEventTarget
)
1613 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsISupportsWeakReference
)
1614 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIRadioGroupContainer
)
1615 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIMutationObserver
)
1616 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIDOMNodeSelector
)
1617 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIApplicationCacheContainer
)
1618 NS_OFFSET_AND_INTERFACE_TABLE_END
1619 NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
1620 NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsDocument
)
1621 if (aIID
.Equals(NS_GET_IID(nsIDOMXPathEvaluator
)) ||
1622 aIID
.Equals(NS_GET_IID(nsIXPathEvaluatorInternal
))) {
1623 if (!mXPathEvaluatorTearoff
) {
1625 mXPathEvaluatorTearoff
=
1626 do_CreateInstance(NS_XPATH_EVALUATOR_CONTRACTID
,
1627 static_cast<nsIDocument
*>(this), &rv
);
1628 NS_ENSURE_SUCCESS(rv
, rv
);
1631 return mXPathEvaluatorTearoff
->QueryInterface(aIID
, aInstancePtr
);
1634 NS_INTERFACE_MAP_END
1637 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsDocument
, nsIDocument
)
1638 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS_WITH_DESTROY(nsDocument
,
1640 nsNodeUtils::LastRelease(this))
1643 static PLDHashOperator
1644 SubDocTraverser(PLDHashTable
*table
, PLDHashEntryHdr
*hdr
, PRUint32 number
,
1647 SubDocMapEntry
*entry
= static_cast<SubDocMapEntry
*>(hdr
);
1648 nsCycleCollectionTraversalCallback
*cb
=
1649 static_cast<nsCycleCollectionTraversalCallback
*>(arg
);
1651 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
, "mSubDocuments entry->mKey");
1652 cb
->NoteXPCOMChild(entry
->mKey
);
1653 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
, "mSubDocuments entry->mSubDocument");
1654 cb
->NoteXPCOMChild(entry
->mSubDocument
);
1656 return PL_DHASH_NEXT
;
1659 static PLDHashOperator
1660 RadioGroupsTraverser(const nsAString
& aKey
, nsRadioGroupStruct
* aData
,
1663 nsCycleCollectionTraversalCallback
*cb
=
1664 static_cast<nsCycleCollectionTraversalCallback
*>(aClosure
);
1666 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
1667 "mRadioGroups entry->mSelectedRadioButton");
1668 cb
->NoteXPCOMChild(aData
->mSelectedRadioButton
);
1670 PRUint32 i
, count
= aData
->mRadioButtons
.Count();
1671 for (i
= 0; i
< count
; ++i
) {
1672 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
1673 "mRadioGroups entry->mRadioButtons[i]");
1674 cb
->NoteXPCOMChild(aData
->mRadioButtons
[i
]);
1677 return PL_DHASH_NEXT
;
1680 static PLDHashOperator
1681 BoxObjectTraverser(const void* key
, nsPIBoxObject
* boxObject
, void* userArg
)
1683 nsCycleCollectionTraversalCallback
*cb
=
1684 static_cast<nsCycleCollectionTraversalCallback
*>(userArg
);
1686 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
, "mBoxObjectTable entry");
1687 cb
->NoteXPCOMChild(boxObject
);
1689 return PL_DHASH_NEXT
;
1692 class LinkMapTraversalVisitor
: public nsUint32ToContentHashEntry::Visitor
1695 nsCycleCollectionTraversalCallback
*mCb
;
1696 virtual void Visit(nsIContent
* aContent
)
1698 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*mCb
, "mLinkMap entry");
1699 mCb
->NoteXPCOMChild(aContent
);
1703 static PLDHashOperator
1704 LinkMapTraverser(nsUint32ToContentHashEntry
* aEntry
, void* userArg
)
1706 LinkMapTraversalVisitor visitor
;
1707 visitor
.mCb
= static_cast<nsCycleCollectionTraversalCallback
*>(userArg
);
1708 aEntry
->VisitContent(&visitor
);
1709 return PL_DHASH_NEXT
;
1712 static PLDHashOperator
1713 IdentifierMapEntryTraverse(nsIdentifierMapEntry
*aEntry
, void *aArg
)
1715 nsCycleCollectionTraversalCallback
*cb
=
1716 static_cast<nsCycleCollectionTraversalCallback
*>(aArg
);
1717 aEntry
->Traverse(cb
);
1718 return PL_DHASH_NEXT
;
1721 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDocument
)
1722 if (nsCCUncollectableMarker::InGeneration(tmp
->GetMarkedCCGeneration())) {
1726 tmp
->mIdentifierMap
.EnumerateEntries(IdentifierMapEntryTraverse
, &cb
);
1728 tmp
->mExternalResourceMap
.Traverse(&cb
);
1730 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNodeInfo
)
1732 // Traverse the mChildren nsAttrAndChildArray.
1733 for (PRInt32 indx
= PRInt32(tmp
->mChildren
.ChildCount()); indx
> 0; --indx
) {
1734 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mChildren[i]");
1735 cb
.NoteXPCOMChild(tmp
->mChildren
.ChildAt(indx
- 1));
1738 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_USERDATA
1740 // Traverse all nsIDocument pointer members.
1741 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCachedRootContent
)
1742 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mNodeInfoManager
,
1744 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSecurityInfo
)
1745 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDisplayDocument
)
1747 // Traverse all nsDocument nsCOMPtrs.
1748 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParser
)
1749 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptGlobalObject
)
1750 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mListenerManager
)
1751 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDOMStyleSheets
)
1752 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptLoader
)
1754 tmp
->mRadioGroups
.EnumerateRead(RadioGroupsTraverser
, &cb
);
1756 // The boxobject for an element will only exist as long as it's in the
1757 // document, so we'll traverse the table here instead of from the element.
1758 if (tmp
->mBoxObjectTable
) {
1759 tmp
->mBoxObjectTable
->EnumerateRead(BoxObjectTraverser
, &cb
);
1762 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChannel
)
1763 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mStyleAttrStyleSheet
)
1764 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptEventManager
)
1765 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mXPathEvaluatorTearoff
)
1766 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLayoutHistoryState
)
1767 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnloadBlocker
)
1769 // An element will only be in the linkmap as long as it's in the
1770 // document, so we'll traverse the table here instead of from the element.
1771 if (tmp
->mLinkMap
.IsInitialized()) {
1772 tmp
->mLinkMap
.EnumerateEntries(LinkMapTraverser
, &cb
);
1775 // Traverse all our nsCOMArrays.
1776 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mStyleSheets
)
1777 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mCatalogSheets
)
1778 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mVisitednessChangedURIs
)
1780 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_PRESERVED_WRAPPER
1782 if (tmp
->mSubDocuments
&& tmp
->mSubDocuments
->ops
) {
1783 PL_DHashTableEnumerate(tmp
->mSubDocuments
, SubDocTraverser
, &cb
);
1785 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1788 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument
)
1789 // Tear down linkmap. This is a performance optimization so that we
1790 // don't waste time removing links one by one as they are removed
1792 tmp
->DestroyLinkMap();
1794 // Clear out our external resources
1795 tmp
->mExternalResourceMap
.Shutdown();
1797 nsAutoScriptBlocker scriptBlocker
;
1799 // Unlink the mChildren nsAttrAndChildArray.
1800 for (PRInt32 indx
= PRInt32(tmp
->mChildren
.ChildCount()) - 1;
1801 indx
>= 0; --indx
) {
1802 tmp
->mChildren
.ChildAt(indx
)->UnbindFromTree();
1803 tmp
->mChildren
.RemoveChildAt(indx
);
1806 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCachedRootContent
)
1807 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDisplayDocument
)
1809 NS_IMPL_CYCLE_COLLECTION_UNLINK_USERDATA
1811 tmp
->mParentDocument
= nsnull
;
1813 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
1815 // nsDocument has a pretty complex destructor, so we're going to
1816 // assume that *most* cycles you actually want to break somewhere
1817 // else, and not unlink an awful lot here.
1819 // In rare cases where you think an unlink will help here, add one
1821 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1827 if (mCSSLoader
|| mNodeInfoManager
|| mScriptLoader
) {
1828 return NS_ERROR_ALREADY_INITIALIZED
;
1831 mIdentifierMap
.Init();
1833 mRadioGroups
.Init();
1835 // Force initialization.
1836 nsINode::nsSlots
* slots
= GetSlots();
1837 NS_ENSURE_TRUE(slots
,NS_ERROR_OUT_OF_MEMORY
);
1839 // Prepend self as mutation-observer whether we need it or not (some
1840 // subclasses currently do, other don't). This is because the code in
1841 // nsNodeUtils always notifies the first observer first, expecting the
1842 // first observer to be the document.
1843 NS_ENSURE_TRUE(slots
->mMutationObservers
.PrependElementUnlessExists(static_cast<nsIMutationObserver
*>(this)),
1844 NS_ERROR_OUT_OF_MEMORY
);
1847 mOnloadBlocker
= new nsOnloadBlocker();
1848 NS_ENSURE_TRUE(mOnloadBlocker
, NS_ERROR_OUT_OF_MEMORY
);
1850 NS_NewCSSLoader(this, &mCSSLoader
);
1851 NS_ENSURE_TRUE(mCSSLoader
, NS_ERROR_OUT_OF_MEMORY
);
1852 // Assume we're not HTML and not quirky, until we know otherwise
1853 mCSSLoader
->SetCaseSensitive(PR_TRUE
);
1854 mCSSLoader
->SetCompatibilityMode(eCompatibility_FullStandards
);
1856 mNodeInfoManager
= new nsNodeInfoManager();
1857 NS_ENSURE_TRUE(mNodeInfoManager
, NS_ERROR_OUT_OF_MEMORY
);
1859 NS_ADDREF(mNodeInfoManager
);
1861 nsresult rv
= mNodeInfoManager
->Init(this);
1862 NS_ENSURE_SUCCESS(rv
, rv
);
1864 mNodeInfo
= mNodeInfoManager
->GetDocumentNodeInfo();
1865 NS_ENSURE_TRUE(mNodeInfo
, NS_ERROR_OUT_OF_MEMORY
);
1867 NS_ASSERTION(GetOwnerDoc() == this, "Our nodeinfo is busted!");
1869 mScriptLoader
= new nsScriptLoader(this);
1870 NS_ENSURE_TRUE(mScriptLoader
, NS_ERROR_OUT_OF_MEMORY
);
1876 nsDocument::AddXMLEventsContent(nsIContent
*aXMLEventsElement
)
1878 if (!mXMLEventsManager
) {
1879 mXMLEventsManager
= new nsXMLEventsManager();
1880 NS_ENSURE_TRUE(mXMLEventsManager
, NS_ERROR_OUT_OF_MEMORY
);
1881 AddObserver(mXMLEventsManager
);
1883 mXMLEventsManager
->AddXMLEventsContent(aXMLEventsElement
);
1888 nsDocument::Reset(nsIChannel
* aChannel
, nsILoadGroup
* aLoadGroup
)
1890 nsCOMPtr
<nsIURI
> uri
;
1891 nsCOMPtr
<nsIPrincipal
> principal
;
1893 // Note: this code is duplicated in nsXULDocument::StartDocumentLoad and
1894 // nsScriptSecurityManager::GetChannelPrincipal.
1895 // Note: this should match nsDocShell::OnLoadingSite
1896 NS_GetFinalChannelURI(aChannel
, getter_AddRefs(uri
));
1898 nsIScriptSecurityManager
*securityManager
=
1899 nsContentUtils::GetSecurityManager();
1900 if (securityManager
) {
1901 securityManager
->GetChannelPrincipal(aChannel
,
1902 getter_AddRefs(principal
));
1906 ResetToURI(uri
, aLoadGroup
, principal
);
1908 nsCOMPtr
<nsIPropertyBag2
> bag
= do_QueryInterface(aChannel
);
1910 nsCOMPtr
<nsIURI
> baseURI
;
1911 bag
->GetPropertyAsInterface(NS_LITERAL_STRING("baseURI"),
1912 NS_GET_IID(nsIURI
), getter_AddRefs(baseURI
));
1914 mDocumentBaseURI
= baseURI
;
1918 mChannel
= aChannel
;
1922 nsDocument::ResetToURI(nsIURI
*aURI
, nsILoadGroup
*aLoadGroup
,
1923 nsIPrincipal
* aPrincipal
)
1925 NS_PRECONDITION(aURI
, "Null URI passed to ResetToURI");
1928 if (gDocumentLeakPRLog
&& PR_LOG_TEST(gDocumentLeakPRLog
, PR_LOG_DEBUG
)) {
1930 aURI
->GetSpec(spec
);
1931 PR_LogPrint("DOCUMENT %p ResetToURI %s", this, spec
.get());
1935 mIdentifierMap
.Clear();
1937 SetPrincipal(nsnull
);
1938 mSecurityInfo
= nsnull
;
1940 mDocumentLoadGroup
= nsnull
;
1942 // Delete references to sub-documents and kill the subdocument map,
1943 // if any. It holds strong references
1944 if (mSubDocuments
) {
1945 PL_DHashTableDestroy(mSubDocuments
);
1947 mSubDocuments
= nsnull
;
1950 // Destroy link map now so we don't waste time removing
1954 PRUint32 count
= mChildren
.ChildCount();
1955 { // Scope for update
1956 MOZ_AUTO_DOC_UPDATE(this, UPDATE_CONTENT_MODEL
, PR_TRUE
);
1957 for (PRInt32 i
= PRInt32(count
) - 1; i
>= 0; i
--) {
1958 nsCOMPtr
<nsIContent
> content
= mChildren
.ChildAt(i
);
1960 // XXXbz this is backwards from how ContentRemoved normally works. That
1961 // is, usually it's dispatched after the content has been removed from
1963 nsNodeUtils::ContentRemoved(this, content
, i
);
1964 content
->UnbindFromTree();
1965 mChildren
.RemoveChildAt(i
);
1968 mCachedRootContent
= nsnull
;
1970 // Reset our stylesheets
1971 ResetStylesheetsToURI(aURI
);
1973 // Release the listener manager
1974 if (mListenerManager
) {
1975 mListenerManager
->Disconnect();
1976 mListenerManager
= nsnull
;
1979 // Release the stylesheets list.
1980 mDOMStyleSheets
= nsnull
;
1982 SetDocumentURI(aURI
);
1983 mDocumentBaseURI
= mDocumentURI
;
1986 mDocumentLoadGroup
= do_GetWeakReference(aLoadGroup
);
1987 // there was an assertion here that aLoadGroup was not null. This
1988 // is no longer valid nsWebShell::SetDocument does not create a
1989 // load group, and it works just fine.
1992 mLastModified
.Truncate();
1993 // XXXbz I guess we're assuming that the caller will either pass in
1994 // a channel with a useful type or call SetContentType?
1995 mContentType
.Truncate();
1996 mContentLanguage
.Truncate();
1997 mBaseTarget
.Truncate();
1998 mReferrer
.Truncate();
2000 mXMLDeclarationBits
= 0;
2002 // Now get our new principal
2004 SetPrincipal(aPrincipal
);
2006 nsIScriptSecurityManager
*securityManager
=
2007 nsContentUtils::GetSecurityManager();
2008 if (securityManager
) {
2009 nsCOMPtr
<nsIPrincipal
> principal
;
2011 securityManager
->GetCodebasePrincipal(mDocumentURI
,
2012 getter_AddRefs(principal
));
2013 if (NS_SUCCEEDED(rv
)) {
2014 SetPrincipal(principal
);
2021 nsDocument::ResetStylesheetsToURI(nsIURI
* aURI
)
2023 NS_PRECONDITION(aURI
, "Null URI passed to ResetStylesheetsToURI");
2025 mozAutoDocUpdate
upd(this, UPDATE_STYLE
, PR_TRUE
);
2027 // The stylesheets should forget us
2028 PRInt32 indx
= mStyleSheets
.Count();
2029 while (--indx
>= 0) {
2030 nsIStyleSheet
* sheet
= mStyleSheets
[indx
];
2031 sheet
->SetOwningDocument(nsnull
);
2034 sheet
->GetApplicable(applicable
);
2036 RemoveStyleSheetFromStyleSets(sheet
);
2039 // XXX Tell observers?
2042 indx
= mCatalogSheets
.Count();
2043 while (--indx
>= 0) {
2044 nsIStyleSheet
* sheet
= mCatalogSheets
[indx
];
2045 sheet
->SetOwningDocument(nsnull
);
2048 sheet
->GetApplicable(applicable
);
2050 nsPresShellIterator
iter(this);
2051 nsCOMPtr
<nsIPresShell
> shell
;
2052 while ((shell
= iter
.GetNextShell())) {
2053 shell
->StyleSet()->RemoveStyleSheet(nsStyleSet::eAgentSheet
, sheet
);
2057 // XXX Tell observers?
2061 // Release all the sheets
2062 mStyleSheets
.Clear();
2063 // NOTE: We don't release the catalog sheets. It doesn't really matter
2064 // now, but it could in the future -- in which case not releasing them
2065 // is probably the right thing to do.
2067 // Now reset our inline style and attribute sheets.
2069 nsStyleSet::sheetType attrSheetType
= GetAttrSheetType();
2070 if (mAttrStyleSheet
) {
2071 // Remove this sheet from all style sets
2072 nsPresShellIterator
iter(this);
2073 nsCOMPtr
<nsIPresShell
> shell
;
2074 while ((shell
= iter
.GetNextShell())) {
2075 shell
->StyleSet()->RemoveStyleSheet(attrSheetType
, mAttrStyleSheet
);
2077 rv
= mAttrStyleSheet
->Reset(aURI
);
2079 rv
= NS_NewHTMLStyleSheet(getter_AddRefs(mAttrStyleSheet
), aURI
, this);
2081 NS_ENSURE_SUCCESS(rv
, rv
);
2083 // Don't use AddStyleSheet, since it'll put the sheet into style
2084 // sets in the document level, which is not desirable here.
2085 mAttrStyleSheet
->SetOwningDocument(this);
2087 if (mStyleAttrStyleSheet
) {
2088 // Remove this sheet from all style sets
2089 nsPresShellIterator
iter(this);
2090 nsCOMPtr
<nsIPresShell
> shell
;
2091 while ((shell
= iter
.GetNextShell())) {
2093 RemoveStyleSheet(nsStyleSet::eStyleAttrSheet
, mStyleAttrStyleSheet
);
2095 rv
= mStyleAttrStyleSheet
->Reset(aURI
);
2097 rv
= NS_NewHTMLCSSStyleSheet(getter_AddRefs(mStyleAttrStyleSheet
), aURI
,
2100 NS_ENSURE_SUCCESS(rv
, rv
);
2102 // The loop over style sets below will handle putting this sheet
2103 // into style sets as needed.
2104 mStyleAttrStyleSheet
->SetOwningDocument(this);
2106 // Now set up our style sets
2107 nsPresShellIterator
iter(this);
2108 nsCOMPtr
<nsIPresShell
> shell
;
2109 while ((shell
= iter
.GetNextShell())) {
2110 FillStyleSet(shell
->StyleSet());
2116 nsStyleSet::sheetType
2117 nsDocument::GetAttrSheetType()
2119 return nsStyleSet::ePresHintSheet
;
2123 nsDocument::FillStyleSet(nsStyleSet
* aStyleSet
)
2125 NS_PRECONDITION(aStyleSet
, "Must have a style set");
2126 NS_PRECONDITION(aStyleSet
->SheetCount(nsStyleSet::ePresHintSheet
) == 0,
2127 "Style set already has a preshint sheet?");
2128 NS_PRECONDITION(aStyleSet
->SheetCount(nsStyleSet::eHTMLPresHintSheet
) == 0,
2129 "Style set already has a HTML preshint sheet?");
2130 NS_PRECONDITION(aStyleSet
->SheetCount(nsStyleSet::eDocSheet
) == 0,
2131 "Style set already has document sheets?");
2132 NS_PRECONDITION(aStyleSet
->SheetCount(nsStyleSet::eStyleAttrSheet
) == 0,
2133 "Style set already has style attr sheets?");
2134 NS_PRECONDITION(mStyleAttrStyleSheet
, "No style attr stylesheet?");
2135 NS_PRECONDITION(mAttrStyleSheet
, "No attr stylesheet?");
2137 aStyleSet
->AppendStyleSheet(GetAttrSheetType(), mAttrStyleSheet
);
2139 aStyleSet
->AppendStyleSheet(nsStyleSet::eStyleAttrSheet
,
2140 mStyleAttrStyleSheet
);
2143 for (i
= mStyleSheets
.Count() - 1; i
>= 0; --i
) {
2144 nsIStyleSheet
* sheet
= mStyleSheets
[i
];
2145 PRBool sheetApplicable
;
2146 sheet
->GetApplicable(sheetApplicable
);
2147 if (sheetApplicable
) {
2148 aStyleSet
->AddDocStyleSheet(sheet
, this);
2152 for (i
= mCatalogSheets
.Count() - 1; i
>= 0; --i
) {
2153 nsIStyleSheet
* sheet
= mCatalogSheets
[i
];
2154 PRBool sheetApplicable
;
2155 sheet
->GetApplicable(sheetApplicable
);
2156 if (sheetApplicable
) {
2157 aStyleSet
->AppendStyleSheet(nsStyleSet::eAgentSheet
, sheet
);
2163 nsDocument::StartDocumentLoad(const char* aCommand
, nsIChannel
* aChannel
,
2164 nsILoadGroup
* aLoadGroup
,
2165 nsISupports
* aContainer
,
2166 nsIStreamListener
**aDocListener
,
2167 PRBool aReset
, nsIContentSink
* aSink
)
2170 if (gDocumentLeakPRLog
&& PR_LOG_TEST(gDocumentLeakPRLog
, PR_LOG_DEBUG
)) {
2171 nsCOMPtr
<nsIURI
> uri
;
2172 aChannel
->GetURI(getter_AddRefs(uri
));
2176 PR_LogPrint("DOCUMENT %p StartDocumentLoad %s", this, spec
.get());
2180 if (nsCRT::strcmp(kLoadAsData
, aCommand
) == 0) {
2181 mLoadedAsData
= PR_TRUE
;
2182 // We need to disable script & style loading in this case.
2183 // We leave them disabled even in EndLoad(), and let anyone
2184 // who puts the document on display to worry about enabling.
2186 // Do not load/process scripts when loading as data
2187 ScriptLoader()->SetEnabled(PR_FALSE
);
2190 CSSLoader()->SetEnabled(PR_FALSE
); // Do not load/process styles when loading as data
2191 } else if (nsCRT::strcmp("external-resource", aCommand
) == 0) {
2192 // Allow CSS, but not scripts
2193 ScriptLoader()->SetEnabled(PR_FALSE
);
2196 mMayStartLayout
= PR_FALSE
;
2198 mHaveInputEncoding
= PR_TRUE
;
2201 Reset(aChannel
, aLoadGroup
);
2204 nsCAutoString contentType
;
2205 if (NS_SUCCEEDED(aChannel
->GetContentType(contentType
))) {
2206 // XXX this is only necessary for viewsource:
2207 nsACString::const_iterator start
, end
, semicolon
;
2208 contentType
.BeginReading(start
);
2209 contentType
.EndReading(end
);
2211 FindCharInReadable(';', semicolon
, end
);
2212 mContentType
= Substring(start
, semicolon
);
2215 RetrieveRelevantHeaders(aChannel
);
2217 mChannel
= aChannel
;
2223 nsDocument::StopDocumentLoad()
2226 mParser
->Terminate();
2231 nsDocument::SetDocumentURI(nsIURI
* aURI
)
2233 mDocumentURI
= NS_TryToMakeImmutable(aURI
);
2237 nsDocument::GetLastModified(nsAString
& aLastModified
)
2239 if (!mLastModified
.IsEmpty()) {
2240 aLastModified
.Assign(mLastModified
);
2242 // If we for whatever reason failed to find the last modified time
2243 // (or even the current time), fall back to what NS4.x returned.
2244 aLastModified
.Assign(NS_LITERAL_STRING("01/01/1970 00:00:00"));
2251 nsDocument::UpdateNameTableEntry(nsIContent
*aContent
)
2253 if (!mIsRegularHTML
)
2256 nsIAtom
* name
= nsContentUtils::IsNamedItem(aContent
);
2260 nsIdentifierMapEntry
*entry
= mIdentifierMap
.GetEntry(name
);
2262 // We're not tracking the elements with this name
2266 entry
->AddNameContent(aContent
);
2270 nsDocument::RemoveFromNameTable(nsIContent
*aContent
)
2272 if (!mIsRegularHTML
)
2275 nsIAtom
* name
= nsContentUtils::IsNamedItem(aContent
);
2279 nsIdentifierMapEntry
*entry
= mIdentifierMap
.GetEntry(name
);
2281 // We're not tracking the elements with this name
2285 entry
->RemoveNameContent(aContent
);
2289 nsDocument::UpdateIdTableEntry(nsIContent
*aContent
)
2291 nsIAtom
* id
= aContent
->GetID();
2295 PRBool liveTable
= IdTableIsLive();
2296 nsIdentifierMapEntry
*entry
=
2297 liveTable
? mIdentifierMap
.PutEntry(id
) : mIdentifierMap
.GetEntry(id
);
2300 entry
->AddIdContent(aContent
);
2305 nsDocument::RemoveFromIdTable(nsIContent
*aContent
)
2307 nsIAtom
* id
= aContent
->GetID();
2311 nsIdentifierMapEntry
*entry
= mIdentifierMap
.GetEntry(id
);
2315 if (entry
->RemoveIdContent(aContent
)) {
2316 mIdentifierMap
.RemoveEntry(id
);
2321 nsDocument::UnregisterNamedItems(nsIContent
*aContent
)
2323 if (aContent
->IsNodeOfType(nsINode::eTEXT
)) {
2324 // Text nodes are not named items nor can they have children.
2328 RemoveFromNameTable(aContent
);
2329 RemoveFromIdTable(aContent
);
2331 PRUint32 i
, count
= aContent
->GetChildCount();
2332 for (i
= 0; i
< count
; ++i
) {
2333 UnregisterNamedItems(aContent
->GetChildAt(i
));
2338 nsDocument::RegisterNamedItems(nsIContent
*aContent
)
2340 if (aContent
->IsNodeOfType(nsINode::eTEXT
)) {
2341 // Text nodes are not named items nor can they have children.
2345 UpdateNameTableEntry(aContent
);
2346 UpdateIdTableEntry(aContent
);
2348 PRUint32 i
, count
= aContent
->GetChildCount();
2349 for (i
= 0; i
< count
; ++i
) {
2350 RegisterNamedItems(aContent
->GetChildAt(i
));
2355 nsDocument::ContentAppended(nsIDocument
* aDocument
,
2356 nsIContent
* aContainer
,
2357 PRInt32 aNewIndexInContainer
)
2359 NS_ASSERTION(aDocument
== this, "unexpected doc");
2361 PRUint32 count
= aContainer
->GetChildCount();
2362 for (PRUint32 i
= aNewIndexInContainer
; i
< count
; ++i
) {
2363 RegisterNamedItems(aContainer
->GetChildAt(i
));
2368 nsDocument::ContentInserted(nsIDocument
* aDocument
,
2369 nsIContent
* aContainer
,
2370 nsIContent
* aContent
,
2371 PRInt32 aIndexInContainer
)
2373 NS_ASSERTION(aDocument
== this, "unexpected doc");
2375 NS_ABORT_IF_FALSE(aContent
, "Null content!");
2377 RegisterNamedItems(aContent
);
2381 nsDocument::ContentRemoved(nsIDocument
* aDocument
,
2382 nsIContent
* aContainer
,
2384 PRInt32 aIndexInContainer
)
2386 NS_ASSERTION(aDocument
== this, "unexpected doc");
2388 NS_ABORT_IF_FALSE(aChild
, "Null content!");
2390 UnregisterNamedItems(aChild
);
2394 nsDocument::AttributeWillChange(nsIContent
* aContent
, PRInt32 aNameSpaceID
,
2395 nsIAtom
* aAttribute
)
2397 NS_ABORT_IF_FALSE(aContent
, "Null content!");
2398 NS_PRECONDITION(aAttribute
, "Must have an attribute that's changing!");
2400 if (aNameSpaceID
!= kNameSpaceID_None
)
2402 if (aAttribute
== nsGkAtoms::name
) {
2403 RemoveFromNameTable(aContent
);
2404 } else if (aAttribute
== aContent
->GetIDAttributeName()) {
2405 RemoveFromIdTable(aContent
);
2410 nsDocument::AttributeChanged(nsIDocument
* aDocument
,
2411 nsIContent
* aContent
, PRInt32 aNameSpaceID
,
2412 nsIAtom
* aAttribute
, PRInt32 aModType
,
2413 PRUint32 aStateMask
)
2415 NS_ASSERTION(aDocument
== this, "unexpected doc");
2417 NS_ABORT_IF_FALSE(aContent
, "Null content!");
2418 NS_PRECONDITION(aAttribute
, "Must have an attribute that's changing!");
2420 if (aNameSpaceID
!= kNameSpaceID_None
)
2422 if (aAttribute
== nsGkAtoms::name
) {
2423 UpdateNameTableEntry(aContent
);
2424 } else if (aAttribute
== aContent
->GetIDAttributeName()) {
2425 UpdateIdTableEntry(aContent
);
2430 nsDocument::GetPrincipal()
2432 return NodePrincipal();
2436 nsDocument::SetPrincipal(nsIPrincipal
*aNewPrincipal
)
2438 mNodeInfoManager
->SetDocumentPrincipal(aNewPrincipal
);
2442 nsDocument::GetApplicationCache(nsIApplicationCache
**aApplicationCache
)
2444 NS_IF_ADDREF(*aApplicationCache
= mApplicationCache
);
2450 nsDocument::SetApplicationCache(nsIApplicationCache
*aApplicationCache
)
2452 mApplicationCache
= aApplicationCache
;
2458 nsDocument::GetContentType(nsAString
& aContentType
)
2460 CopyUTF8toUTF16(mContentType
, aContentType
);
2466 nsDocument::SetContentType(const nsAString
& aContentType
)
2468 NS_ASSERTION(mContentType
.IsEmpty() ||
2469 mContentType
.Equals(NS_ConvertUTF16toUTF8(aContentType
)),
2470 "Do you really want to change the content-type?");
2472 CopyUTF16toUTF8(aContentType
, mContentType
);
2475 /* Return true if the document is in the focused top-level window, and is an
2476 * ancestor of the focused DOMWindow. */
2478 nsDocument::HasFocus(PRBool
* aResult
)
2480 *aResult
= PR_FALSE
;
2482 nsPIDOMWindow
* window
= GetWindow();
2483 nsIFocusController
* focusController
= window
?
2484 window
->GetRootFocusController() : nsnull
;
2485 if (!focusController
) {
2489 // Does the top-level window have focus?
2491 nsresult rv
= focusController
->GetActive(&active
);
2492 NS_ENSURE_SUCCESS(rv
, rv
);
2497 // Is there a focused DOMWindow?
2498 nsCOMPtr
<nsIDOMWindowInternal
> focusedWindow
;
2499 rv
= focusController
->GetFocusedWindow(getter_AddRefs(focusedWindow
));
2500 NS_ENSURE_SUCCESS(rv
, rv
);
2501 if (!focusedWindow
) {
2502 return NS_ERROR_FAILURE
;
2505 // Are we an ancestor of the focused DOMWindow?
2506 nsCOMPtr
<nsIDOMDocument
> domDocument
;
2507 focusedWindow
->GetDocument(getter_AddRefs(domDocument
));
2508 nsCOMPtr
<nsIDocument
> document
= do_QueryInterface(domDocument
);
2510 for (nsIDocument
* currentDoc
= document
; currentDoc
;
2511 currentDoc
= currentDoc
->GetParentDocument()) {
2512 if (currentDoc
== this) {
2513 // Yes, we are an ancestor
2523 nsDocument::GetReferrer(nsAString
& aReferrer
)
2525 CopyUTF8toUTF16(mReferrer
, aReferrer
);
2530 nsDocument::GetActiveElement(nsIDOMElement
**aElement
)
2534 // Get the focused element.
2535 nsPIDOMWindow
* window
= GetWindow();
2537 return NS_ERROR_NOT_AVAILABLE
;
2540 nsIFocusController
* focusController
= window
->GetRootFocusController();
2541 if (!focusController
) {
2542 return NS_ERROR_FAILURE
;
2545 nsCOMPtr
<nsIDOMElement
> focusedElement
;
2546 focusController
->GetFocusedElement(getter_AddRefs(focusedElement
));
2547 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(focusedElement
);
2549 // Found a focused element. See if it's in this document.
2550 nsIDocument
* currentDoc
= content
->GetCurrentDoc();
2551 if (currentDoc
== this) {
2552 focusedElement
.swap(*aElement
);
2556 // Not in this document. If it's in a child document, return the iframe in
2557 // this document that's an ancestor of the child.
2559 *aElement
= CheckAncestryAndGetFrame(currentDoc
).get();
2566 // Couldn't find a focused element. Check if something like an IFRAME is
2567 // focused, which will give us a focused window rather than a focused
2569 nsCOMPtr
<nsIDOMWindowInternal
> focusedWindow
;
2570 focusController
->GetFocusedWindow(getter_AddRefs(focusedWindow
));
2571 if (focusedWindow
) {
2572 // Found a focused window. See if it's in a child of this document. (If
2573 // the window's document is this, then we should just fall through to
2574 // returning the BODY below).
2575 nsCOMPtr
<nsIDOMDocument
> domDocument
;
2576 focusedWindow
->GetDocument(getter_AddRefs(domDocument
));
2577 nsCOMPtr
<nsIDocument
> document
= do_QueryInterface(domDocument
);
2579 if (document
&& (document
!= this)) {
2580 *aElement
= CheckAncestryAndGetFrame(document
).get();
2587 // No focused element anywhere in this document. Try to get the BODY.
2588 nsCOMPtr
<nsIDOMHTMLDocument
> htmlDoc
=
2589 do_QueryInterface(static_cast<nsIDocument
*>(this));
2591 nsCOMPtr
<nsIDOMHTMLElement
> bodyElement
;
2592 htmlDoc
->GetBody(getter_AddRefs(bodyElement
));
2594 *aElement
= bodyElement
;
2595 NS_ADDREF(*aElement
);
2597 // Because of IE compatibility, return null when html document doesn't have
2602 // If we couldn't get a BODY, return the root element.
2603 return GetDocumentElement(aElement
);
2607 nsDocument::ElementFromPoint(PRInt32 aX
, PRInt32 aY
, nsIDOMElement
** aReturn
)
2609 return ElementFromPointHelper(aX
, aY
, PR_FALSE
, PR_TRUE
, aReturn
);
2613 nsDocument::ElementFromPointHelper(PRInt32 aX
, PRInt32 aY
,
2614 PRBool aIgnoreRootScrollFrame
,
2615 PRBool aFlushLayout
,
2616 nsIDOMElement
** aReturn
)
2618 NS_ENSURE_ARG_POINTER(aReturn
);
2620 // As per the the spec, we return null if either coord is negative
2621 if (aX
< 0 || aY
< 0)
2624 nscoord x
= nsPresContext::CSSPixelsToAppUnits(aX
);
2625 nscoord y
= nsPresContext::CSSPixelsToAppUnits(aY
);
2628 // Make sure the layout information we get is up-to-date, and
2629 // ensure we get a root frame (for everything but XUL)
2631 FlushPendingNotifications(Flush_Layout
);
2633 nsIPresShell
*ps
= GetPrimaryShell();
2634 NS_ENSURE_STATE(ps
);
2635 nsIFrame
*rootFrame
= ps
->GetRootFrame();
2637 // XUL docs, unlike HTML, have no frame tree until everything's done loading
2639 return NS_OK
; // return null to premature XUL callers as a reminder to wait
2641 nsIFrame
*ptFrame
= nsLayoutUtils::GetFrameForPoint(rootFrame
, pt
, PR_TRUE
,
2642 aIgnoreRootScrollFrame
);
2646 nsIContent
* ptContent
= ptFrame
->GetContent();
2647 NS_ENSURE_STATE(ptContent
);
2649 // If the content is in a subdocument, try to get the element from |this| doc
2650 nsIDocument
*currentDoc
= ptContent
->GetCurrentDoc();
2651 if (currentDoc
&& (currentDoc
!= this)) {
2652 *aReturn
= CheckAncestryAndGetFrame(currentDoc
).get();
2656 // If we have an anonymous element (such as an internal div from a textbox),
2657 // or a node that isn't an element (such as a text frame node),
2658 // replace it with the first non-anonymous parent node of type element.
2660 !ptContent
->IsNodeOfType(nsINode::eELEMENT
) ||
2661 ptContent
->IsInAnonymousSubtree()) {
2662 // XXXldb: Faster to jump to GetBindingParent if non-null?
2663 ptContent
= ptContent
->GetParent();
2667 CallQueryInterface(ptContent
, aReturn
);
2672 nsDocument::GetElementsByClassName(const nsAString
& aClasses
,
2673 nsIDOMNodeList
** aReturn
)
2675 return GetElementsByClassNameHelper(this, aClasses
, aReturn
);
2679 // static GetElementsByClassName helpers
2681 nsDocument::GetElementsByClassNameHelper(nsINode
* aRootNode
,
2682 const nsAString
& aClasses
,
2683 nsIDOMNodeList
** aReturn
)
2685 NS_PRECONDITION(aRootNode
, "Must have root node");
2687 nsAttrValue attrValue
;
2688 attrValue
.ParseAtomArray(aClasses
);
2689 // nsAttrValue::Equals is sensitive to order, so we'll send an array
2690 nsCOMArray
<nsIAtom
>* classes
= new nsCOMArray
<nsIAtom
>;
2691 NS_ENSURE_TRUE(classes
, NS_ERROR_OUT_OF_MEMORY
);
2693 if (attrValue
.Type() == nsAttrValue::eAtomArray
) {
2694 classes
->AppendObjects(*(attrValue
.GetAtomArrayValue()));
2695 } else if (attrValue
.Type() == nsAttrValue::eAtom
) {
2696 classes
->AppendObject(attrValue
.GetAtomValue());
2699 nsBaseContentList
* elements
;
2700 if (classes
->Count() > 0) {
2701 elements
= new nsContentList(aRootNode
, MatchClassNames
,
2702 DestroyClassNameArray
, classes
);
2706 elements
= new nsBaseContentList();
2710 return NS_ERROR_OUT_OF_MEMORY
;
2713 *aReturn
= elements
;
2714 NS_ADDREF(*aReturn
);
2721 nsDocument::MatchClassNames(nsIContent
* aContent
,
2722 PRInt32 aNamespaceID
,
2723 nsIAtom
* aAtom
, void* aData
)
2725 // We can't match if there are no class names
2726 const nsAttrValue
* classAttr
= aContent
->GetClasses();
2731 // need to match *all* of the classes
2732 nsCOMArray
<nsIAtom
>* classes
= static_cast<nsCOMArray
<nsIAtom
>*>(aData
);
2733 PRInt32 length
= classes
->Count();
2735 for (i
= 0; i
< length
; ++i
) {
2736 if (!classAttr
->Contains(classes
->ObjectAt(i
), eCaseMatters
)) {
2746 nsDocument::DestroyClassNameArray(void* aData
)
2748 nsCOMArray
<nsIAtom
>* classes
= static_cast<nsCOMArray
<nsIAtom
>*>(aData
);
2753 nsDocument::SetBaseURI(nsIURI
* aURI
)
2755 nsresult rv
= NS_OK
;
2758 rv
= nsContentUtils::GetSecurityManager()->
2759 CheckLoadURIWithPrincipal(NodePrincipal(), aURI
,
2760 nsIScriptSecurityManager::STANDARD
);
2761 if (NS_SUCCEEDED(rv
)) {
2762 mDocumentBaseURI
= NS_TryToMakeImmutable(aURI
);
2765 mDocumentBaseURI
= nsnull
;
2772 nsDocument::GetBaseTarget(nsAString
&aBaseTarget
) const
2774 aBaseTarget
.Assign(mBaseTarget
);
2778 nsDocument::SetBaseTarget(const nsAString
&aBaseTarget
)
2780 mBaseTarget
.Assign(aBaseTarget
);
2784 nsDocument::SetDocumentCharacterSet(const nsACString
& aCharSetID
)
2786 if (!mCharacterSet
.Equals(aCharSetID
)) {
2787 mCharacterSet
= aCharSetID
;
2790 nsCOMPtr
<nsICharsetAlias
> calias(do_GetService(NS_CHARSETALIAS_CONTRACTID
));
2792 nsCAutoString canonicalName
;
2793 calias
->GetPreferred(aCharSetID
, canonicalName
);
2794 NS_ASSERTION(canonicalName
.Equals(aCharSetID
),
2795 "charset name must be canonical");
2799 PRInt32 n
= mCharSetObservers
.Count();
2801 for (PRInt32 i
= 0; i
< n
; i
++) {
2802 nsIObserver
* observer
=
2803 static_cast<nsIObserver
*>(mCharSetObservers
.ElementAt(i
));
2805 observer
->Observe(static_cast<nsIDocument
*>(this), "charset",
2806 NS_ConvertASCIItoUTF16(aCharSetID
).get());
2812 nsDocument::AddCharSetObserver(nsIObserver
* aObserver
)
2814 NS_ENSURE_ARG_POINTER(aObserver
);
2816 NS_ENSURE_TRUE(mCharSetObservers
.AppendElement(aObserver
), NS_ERROR_FAILURE
);
2822 nsDocument::RemoveCharSetObserver(nsIObserver
* aObserver
)
2824 mCharSetObservers
.RemoveElement(aObserver
);
2828 nsDocument::GetHeaderData(nsIAtom
* aHeaderField
, nsAString
& aData
) const
2831 const nsDocHeaderData
* data
= mHeaderData
;
2833 if (data
->mField
== aHeaderField
) {
2834 aData
= data
->mData
;
2843 nsDocument::SetHeaderData(nsIAtom
* aHeaderField
, const nsAString
& aData
)
2845 if (!aHeaderField
) {
2846 NS_ERROR("null headerField");
2851 if (!aData
.IsEmpty()) { // don't bother storing empty string
2852 mHeaderData
= new nsDocHeaderData(aHeaderField
, aData
);
2856 nsDocHeaderData
* data
= mHeaderData
;
2857 nsDocHeaderData
** lastPtr
= &mHeaderData
;
2858 PRBool found
= PR_FALSE
;
2859 do { // look for existing and replace
2860 if (data
->mField
== aHeaderField
) {
2861 if (!aData
.IsEmpty()) {
2862 data
->mData
.Assign(aData
);
2864 else { // don't store empty string
2865 *lastPtr
= data
->mNext
;
2866 data
->mNext
= nsnull
;
2873 lastPtr
= &(data
->mNext
);
2877 if (!aData
.IsEmpty() && !found
) {
2878 // didn't find, append
2879 *lastPtr
= new nsDocHeaderData(aHeaderField
, aData
);
2883 if (aHeaderField
== nsGkAtoms::headerContentLanguage
) {
2884 CopyUTF16toUTF8(aData
, mContentLanguage
);
2887 // Set the default script-type on the root element.
2888 if (aHeaderField
== nsGkAtoms::headerContentScriptType
) {
2889 nsIContent
*root
= GetRootContent();
2891 // Get the script-type ID for this value.
2893 nsCOMPtr
<nsIScriptRuntime
> runtime
;
2894 rv
= NS_GetScriptRuntime(aData
, getter_AddRefs(runtime
));
2895 if (NS_FAILED(rv
) || runtime
== nsnull
) {
2896 NS_WARNING("The script-type is unknown");
2898 root
->SetScriptTypeID(runtime
->GetScriptTypeID());
2903 if (aHeaderField
== nsGkAtoms::headerDefaultStyle
) {
2904 // Only mess with our stylesheets if we don't have a lastStyleSheetSet, per
2906 if (DOMStringIsNull(mLastStyleSheetSet
)) {
2907 // Calling EnableStyleSheetsForSetInternal, not SetSelectedStyleSheetSet,
2908 // per spec. The idea here is that we're changing our preferred set and
2909 // that shouldn't change the value of lastStyleSheetSet. Also, we're
2910 // using the Internal version so we can update the CSSLoader and not have
2911 // to worry about null strings.
2912 EnableStyleSheetsForSetInternal(aData
, PR_TRUE
);
2916 if (aHeaderField
== nsGkAtoms::refresh
) {
2917 // We get into this code before we have a script global yet, so get to
2918 // our container via mDocumentContainer.
2919 nsCOMPtr
<nsIRefreshURI
> refresher
= do_QueryReferent(mDocumentContainer
);
2921 // Note: using mDocumentURI instead of mBaseURI here, for consistency
2922 // (used to just use the current URI of our webnavigation, but that
2923 // should really be the same thing). Note that this code can run
2924 // before the current URI of the webnavigation has been updated, so we
2925 // can't assert equality here.
2926 refresher
->SetupRefreshURIFromHeader(mDocumentURI
,
2927 NS_ConvertUTF16toUTF8(aData
));
2933 nsDocument::TryChannelCharset(nsIChannel
*aChannel
,
2934 PRInt32
& aCharsetSource
,
2935 nsACString
& aCharset
)
2937 if(kCharsetFromChannel
<= aCharsetSource
) {
2942 nsCAutoString charsetVal
;
2943 nsresult rv
= aChannel
->GetContentCharset(charsetVal
);
2944 if (NS_SUCCEEDED(rv
)) {
2945 nsCOMPtr
<nsICharsetAlias
> calias(do_GetService(NS_CHARSETALIAS_CONTRACTID
));
2947 nsCAutoString preferred
;
2948 rv
= calias
->GetPreferred(charsetVal
,
2950 if(NS_SUCCEEDED(rv
)) {
2951 aCharset
= preferred
;
2952 aCharsetSource
= kCharsetFromChannel
;
2962 nsDocument::CreateShell(nsPresContext
* aContext
, nsIViewManager
* aViewManager
,
2963 nsStyleSet
* aStyleSet
,
2964 nsIPresShell
** aInstancePtrResult
)
2966 // Don't add anything here. Add it to |doCreateShell| instead.
2967 // This exists so that subclasses can pass other values for the 4th
2968 // parameter some of the time.
2969 return doCreateShell(aContext
, aViewManager
, aStyleSet
,
2970 eCompatibility_FullStandards
, aInstancePtrResult
);
2974 nsDocument::doCreateShell(nsPresContext
* aContext
,
2975 nsIViewManager
* aViewManager
, nsStyleSet
* aStyleSet
,
2976 nsCompatibility aCompatMode
,
2977 nsIPresShell
** aInstancePtrResult
)
2979 *aInstancePtrResult
= nsnull
;
2981 NS_ENSURE_FALSE(mShellsAreHidden
, NS_ERROR_FAILURE
);
2983 FillStyleSet(aStyleSet
);
2985 nsCOMPtr
<nsIPresShell
> shell
;
2986 nsresult rv
= NS_NewPresShell(getter_AddRefs(shell
));
2987 if (NS_FAILED(rv
)) {
2991 rv
= shell
->Init(this, aContext
, aViewManager
, aStyleSet
, aCompatMode
);
2992 NS_ENSURE_SUCCESS(rv
, rv
);
2994 // Note: we don't hold a ref to the shell (it holds a ref to us)
2995 NS_ENSURE_TRUE(mPresShells
.AppendElementUnlessExists(shell
),
2996 NS_ERROR_OUT_OF_MEMORY
);
2997 shell
.swap(*aInstancePtrResult
);
3003 nsDocument::DeleteShell(nsIPresShell
* aShell
)
3005 return mPresShells
.RemoveElement(aShell
);
3010 nsDocument::GetPrimaryShell() const
3012 return mShellsAreHidden
? nsnull
: mPresShells
.SafeElementAt(0, nsnull
);
3016 SubDocClearEntry(PLDHashTable
*table
, PLDHashEntryHdr
*entry
)
3018 SubDocMapEntry
*e
= static_cast<SubDocMapEntry
*>(entry
);
3020 NS_RELEASE(e
->mKey
);
3021 if (e
->mSubDocument
) {
3022 e
->mSubDocument
->SetParentDocument(nsnull
);
3023 NS_RELEASE(e
->mSubDocument
);
3028 SubDocInitEntry(PLDHashTable
*table
, PLDHashEntryHdr
*entry
, const void *key
)
3031 const_cast<SubDocMapEntry
*>
3032 (static_cast<const SubDocMapEntry
*>(entry
));
3034 e
->mKey
= const_cast<nsIContent
*>
3035 (static_cast<const nsIContent
*>(key
));
3038 e
->mSubDocument
= nsnull
;
3043 nsDocument::SetSubDocumentFor(nsIContent
*aContent
, nsIDocument
* aSubDoc
)
3045 NS_ENSURE_TRUE(aContent
, NS_ERROR_UNEXPECTED
);
3048 // aSubDoc is nsnull, remove the mapping
3050 if (mSubDocuments
) {
3051 SubDocMapEntry
*entry
=
3052 static_cast<SubDocMapEntry
*>
3053 (PL_DHashTableOperate(mSubDocuments
, aContent
,
3056 if (PL_DHASH_ENTRY_IS_BUSY(entry
)) {
3057 PL_DHashTableRawRemove(mSubDocuments
, entry
);
3061 if (!mSubDocuments
) {
3062 // Create a new hashtable
3064 static PLDHashTableOps hash_table_ops
=
3068 PL_DHashVoidPtrKeyStub
,
3069 PL_DHashMatchEntryStub
,
3070 PL_DHashMoveEntryStub
,
3072 PL_DHashFinalizeStub
,
3076 mSubDocuments
= PL_NewDHashTable(&hash_table_ops
, nsnull
,
3077 sizeof(SubDocMapEntry
), 16);
3078 if (!mSubDocuments
) {
3079 return NS_ERROR_OUT_OF_MEMORY
;
3083 // Add a mapping to the hash table
3084 SubDocMapEntry
*entry
=
3085 static_cast<SubDocMapEntry
*>
3086 (PL_DHashTableOperate(mSubDocuments
, aContent
,
3090 return NS_ERROR_OUT_OF_MEMORY
;
3093 if (entry
->mSubDocument
) {
3094 entry
->mSubDocument
->SetParentDocument(nsnull
);
3096 // Release the old sub document
3097 NS_RELEASE(entry
->mSubDocument
);
3100 entry
->mSubDocument
= aSubDoc
;
3101 NS_ADDREF(entry
->mSubDocument
);
3103 aSubDoc
->SetParentDocument(this);
3110 nsDocument::GetSubDocumentFor(nsIContent
*aContent
) const
3112 if (mSubDocuments
) {
3113 SubDocMapEntry
*entry
=
3114 static_cast<SubDocMapEntry
*>
3115 (PL_DHashTableOperate(mSubDocuments
, aContent
,
3118 if (PL_DHASH_ENTRY_IS_BUSY(entry
)) {
3119 return entry
->mSubDocument
;
3126 static PLDHashOperator
3127 FindContentEnumerator(PLDHashTable
*table
, PLDHashEntryHdr
*hdr
,
3128 PRUint32 number
, void *arg
)
3130 SubDocMapEntry
*entry
= static_cast<SubDocMapEntry
*>(hdr
);
3131 FindContentData
*data
= static_cast<FindContentData
*>(arg
);
3133 if (entry
->mSubDocument
== data
->mSubDocument
) {
3134 data
->mResult
= entry
->mKey
;
3136 return PL_DHASH_STOP
;
3139 return PL_DHASH_NEXT
;
3143 nsDocument::FindContentForSubDocument(nsIDocument
*aDocument
) const
3145 NS_ENSURE_TRUE(aDocument
, nsnull
);
3147 if (!mSubDocuments
) {
3151 FindContentData
data(aDocument
);
3152 PL_DHashTableEnumerate(mSubDocuments
, FindContentEnumerator
, &data
);
3154 return data
.mResult
;
3158 nsDocument::IsNodeOfType(PRUint32 aFlags
) const
3160 return !(aFlags
& ~eDOCUMENT
);
3164 nsDocument::GetRootContentInternal() const
3166 // Loop backwards because any non-elements, such as doctypes and PIs
3167 // are likely to appear before the root element.
3169 for (i
= mChildren
.ChildCount(); i
> 0; --i
) {
3170 nsIContent
* child
= mChildren
.ChildAt(i
- 1);
3171 if (child
->IsNodeOfType(nsINode::eELEMENT
)) {
3172 const_cast<nsDocument
*>(this)->mCachedRootContent
= child
;
3177 const_cast<nsDocument
*>(this)->mCachedRootContent
= nsnull
;
3182 nsDocument::GetChildAt(PRUint32 aIndex
) const
3184 return mChildren
.GetSafeChildAt(aIndex
);
3188 nsDocument::IndexOf(nsINode
* aPossibleChild
) const
3190 return mChildren
.IndexOfChild(aPossibleChild
);
3194 nsDocument::GetChildCount() const
3196 return mChildren
.ChildCount();
3199 nsIContent
* const *
3200 nsDocument::GetChildArray(PRUint32
* aChildCount
) const
3202 return mChildren
.GetChildArray(aChildCount
);
3207 nsDocument::InsertChildAt(nsIContent
* aKid
, PRUint32 aIndex
,
3210 if (aKid
->IsNodeOfType(nsINode::eELEMENT
) &&
3212 NS_ERROR("Inserting element child when we already have one");
3213 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
;
3216 return nsGenericElement::doInsertChildAt(aKid
, aIndex
, aNotify
,
3217 nsnull
, this, mChildren
);
3221 nsDocument::AppendChildTo(nsIContent
* aKid
, PRBool aNotify
)
3223 // Make sure to _not_ call the subclass InsertChildAt here. If
3224 // subclasses wanted to hook into this stuff, they would have
3225 // overridden AppendChildTo.
3226 // XXXbz maybe this should just be a non-virtual method on nsINode?
3227 // Feels that way to me...
3228 return nsDocument::InsertChildAt(aKid
, GetChildCount(), aNotify
);
3232 nsDocument::RemoveChildAt(PRUint32 aIndex
, PRBool aNotify
)
3234 nsCOMPtr
<nsIContent
> oldKid
= GetChildAt(aIndex
);
3239 if (oldKid
->IsNodeOfType(nsINode::eELEMENT
)) {
3240 // Destroy the link map up front before we mess with the child list.
3244 nsresult rv
= nsGenericElement::doRemoveChildAt(aIndex
, aNotify
, oldKid
,
3245 nsnull
, this, mChildren
);
3246 mCachedRootContent
= nsnull
;
3251 nsDocument::GetNumberOfStyleSheets() const
3253 return mStyleSheets
.Count();
3257 nsDocument::GetStyleSheetAt(PRInt32 aIndex
) const
3259 NS_ENSURE_TRUE(0 <= aIndex
&& aIndex
< mStyleSheets
.Count(), nsnull
);
3260 return mStyleSheets
[aIndex
];
3264 nsDocument::GetIndexOfStyleSheet(nsIStyleSheet
* aSheet
) const
3266 return mStyleSheets
.IndexOf(aSheet
);
3270 nsDocument::AddStyleSheetToStyleSets(nsIStyleSheet
* aSheet
)
3272 nsPresShellIterator
iter(this);
3273 nsCOMPtr
<nsIPresShell
> shell
;
3274 while ((shell
= iter
.GetNextShell())) {
3275 shell
->StyleSet()->AddDocStyleSheet(aSheet
, this);
3280 nsDocument::AddStyleSheet(nsIStyleSheet
* aSheet
)
3282 NS_PRECONDITION(aSheet
, "null arg");
3283 mStyleSheets
.AppendObject(aSheet
);
3284 aSheet
->SetOwningDocument(this);
3287 aSheet
->GetApplicable(applicable
);
3290 AddStyleSheetToStyleSets(aSheet
);
3293 NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded
, (this, aSheet
, PR_TRUE
));
3297 nsDocument::RemoveStyleSheetFromStyleSets(nsIStyleSheet
* aSheet
)
3299 nsPresShellIterator
iter(this);
3300 nsCOMPtr
<nsIPresShell
> shell
;
3301 while ((shell
= iter
.GetNextShell())) {
3302 shell
->StyleSet()->RemoveStyleSheet(nsStyleSet::eDocSheet
, aSheet
);
3307 nsDocument::RemoveStyleSheet(nsIStyleSheet
* aSheet
)
3309 NS_PRECONDITION(aSheet
, "null arg");
3310 nsCOMPtr
<nsIStyleSheet
> sheet
= aSheet
; // hold ref so it won't die too soon
3312 if (!mStyleSheets
.RemoveObject(aSheet
)) {
3313 NS_NOTREACHED("stylesheet not found");
3317 if (!mIsGoingAway
) {
3318 PRBool applicable
= PR_TRUE
;
3319 aSheet
->GetApplicable(applicable
);
3321 RemoveStyleSheetFromStyleSets(aSheet
);
3324 NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetRemoved
, (this, aSheet
, PR_TRUE
));
3327 aSheet
->SetOwningDocument(nsnull
);
3331 nsDocument::UpdateStyleSheets(nsCOMArray
<nsIStyleSheet
>& aOldSheets
,
3332 nsCOMArray
<nsIStyleSheet
>& aNewSheets
)
3334 BeginUpdate(UPDATE_STYLE
);
3336 // XXX Need to set the sheet on the ownernode, if any
3337 NS_PRECONDITION(aOldSheets
.Count() == aNewSheets
.Count(),
3338 "The lists must be the same length!");
3339 PRInt32 count
= aOldSheets
.Count();
3341 nsCOMPtr
<nsIStyleSheet
> oldSheet
;
3343 for (i
= 0; i
< count
; ++i
) {
3344 oldSheet
= aOldSheets
[i
];
3346 // First remove the old sheet.
3347 NS_ASSERTION(oldSheet
, "None of the old sheets should be null");
3348 PRInt32 oldIndex
= mStyleSheets
.IndexOf(oldSheet
);
3349 RemoveStyleSheet(oldSheet
); // This does the right notifications
3351 // Now put the new one in its place. If it's null, just ignore it.
3352 nsIStyleSheet
* newSheet
= aNewSheets
[i
];
3354 mStyleSheets
.InsertObjectAt(newSheet
, oldIndex
);
3355 newSheet
->SetOwningDocument(this);
3356 PRBool applicable
= PR_TRUE
;
3357 newSheet
->GetApplicable(applicable
);
3359 AddStyleSheetToStyleSets(newSheet
);
3362 NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded
, (this, newSheet
, PR_TRUE
));
3366 EndUpdate(UPDATE_STYLE
);
3370 nsDocument::InsertStyleSheetAt(nsIStyleSheet
* aSheet
, PRInt32 aIndex
)
3372 NS_PRECONDITION(aSheet
, "null ptr");
3373 mStyleSheets
.InsertObjectAt(aSheet
, aIndex
);
3375 aSheet
->SetOwningDocument(this);
3378 aSheet
->GetApplicable(applicable
);
3381 AddStyleSheetToStyleSets(aSheet
);
3384 NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded
, (this, aSheet
, PR_TRUE
));
3389 nsDocument::SetStyleSheetApplicableState(nsIStyleSheet
* aSheet
,
3392 NS_PRECONDITION(aSheet
, "null arg");
3394 // If we're actually in the document style sheet list
3395 if (-1 != mStyleSheets
.IndexOf(aSheet
)) {
3397 AddStyleSheetToStyleSets(aSheet
);
3399 RemoveStyleSheetFromStyleSets(aSheet
);
3403 // We have to always notify, since this will be called for sheets
3404 // that are children of sheets in our style set, as well as some
3405 // sheets for nsHTMLEditor.
3407 NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetApplicableStateChanged
,
3408 (this, aSheet
, aApplicable
));
3411 // These three functions are a lot like the implementation of the
3412 // corresponding API for regular stylesheets.
3415 nsDocument::GetNumberOfCatalogStyleSheets() const
3417 return mCatalogSheets
.Count();
3421 nsDocument::GetCatalogStyleSheetAt(PRInt32 aIndex
) const
3423 NS_ENSURE_TRUE(0 <= aIndex
&& aIndex
< mCatalogSheets
.Count(), nsnull
);
3424 return mCatalogSheets
[aIndex
];
3428 nsDocument::AddCatalogStyleSheet(nsIStyleSheet
* aSheet
)
3430 mCatalogSheets
.AppendObject(aSheet
);
3431 aSheet
->SetOwningDocument(this);
3434 aSheet
->GetApplicable(applicable
);
3437 // This is like |AddStyleSheetToStyleSets|, but for an agent sheet.
3438 nsPresShellIterator
iter(this);
3439 nsCOMPtr
<nsIPresShell
> shell
;
3440 while ((shell
= iter
.GetNextShell())) {
3441 shell
->StyleSet()->AppendStyleSheet(nsStyleSet::eAgentSheet
, aSheet
);
3445 NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded
, (this, aSheet
, PR_FALSE
));
3449 nsDocument::EnsureCatalogStyleSheet(const char *aStyleSheetURI
)
3451 nsICSSLoader
* cssLoader
= CSSLoader();
3453 if (NS_SUCCEEDED(cssLoader
->GetEnabled(&enabled
)) && enabled
) {
3454 PRInt32 sheetCount
= GetNumberOfCatalogStyleSheets();
3455 for (PRInt32 i
= 0; i
< sheetCount
; i
++) {
3456 nsIStyleSheet
* sheet
= GetCatalogStyleSheetAt(i
);
3457 NS_ASSERTION(sheet
, "unexpected null stylesheet in the document");
3459 nsCOMPtr
<nsIURI
> uri
;
3460 sheet
->GetSheetURI(getter_AddRefs(uri
));
3461 nsCAutoString uriStr
;
3462 uri
->GetSpec(uriStr
);
3463 if (uriStr
.Equals(aStyleSheetURI
))
3468 nsCOMPtr
<nsIURI
> uri
;
3469 NS_NewURI(getter_AddRefs(uri
), aStyleSheetURI
);
3471 nsCOMPtr
<nsICSSStyleSheet
> sheet
;
3472 cssLoader
->LoadSheetSync(uri
, PR_TRUE
, getter_AddRefs(sheet
));
3474 BeginUpdate(UPDATE_STYLE
);
3475 AddCatalogStyleSheet(sheet
);
3476 EndUpdate(UPDATE_STYLE
);
3482 nsIScriptGlobalObject
*
3483 nsDocument::GetScriptGlobalObject() const
3485 // If we're going away, we've already released the reference to our
3486 // ScriptGlobalObject. We can, however, try to obtain it for the
3487 // caller through our docshell.
3489 // We actually need to start returning the docshell's script global
3490 // object as soon as nsDocumentViewer::Close has called
3491 // RemovedFromDocShell on us.
3492 if (mRemovedFromDocShell
) {
3493 nsCOMPtr
<nsIInterfaceRequestor
> requestor
=
3494 do_QueryReferent(mDocumentContainer
);
3496 nsCOMPtr
<nsIScriptGlobalObject
> globalObject
= do_GetInterface(requestor
);
3497 return globalObject
;
3501 return mScriptGlobalObject
;
3504 nsIScriptGlobalObject
*
3505 nsDocument::GetScopeObject()
3507 nsCOMPtr
<nsIScriptGlobalObject
> scope(do_QueryReferent(mScopeObject
));
3512 nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject
*aScriptGlobalObject
)
3516 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(aScriptGlobalObject
));
3518 NS_ASSERTION(!win
|| win
->IsInnerWindow(),
3519 "Script global object must be an inner window!");
3523 if (mScriptGlobalObject
&& !aScriptGlobalObject
) {
3524 // We're detaching from the window. We need to grab a pointer to
3525 // our layout history state now.
3526 mLayoutHistoryState
= GetLayoutHistoryState();
3528 // Also make sure to remove our onload blocker now if we haven't done it yet
3529 if (mOnloadBlockCount
!= 0) {
3530 nsCOMPtr
<nsILoadGroup
> loadGroup
= GetDocumentLoadGroup();
3532 loadGroup
->RemoveRequest(mOnloadBlocker
, nsnull
, NS_OK
);
3537 mScriptGlobalObject
= aScriptGlobalObject
;
3539 if (aScriptGlobalObject
) {
3540 mScriptObject
= nsnull
;
3541 mHasHadScriptHandlingObject
= PR_TRUE
;
3542 // Go back to using the docshell for the layout history state
3543 mLayoutHistoryState
= nsnull
;
3544 mScopeObject
= do_GetWeakReference(aScriptGlobalObject
);
3547 // Remember the pointer to our window (or lack there of), to avoid
3548 // having to QI every time it's asked for.
3549 nsCOMPtr
<nsPIDOMWindow
> window
= do_QueryInterface(mScriptGlobalObject
);
3553 nsIScriptGlobalObject
*
3554 nsDocument::GetScriptHandlingObject(PRBool
& aHasHadScriptHandlingObject
) const
3556 aHasHadScriptHandlingObject
= mHasHadScriptHandlingObject
;
3557 if (mScriptGlobalObject
) {
3558 return mScriptGlobalObject
;
3561 nsCOMPtr
<nsIScriptGlobalObject
> scriptHandlingObject
=
3562 do_QueryReferent(mScriptObject
);
3563 nsCOMPtr
<nsPIDOMWindow
> win
= do_QueryInterface(scriptHandlingObject
);
3565 NS_ASSERTION(win
->IsInnerWindow(), "Should have inner window here!");
3566 nsPIDOMWindow
* outer
= win
->GetOuterWindow();
3567 if (!outer
|| outer
->GetCurrentInnerWindow() != win
) {
3568 NS_WARNING("Wrong inner/outer window combination!");
3572 return scriptHandlingObject
;
3575 nsDocument::SetScriptHandlingObject(nsIScriptGlobalObject
* aScriptObject
)
3577 NS_ASSERTION(!mScriptGlobalObject
||
3578 mScriptGlobalObject
== aScriptObject
,
3579 "Wrong script object!");
3580 nsCOMPtr
<nsPIDOMWindow
> win
= do_QueryInterface(aScriptObject
);
3581 NS_ASSERTION(!win
|| win
->IsInnerWindow(), "Should have inner window here!");
3582 mScopeObject
= mScriptObject
= do_GetWeakReference(aScriptObject
);
3583 if (aScriptObject
) {
3584 mHasHadScriptHandlingObject
= PR_TRUE
;
3589 nsDocument::GetWindow()
3592 return mWindow
->GetOuterWindow();
3595 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(GetScriptGlobalObject()));
3601 return win
->GetOuterWindow();
3605 nsDocument::GetInnerWindow()
3607 if (!mRemovedFromDocShell
) {
3611 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(GetScriptGlobalObject()));
3617 nsDocument::ScriptLoader()
3619 return mScriptLoader
;
3622 // Note: We don't hold a reference to the document observer; we assume
3623 // that it has a live reference to the document.
3625 nsDocument::AddObserver(nsIDocumentObserver
* aObserver
)
3627 // The array makes sure the observer isn't already in the list
3628 mObservers
.AppendElementUnlessExists(aObserver
);
3629 AddMutationObserver(aObserver
);
3633 nsDocument::RemoveObserver(nsIDocumentObserver
* aObserver
)
3635 // If we're in the process of destroying the document (and we're
3636 // informing the observers of the destruction), don't remove the
3637 // observers from the list. This is not a big deal, since we
3638 // don't hold a live reference to the observers.
3639 if (!mInDestructor
) {
3640 RemoveMutationObserver(aObserver
);
3641 return mObservers
.RemoveElement(aObserver
);
3644 return mObservers
.Contains(aObserver
);
3648 nsDocument::BeginUpdate(nsUpdateType aUpdateType
)
3650 if (mUpdateNestLevel
== 0) {
3651 BindingManager()->BeginOutermostUpdate();
3655 NS_DOCUMENT_NOTIFY_OBSERVERS(BeginUpdate
, (this, aUpdateType
));
3657 if (aUpdateType
== UPDATE_CONTENT_MODEL
) {
3658 nsContentUtils::AddRemovableScriptBlocker();
3661 nsContentUtils::AddScriptBlocker();
3666 nsDocument::EndUpdate(nsUpdateType aUpdateType
)
3668 if (aUpdateType
== UPDATE_CONTENT_MODEL
) {
3669 nsContentUtils::RemoveRemovableScriptBlocker();
3672 nsContentUtils::RemoveScriptBlocker();
3674 NS_DOCUMENT_NOTIFY_OBSERVERS(EndUpdate
, (this, aUpdateType
));
3677 if (mUpdateNestLevel
== 0) {
3678 // This set of updates may have created XBL bindings. Let the
3679 // binding manager know we're done.
3680 BindingManager()->EndOutermostUpdate();
3683 if (mUpdateNestLevel
== 0 && !mDelayFrameLoaderInitialization
) {
3684 InitializeFinalizeFrameLoaders();
3689 nsDocument::BeginLoad()
3691 // Block onload here to prevent having to deal with blocking and
3692 // unblocking it while we know the document is loading.
3695 if (mScriptLoader
) {
3696 mScriptLoader
->BeginDeferringScripts();
3699 NS_DOCUMENT_NOTIFY_OBSERVERS(BeginLoad
, (this));
3703 nsDocument::CheckGetElementByIdArg(const nsIAtom
* aId
)
3705 if (aId
== nsGkAtoms::_empty
) {
3706 nsContentUtils::ReportToConsole(
3707 nsContentUtils::eDOM_PROPERTIES
,
3708 "EmptyGetElementByIdParam",
3711 EmptyString(), 0, 0,
3712 nsIScriptError::warningFlag
,
3720 MatchAllElementsId(nsIContent
* aContent
, nsIAtom
* aId
, nsIdentifierMapEntry
* aEntry
)
3722 if (aId
== aContent
->GetID()) {
3723 aEntry
->AddIdContent(aContent
);
3726 PRUint32 i
, count
= aContent
->GetChildCount();
3727 for (i
= 0; i
< count
; i
++) {
3728 MatchAllElementsId(aContent
->GetChildAt(i
), aId
, aEntry
);
3732 nsIdentifierMapEntry
*
3733 nsDocument::GetElementByIdInternal(nsIAtom
* aID
)
3735 // We don't have to flush before we do the initial hashtable lookup, since if
3736 // the id is already in the hashtable it couldn't have been removed without
3737 // us being notified (all removals notify immediately, as far as I can tell).
3738 // So do the lookup first.
3739 nsIdentifierMapEntry
*entry
= mIdentifierMap
.PutEntry(aID
);
3740 NS_ENSURE_TRUE(entry
, nsnull
);
3742 if (entry
->GetIdContent())
3745 // Now we have to flush. It could be that we have a cached "not in
3746 // document" or know nothing about this ID yet but more content has been
3747 // added to the document since. Note that we have to flush notifications,
3748 // so that the entry will get updated properly.
3750 // Make sure to stash away the current generation so we can check whether
3751 // the table changes when we flush.
3752 PRUint32 generation
= mIdentifierMap
.GetGeneration();
3754 FlushPendingNotifications(Flush_ContentAndNotify
);
3756 if (generation
!= mIdentifierMap
.GetGeneration()) {
3757 // Table changed, so the entry pointer is no longer valid; look up the
3758 // entry again, adding if necessary (the adding may be necessary in case
3759 // the flush actually deleted entries).
3760 entry
= mIdentifierMap
.PutEntry(aID
);
3763 PRBool isNotInDocument
;
3764 nsIContent
*e
= entry
->GetIdContent(&isNotInDocument
);
3765 if (e
|| isNotInDocument
)
3768 // Status of this id is unknown, search document
3769 nsIContent
* root
= GetRootContent();
3770 if (!IdTableIsLive()) {
3771 if (IdTableShouldBecomeLive()) {
3772 // Just make sure our table is up to date and call this method again
3773 // to look up in the hashtable.
3775 RegisterNamedItems(root
);
3777 return GetElementByIdInternal(aID
);
3781 // No-one should have registered an ID change callback yet. We don't
3782 // want to fire one as a side-effect of getElementById! This shouldn't
3783 // happen, since if someone called AddIDTargetObserver already for
3784 // this ID, we should have filled in this entry with content or
3786 NS_ASSERTION(!entry
->HasContentChangeCallback(),
3787 "No callbacks should be registered while we set up this entry");
3788 MatchAllElementsId(root
, aID
, entry
);
3789 e
= entry
->GetIdContent();
3795 // No reason to call MatchElementId if !IdTableIsLive, since
3796 // we'd have done just that already
3797 if (IdTableIsLive() && root
&& aID
!= nsGkAtoms::_empty
) {
3798 nsIContent
* eDebug
=
3799 nsContentUtils::MatchElementId(root
, aID
);
3800 NS_ASSERTION(!eDebug
,
3801 "We got null for |e| but MatchElementId found something?");
3804 // There is no element with the given id in the document, cache
3805 // the fact that it's not in the document
3806 entry
->FlagIDNotInDocument();
3814 nsDocument::GetElementById(const nsAString
& aElementId
,
3815 nsIDOMElement
** aReturn
)
3817 NS_ENSURE_ARG_POINTER(aReturn
);
3820 nsCOMPtr
<nsIAtom
> idAtom(do_GetAtom(aElementId
));
3821 NS_ENSURE_TRUE(idAtom
, NS_ERROR_OUT_OF_MEMORY
);
3822 if (!CheckGetElementByIdArg(idAtom
))
3825 nsIdentifierMapEntry
*entry
= GetElementByIdInternal(idAtom
);
3826 NS_ENSURE_TRUE(entry
, NS_ERROR_OUT_OF_MEMORY
);
3828 PRBool isNotInDocument
;
3829 nsIContent
*e
= entry
->GetIdContent(&isNotInDocument
);
3830 NS_ASSERTION(e
|| isNotInDocument
, "Incomplete map entry!");
3831 if (isNotInDocument
)
3834 return CallQueryInterface(e
, aReturn
);
3838 nsDocument::AddIDTargetObserver(nsIAtom
* aID
, IDTargetObserver aObserver
,
3841 if (!CheckGetElementByIdArg(aID
))
3844 nsIdentifierMapEntry
*entry
= GetElementByIdInternal(aID
);
3845 NS_ENSURE_TRUE(entry
, nsnull
);
3847 entry
->AddContentChangeCallback(aObserver
, aData
);
3848 return entry
->GetIdContent();
3852 nsDocument::RemoveIDTargetObserver(nsIAtom
* aID
,
3853 IDTargetObserver aObserver
, void* aData
)
3855 if (!CheckGetElementByIdArg(aID
))
3858 nsIdentifierMapEntry
*entry
= GetElementByIdInternal(aID
);
3862 entry
->RemoveContentChangeCallback(aObserver
, aData
);
3866 nsDocument::DispatchContentLoadedEvents()
3868 // If you add early returns from this method, make sure you're
3869 // calling UnblockOnload properly.
3871 // Fire a DOM event notifying listeners that this document has been
3872 // loaded (excluding images and other loads initiated by this
3874 nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument
*>(this),
3875 NS_LITERAL_STRING("DOMContentLoaded"),
3878 // If this document is a [i]frame, fire a DOMFrameContentLoaded
3879 // event on all parent documents notifying that the HTML (excluding
3880 // other external files such as images and stylesheets) in a frame
3881 // has finished loading.
3883 // target_frame is the [i]frame element that will be used as the
3884 // target for the event. It's the [i]frame whose content is done
3886 nsCOMPtr
<nsIDOMEventTarget
> target_frame
;
3888 if (mParentDocument
) {
3890 do_QueryInterface(mParentDocument
->FindContentForSubDocument(this));
3894 nsCOMPtr
<nsIDocument
> parent
= mParentDocument
;
3896 nsCOMPtr
<nsIDOMDocumentEvent
> document_event
=
3897 do_QueryInterface(parent
);
3899 nsCOMPtr
<nsIDOMEvent
> event
;
3900 nsCOMPtr
<nsIPrivateDOMEvent
> privateEvent
;
3901 if (document_event
) {
3902 document_event
->CreateEvent(NS_LITERAL_STRING("Events"),
3903 getter_AddRefs(event
));
3905 privateEvent
= do_QueryInterface(event
);
3908 if (event
&& privateEvent
) {
3909 event
->InitEvent(NS_LITERAL_STRING("DOMFrameContentLoaded"), PR_TRUE
,
3912 privateEvent
->SetTarget(target_frame
);
3913 privateEvent
->SetTrusted(PR_TRUE
);
3915 // To dispatch this event we must manually call
3916 // nsEventDispatcher::Dispatch() on the ancestor document since the
3917 // target is not in the same document, so the event would never reach
3918 // the ancestor document if we used the normal event
3919 // dispatching code.
3921 nsEvent
* innerEvent
= privateEvent
->GetInternalNSEvent();
3923 nsEventStatus status
= nsEventStatus_eIgnore
;
3925 nsIPresShell
*shell
= parent
->GetPrimaryShell();
3927 nsCOMPtr
<nsPresContext
> context
= shell
->GetPresContext();
3930 nsEventDispatcher::Dispatch(parent
, context
, innerEvent
, event
,
3937 parent
= parent
->GetParentDocument();
3941 if (mScriptLoader
) {
3942 mScriptLoader
->EndDeferringScripts();
3945 UnblockOnload(PR_TRUE
);
3949 nsDocument::EndLoad()
3951 // Drop the ref to our parser, if any, but keep hold of the sink so that we
3952 // can flush it from FlushPendingNotifications as needed. We might have to
3953 // do that to get a StartLayout() to happen.
3955 mWeakSink
= do_GetWeakReference(mParser
->GetContentSink());
3959 NS_DOCUMENT_NOTIFY_OBSERVERS(EndLoad
, (this));
3961 if (!mSynchronousDOMContentLoaded
) {
3962 nsRefPtr
<nsIRunnable
> ev
=
3963 new nsRunnableMethod
<nsDocument
>(this,
3964 &nsDocument::DispatchContentLoadedEvents
);
3965 NS_DispatchToCurrentThread(ev
);
3967 DispatchContentLoadedEvents();
3972 nsDocument::ContentStatesChanged(nsIContent
* aContent1
, nsIContent
* aContent2
,
3975 NS_DOCUMENT_NOTIFY_OBSERVERS(ContentStatesChanged
,
3976 (this, aContent1
, aContent2
, aStateMask
));
3980 nsDocument::StyleRuleChanged(nsIStyleSheet
* aStyleSheet
,
3981 nsIStyleRule
* aOldStyleRule
,
3982 nsIStyleRule
* aNewStyleRule
)
3984 NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleChanged
,
3986 aOldStyleRule
, aNewStyleRule
));
3990 nsDocument::StyleRuleAdded(nsIStyleSheet
* aStyleSheet
,
3991 nsIStyleRule
* aStyleRule
)
3993 NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleAdded
,
3994 (this, aStyleSheet
, aStyleRule
));
3998 nsDocument::StyleRuleRemoved(nsIStyleSheet
* aStyleSheet
,
3999 nsIStyleRule
* aStyleRule
)
4001 NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleRemoved
,
4002 (this, aStyleSheet
, aStyleRule
));
4007 // nsIDOMDocument interface
4010 nsDocument::GetDoctype(nsIDOMDocumentType
** aDoctype
)
4012 NS_ENSURE_ARG_POINTER(aDoctype
);
4016 count
= mChildren
.ChildCount();
4017 for (i
= 0; i
< count
; i
++) {
4018 CallQueryInterface(mChildren
.ChildAt(i
), aDoctype
);
4029 nsDocument::GetImplementation(nsIDOMDOMImplementation
** aImplementation
)
4031 // For now, create a new implementation every time. This shouldn't
4032 // be a high bandwidth operation
4033 nsCOMPtr
<nsIURI
> uri
;
4034 NS_NewURI(getter_AddRefs(uri
), "about:blank");
4035 NS_ENSURE_TRUE(uri
, NS_ERROR_OUT_OF_MEMORY
);
4036 PRBool hasHadScriptObject
= PR_TRUE
;
4037 nsIScriptGlobalObject
* scriptObject
=
4038 GetScriptHandlingObject(hasHadScriptObject
);
4039 NS_ENSURE_STATE(scriptObject
|| !hasHadScriptObject
);
4040 *aImplementation
= new nsDOMImplementation(scriptObject
, uri
, uri
,
4042 if (!*aImplementation
) {
4043 return NS_ERROR_OUT_OF_MEMORY
;
4046 NS_ADDREF(*aImplementation
);
4052 nsDocument::GetDocumentElement(nsIDOMElement
** aDocumentElement
)
4054 NS_ENSURE_ARG_POINTER(aDocumentElement
);
4056 nsIContent
* root
= GetRootContent();
4058 return CallQueryInterface(root
, aDocumentElement
);
4061 *aDocumentElement
= nsnull
;
4067 nsDocument::CreateElement(const nsAString
& aTagName
,
4068 nsIDOMElement
** aReturn
)
4072 nsresult rv
= nsContentUtils::CheckQName(aTagName
, PR_FALSE
);
4073 NS_ENSURE_SUCCESS(rv
, rv
);
4075 NS_ASSERTION(IsCaseSensitive(),
4076 "nsDocument::CreateElement() called on document that is not "
4077 "case sensitive. Fix caller, or fix "
4078 "nsDocument::CreateElement()!");
4080 nsCOMPtr
<nsIAtom
> name
= do_GetAtom(aTagName
);
4082 nsCOMPtr
<nsIContent
> content
;
4083 rv
= CreateElem(name
, nsnull
, GetDefaultNamespaceID(), PR_TRUE
,
4084 getter_AddRefs(content
));
4085 NS_ENSURE_SUCCESS(rv
, rv
);
4087 return CallQueryInterface(content
, aReturn
);
4091 nsDocument::CreateElementNS(const nsAString
& aNamespaceURI
,
4092 const nsAString
& aQualifiedName
,
4093 nsIDOMElement
** aReturn
)
4097 nsCOMPtr
<nsINodeInfo
> nodeInfo
;
4098 nsresult rv
= nsContentUtils::GetNodeInfoFromQName(aNamespaceURI
,
4101 getter_AddRefs(nodeInfo
));
4102 NS_ENSURE_SUCCESS(rv
, rv
);
4104 nsCOMPtr
<nsIContent
> content
;
4105 NS_NewElement(getter_AddRefs(content
), nodeInfo
->NamespaceID(), nodeInfo
,
4107 NS_ENSURE_SUCCESS(rv
, rv
);
4109 return CallQueryInterface(content
, aReturn
);
4113 nsDocument::CreateTextNode(const nsAString
& aData
, nsIDOMText
** aReturn
)
4117 nsCOMPtr
<nsIContent
> text
;
4118 nsresult rv
= NS_NewTextNode(getter_AddRefs(text
), mNodeInfoManager
);
4120 if (NS_SUCCEEDED(rv
)) {
4121 // Don't notify; this node is still being created.
4122 text
->SetText(aData
, PR_FALSE
);
4124 rv
= CallQueryInterface(text
, aReturn
);
4131 nsDocument::CreateDocumentFragment(nsIDOMDocumentFragment
** aReturn
)
4133 return NS_NewDocumentFragment(aReturn
, mNodeInfoManager
);
4137 nsDocument::CreateComment(const nsAString
& aData
, nsIDOMComment
** aReturn
)
4141 // Make sure the substring "--" is not present in aData. Otherwise
4142 // we'll create a document that can't be serialized.
4143 if (FindInReadable(NS_LITERAL_STRING("--"), aData
)) {
4144 return NS_ERROR_DOM_INVALID_CHARACTER_ERR
;
4147 nsCOMPtr
<nsIContent
> comment
;
4148 nsresult rv
= NS_NewCommentNode(getter_AddRefs(comment
), mNodeInfoManager
);
4150 if (NS_SUCCEEDED(rv
)) {
4151 // Don't notify; this node is still being created.
4152 comment
->SetText(aData
, PR_FALSE
);
4154 rv
= CallQueryInterface(comment
, aReturn
);
4161 nsDocument::CreateCDATASection(const nsAString
& aData
,
4162 nsIDOMCDATASection
** aReturn
)
4164 NS_ENSURE_ARG_POINTER(aReturn
);
4167 if (FindInReadable(NS_LITERAL_STRING("]]>"), aData
))
4168 return NS_ERROR_DOM_INVALID_CHARACTER_ERR
;
4170 nsCOMPtr
<nsIContent
> content
;
4171 nsresult rv
= NS_NewXMLCDATASection(getter_AddRefs(content
),
4174 if (NS_SUCCEEDED(rv
)) {
4175 // Don't notify; this node is still being created.
4176 content
->SetText(aData
, PR_FALSE
);
4178 rv
= CallQueryInterface(content
, aReturn
);
4185 nsDocument::CreateProcessingInstruction(const nsAString
& aTarget
,
4186 const nsAString
& aData
,
4187 nsIDOMProcessingInstruction
** aReturn
)
4191 nsresult rv
= nsContentUtils::CheckQName(aTarget
, PR_FALSE
);
4192 NS_ENSURE_SUCCESS(rv
, rv
);
4194 if (FindInReadable(NS_LITERAL_STRING("?>"), aData
)) {
4195 return NS_ERROR_DOM_INVALID_CHARACTER_ERR
;
4198 nsCOMPtr
<nsIContent
> content
;
4199 rv
= NS_NewXMLProcessingInstruction(getter_AddRefs(content
),
4200 mNodeInfoManager
, aTarget
, aData
);
4201 if (NS_FAILED(rv
)) {
4205 return CallQueryInterface(content
, aReturn
);
4209 nsDocument::CreateAttribute(const nsAString
& aName
,
4210 nsIDOMAttr
** aReturn
)
4213 NS_ENSURE_TRUE(mNodeInfoManager
, NS_ERROR_NOT_INITIALIZED
);
4215 nsresult rv
= nsContentUtils::CheckQName(aName
, PR_FALSE
);
4216 NS_ENSURE_SUCCESS(rv
, rv
);
4219 nsDOMAttribute
* attribute
;
4221 nsCOMPtr
<nsINodeInfo
> nodeInfo
;
4222 rv
= mNodeInfoManager
->GetNodeInfo(aName
, nsnull
, kNameSpaceID_None
,
4223 getter_AddRefs(nodeInfo
));
4224 NS_ENSURE_SUCCESS(rv
, rv
);
4226 attribute
= new nsDOMAttribute(nsnull
, nodeInfo
, value
);
4227 NS_ENSURE_TRUE(attribute
, NS_ERROR_OUT_OF_MEMORY
);
4229 return CallQueryInterface(attribute
, aReturn
);
4233 nsDocument::CreateAttributeNS(const nsAString
& aNamespaceURI
,
4234 const nsAString
& aQualifiedName
,
4235 nsIDOMAttr
**aResult
)
4237 NS_ENSURE_ARG_POINTER(aResult
);
4240 nsCOMPtr
<nsINodeInfo
> nodeInfo
;
4241 nsresult rv
= nsContentUtils::GetNodeInfoFromQName(aNamespaceURI
,
4244 getter_AddRefs(nodeInfo
));
4245 NS_ENSURE_SUCCESS(rv
, rv
);
4248 nsDOMAttribute
* attribute
= new nsDOMAttribute(nsnull
, nodeInfo
, value
);
4249 NS_ENSURE_TRUE(attribute
, NS_ERROR_OUT_OF_MEMORY
);
4251 return CallQueryInterface(attribute
, aResult
);
4255 nsDocument::CreateEntityReference(const nsAString
& aName
,
4256 nsIDOMEntityReference
** aReturn
)
4258 NS_ENSURE_ARG_POINTER(aReturn
);
4265 nsDocument::GetElementsByTagName(const nsAString
& aTagname
,
4266 nsIDOMNodeList
** aReturn
)
4268 nsCOMPtr
<nsIAtom
> nameAtom
= do_GetAtom(aTagname
);
4269 NS_ENSURE_TRUE(nameAtom
, NS_ERROR_OUT_OF_MEMORY
);
4271 nsContentList
*list
= NS_GetContentList(this, nameAtom
, kNameSpaceID_Unknown
).get();
4272 NS_ENSURE_TRUE(list
, NS_ERROR_OUT_OF_MEMORY
);
4274 // transfer ref to aReturn
4280 nsDocument::GetElementsByTagNameNS(const nsAString
& aNamespaceURI
,
4281 const nsAString
& aLocalName
,
4282 nsIDOMNodeList
** aReturn
)
4284 PRInt32 nameSpaceId
= kNameSpaceID_Wildcard
;
4286 if (!aNamespaceURI
.EqualsLiteral("*")) {
4288 nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI
,
4290 NS_ENSURE_SUCCESS(rv
, rv
);
4293 nsCOMPtr
<nsIAtom
> nameAtom
= do_GetAtom(aLocalName
);
4294 NS_ENSURE_TRUE(nameAtom
, NS_ERROR_OUT_OF_MEMORY
);
4296 nsContentList
*list
= NS_GetContentList(this, nameAtom
, nameSpaceId
).get();
4297 NS_ENSURE_TRUE(list
, NS_ERROR_OUT_OF_MEMORY
);
4299 // transfer ref to aReturn
4305 nsDocument::GetAsync(PRBool
*aAsync
)
4307 NS_ERROR("nsDocument::GetAsync() should be overriden by subclass!");
4309 return NS_ERROR_NOT_IMPLEMENTED
;
4313 nsDocument::SetAsync(PRBool aAsync
)
4315 NS_ERROR("nsDocument::SetAsync() should be overriden by subclass!");
4317 return NS_ERROR_NOT_IMPLEMENTED
;
4321 nsDocument::Load(const nsAString
& aUrl
, PRBool
*aReturn
)
4323 NS_ERROR("nsDocument::Load() should be overriden by subclass!");
4325 return NS_ERROR_NOT_IMPLEMENTED
;
4329 nsDocument::EvaluateFIXptr(const nsAString
& aExpression
, nsIDOMRange
**aRange
)
4331 NS_ERROR("nsDocument::EvaluateFIXptr() should be overriden by subclass!");
4333 return NS_ERROR_NOT_IMPLEMENTED
;
4337 nsDocument::EvaluateXPointer(const nsAString
& aExpression
,
4338 nsIXPointerResult
**aResult
)
4340 NS_ERROR("nsDocument::EvaluateXPointer() should be overriden by subclass!");
4342 return NS_ERROR_NOT_IMPLEMENTED
;
4346 nsDocument::GetStyleSheets(nsIDOMStyleSheetList
** aStyleSheets
)
4348 if (!mDOMStyleSheets
) {
4349 mDOMStyleSheets
= new nsDOMStyleSheetList(this);
4350 if (!mDOMStyleSheets
) {
4351 return NS_ERROR_OUT_OF_MEMORY
;
4355 *aStyleSheets
= mDOMStyleSheets
;
4356 NS_ADDREF(*aStyleSheets
);
4362 nsDocument::GetSelectedStyleSheetSet(nsAString
& aSheetSet
)
4364 aSheetSet
.Truncate();
4366 // Look through our sheets, find the selected set title
4367 PRInt32 count
= GetNumberOfStyleSheets();
4369 for (PRInt32 index
= 0; index
< count
; index
++) {
4370 nsIStyleSheet
* sheet
= GetStyleSheetAt(index
);
4371 NS_ASSERTION(sheet
, "Null sheet in sheet list!");
4373 nsCOMPtr
<nsIDOMStyleSheet
> domSheet
= do_QueryInterface(sheet
);
4374 NS_ASSERTION(domSheet
, "Sheet must QI to nsIDOMStyleSheet");
4376 domSheet
->GetDisabled(&disabled
);
4378 // Disabled sheets don't affect the currently selected set
4382 sheet
->GetTitle(title
);
4384 if (aSheetSet
.IsEmpty()) {
4386 } else if (!title
.IsEmpty() && !aSheetSet
.Equals(title
)) {
4387 // Sheets from multiple sets enabled; return null string, per spec.
4388 SetDOMStringToNull(aSheetSet
);
4397 nsDocument::SetSelectedStyleSheetSet(const nsAString
& aSheetSet
)
4399 if (DOMStringIsNull(aSheetSet
)) {
4403 // Must update mLastStyleSheetSet before doing anything else with stylesheets
4405 mLastStyleSheetSet
= aSheetSet
;
4406 EnableStyleSheetsForSetInternal(aSheetSet
, PR_TRUE
);
4411 nsDocument::GetLastStyleSheetSet(nsAString
& aSheetSet
)
4413 aSheetSet
= mLastStyleSheetSet
;
4418 nsDocument::GetPreferredStyleSheetSet(nsAString
& aSheetSet
)
4420 GetHeaderData(nsGkAtoms::headerDefaultStyle
, aSheetSet
);
4425 nsDocument::GetStyleSheetSets(nsIDOMDOMStringList
** aList
)
4427 if (!mStyleSheetSetList
) {
4428 mStyleSheetSetList
= new nsDOMStyleSheetSetList(this);
4429 if (!mStyleSheetSetList
) {
4430 return NS_ERROR_OUT_OF_MEMORY
;
4434 NS_ADDREF(*aList
= mStyleSheetSetList
);
4439 nsDocument::EnableStyleSheetsForSet(const nsAString
& aSheetSet
)
4441 // Per spec, passing in null is a no-op.
4442 if (!DOMStringIsNull(aSheetSet
)) {
4443 // Note: must make sure to not change the CSSLoader's preferred sheet --
4444 // that value should be equal to either our lastStyleSheetSet (if that's
4445 // non-null) or to our preferredStyleSheetSet. And this method doesn't
4446 // change either of those.
4447 EnableStyleSheetsForSetInternal(aSheetSet
, PR_FALSE
);
4454 nsDocument::EnableStyleSheetsForSetInternal(const nsAString
& aSheetSet
,
4455 PRBool aUpdateCSSLoader
)
4457 BeginUpdate(UPDATE_STYLE
);
4458 PRInt32 count
= GetNumberOfStyleSheets();
4460 for (PRInt32 index
= 0; index
< count
; index
++) {
4461 nsIStyleSheet
* sheet
= GetStyleSheetAt(index
);
4462 NS_ASSERTION(sheet
, "Null sheet in sheet list!");
4463 sheet
->GetTitle(title
);
4464 if (!title
.IsEmpty()) {
4465 sheet
->SetEnabled(title
.Equals(aSheetSet
));
4468 if (aUpdateCSSLoader
) {
4469 CSSLoader()->SetPreferredSheet(aSheetSet
);
4471 EndUpdate(UPDATE_STYLE
);
4475 nsDocument::GetCharacterSet(nsAString
& aCharacterSet
)
4477 CopyASCIItoUTF16(GetDocumentCharacterSet(), aCharacterSet
);
4482 nsDocument::ImportNode(nsIDOMNode
* aImportedNode
,
4484 nsIDOMNode
** aResult
)
4486 NS_ENSURE_ARG(aImportedNode
);
4490 nsresult rv
= nsContentUtils::CheckSameOrigin(this, aImportedNode
);
4491 if (NS_FAILED(rv
)) {
4496 aImportedNode
->GetNodeType(&nodeType
);
4498 case nsIDOMNode::ATTRIBUTE_NODE
:
4499 case nsIDOMNode::DOCUMENT_FRAGMENT_NODE
:
4500 case nsIDOMNode::ELEMENT_NODE
:
4501 case nsIDOMNode::PROCESSING_INSTRUCTION_NODE
:
4502 case nsIDOMNode::TEXT_NODE
:
4503 case nsIDOMNode::CDATA_SECTION_NODE
:
4504 case nsIDOMNode::COMMENT_NODE
:
4506 nsCOMPtr
<nsINode
> imported
= do_QueryInterface(aImportedNode
);
4507 NS_ENSURE_TRUE(imported
, NS_ERROR_FAILURE
);
4509 nsCOMPtr
<nsIDOMNode
> newNode
;
4510 nsCOMArray
<nsINode
> nodesWithProperties
;
4511 rv
= nsNodeUtils::Clone(imported
, aDeep
, mNodeInfoManager
,
4512 nodesWithProperties
, getter_AddRefs(newNode
));
4513 NS_ENSURE_SUCCESS(rv
, rv
);
4515 nsIDocument
*ownerDoc
= imported
->GetOwnerDoc();
4517 rv
= nsNodeUtils::CallUserDataHandlers(nodesWithProperties
, ownerDoc
,
4518 nsIDOMUserDataHandler::NODE_IMPORTED
,
4520 NS_ENSURE_SUCCESS(rv
, rv
);
4523 newNode
.swap(*aResult
);
4527 case nsIDOMNode::ENTITY_NODE
:
4528 case nsIDOMNode::ENTITY_REFERENCE_NODE
:
4529 case nsIDOMNode::NOTATION_NODE
:
4531 return NS_ERROR_NOT_IMPLEMENTED
;
4535 NS_WARNING("Don't know how to clone this nodetype for importNode.");
4537 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
4543 nsDocument::AddBinding(nsIDOMElement
* aContent
, const nsAString
& aURI
)
4545 NS_ENSURE_ARG(aContent
);
4547 nsresult rv
= nsContentUtils::CheckSameOrigin(this, aContent
);
4548 if (NS_FAILED(rv
)) {
4552 nsCOMPtr
<nsIContent
> content(do_QueryInterface(aContent
));
4554 nsCOMPtr
<nsIURI
> uri
;
4555 rv
= NS_NewURI(getter_AddRefs(uri
), aURI
);
4556 if (NS_FAILED(rv
)) {
4560 // Figure out the right principal to use
4561 nsCOMPtr
<nsIPrincipal
> subject
;
4562 nsIScriptSecurityManager
* secMan
= nsContentUtils::GetSecurityManager();
4564 rv
= secMan
->GetSubjectPrincipal(getter_AddRefs(subject
));
4565 NS_ENSURE_SUCCESS(rv
, rv
);
4569 // Fall back to our principal. Or should we fall back to the null
4570 // principal? The latter would just mean no binding loads....
4571 subject
= NodePrincipal();
4574 return BindingManager()->AddLayeredBinding(content
, uri
, subject
);
4578 nsDocument::RemoveBinding(nsIDOMElement
* aContent
, const nsAString
& aURI
)
4580 NS_ENSURE_ARG(aContent
);
4582 nsresult rv
= nsContentUtils::CheckSameOrigin(this, aContent
);
4583 if (NS_FAILED(rv
)) {
4587 nsCOMPtr
<nsIURI
> uri
;
4588 rv
= NS_NewURI(getter_AddRefs(uri
), aURI
);
4589 if (NS_FAILED(rv
)) {
4593 nsCOMPtr
<nsIContent
> content(do_QueryInterface(aContent
));
4594 return BindingManager()->RemoveLayeredBinding(content
, uri
);
4598 nsDocument::LoadBindingDocument(const nsAString
& aURI
)
4600 nsCOMPtr
<nsIURI
> uri
;
4601 nsresult rv
= NS_NewURI(getter_AddRefs(uri
), aURI
,
4602 mCharacterSet
.get(),
4603 static_cast<nsIDocument
*>(this)->GetBaseURI());
4604 NS_ENSURE_SUCCESS(rv
, rv
);
4606 // Figure out the right principal to use
4607 nsCOMPtr
<nsIPrincipal
> subject
;
4608 nsIScriptSecurityManager
* secMan
= nsContentUtils::GetSecurityManager();
4610 rv
= secMan
->GetSubjectPrincipal(getter_AddRefs(subject
));
4611 NS_ENSURE_SUCCESS(rv
, rv
);
4615 // Fall back to our principal. Or should we fall back to the null
4616 // principal? The latter would just mean no binding loads....
4617 subject
= NodePrincipal();
4620 BindingManager()->LoadBindingDocument(this, uri
, subject
);
4626 nsDocument::GetBindingParent(nsIDOMNode
* aNode
, nsIDOMElement
** aResult
)
4629 nsCOMPtr
<nsIContent
> content(do_QueryInterface(aNode
));
4631 return NS_ERROR_FAILURE
;
4633 nsCOMPtr
<nsIDOMElement
> elt(do_QueryInterface(content
->GetBindingParent()));
4634 NS_IF_ADDREF(*aResult
= elt
);
4639 GetElementByAttribute(nsIContent
* aContent
, nsIAtom
* aAttrName
,
4640 const nsAString
& aAttrValue
, PRBool aUniversalMatch
,
4641 nsIDOMElement
** aResult
)
4643 if (aUniversalMatch
? aContent
->HasAttr(kNameSpaceID_None
, aAttrName
) :
4644 aContent
->AttrValueIs(kNameSpaceID_None
, aAttrName
,
4645 aAttrValue
, eCaseMatters
)) {
4646 return CallQueryInterface(aContent
, aResult
);
4649 PRUint32 childCount
= aContent
->GetChildCount();
4651 for (PRUint32 i
= 0; i
< childCount
; ++i
) {
4652 nsIContent
*current
= aContent
->GetChildAt(i
);
4654 GetElementByAttribute(current
, aAttrName
, aAttrValue
, aUniversalMatch
,
4665 nsDocument::GetAnonymousElementByAttribute(nsIDOMElement
* aElement
,
4666 const nsAString
& aAttrName
,
4667 const nsAString
& aAttrValue
,
4668 nsIDOMElement
** aResult
)
4672 nsCOMPtr
<nsIDOMNodeList
> nodeList
;
4673 GetAnonymousNodes(aElement
, getter_AddRefs(nodeList
));
4678 nsCOMPtr
<nsIAtom
> attribute
= do_GetAtom(aAttrName
);
4681 nodeList
->GetLength(&length
);
4683 PRBool universalMatch
= aAttrValue
.EqualsLiteral("*");
4685 for (PRUint32 i
= 0; i
< length
; ++i
) {
4686 nsCOMPtr
<nsIDOMNode
> current
;
4687 nodeList
->Item(i
, getter_AddRefs(current
));
4689 nsCOMPtr
<nsIContent
> content(do_QueryInterface(current
));
4691 GetElementByAttribute(content
, attribute
, aAttrValue
, universalMatch
,
4702 nsDocument::GetAnonymousNodes(nsIDOMElement
* aElement
,
4703 nsIDOMNodeList
** aResult
)
4707 nsCOMPtr
<nsIContent
> content(do_QueryInterface(aElement
));
4708 return BindingManager()->GetAnonymousNodesFor(content
, aResult
);
4712 nsDocument::CreateRange(nsIDOMRange
** aReturn
)
4714 nsresult rv
= NS_NewRange(aReturn
);
4716 if (NS_SUCCEEDED(rv
)) {
4717 (*aReturn
)->SetStart(this, 0);
4718 (*aReturn
)->SetEnd(this, 0);
4725 nsDocument::CreateNodeIterator(nsIDOMNode
*aRoot
,
4726 PRUint32 aWhatToShow
,
4727 nsIDOMNodeFilter
*aFilter
,
4728 PRBool aEntityReferenceExpansion
,
4729 nsIDOMNodeIterator
**_retval
)
4734 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
4736 nsresult rv
= nsContentUtils::CheckSameOrigin(this, aRoot
);
4737 NS_ENSURE_SUCCESS(rv
, rv
);
4739 NS_ENSURE_ARG_POINTER(_retval
);
4741 nsCOMPtr
<nsINode
> root
= do_QueryInterface(aRoot
);
4742 NS_ENSURE_TRUE(root
, NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
4744 nsNodeIterator
*iterator
= new nsNodeIterator(root
,
4747 aEntityReferenceExpansion
);
4748 NS_ENSURE_TRUE(iterator
, NS_ERROR_OUT_OF_MEMORY
);
4750 NS_ADDREF(*_retval
= iterator
);
4756 nsDocument::CreateTreeWalker(nsIDOMNode
*aRoot
,
4757 PRUint32 aWhatToShow
,
4758 nsIDOMNodeFilter
*aFilter
,
4759 PRBool aEntityReferenceExpansion
,
4760 nsIDOMTreeWalker
**_retval
)
4765 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
4767 nsresult rv
= nsContentUtils::CheckSameOrigin(this, aRoot
);
4768 NS_ENSURE_SUCCESS(rv
, rv
);
4770 NS_ENSURE_ARG_POINTER(_retval
);
4772 nsCOMPtr
<nsINode
> root
= do_QueryInterface(aRoot
);
4773 NS_ENSURE_TRUE(root
, NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
4775 nsTreeWalker
* walker
= new nsTreeWalker(root
,
4778 aEntityReferenceExpansion
);
4779 NS_ENSURE_TRUE(walker
, NS_ERROR_OUT_OF_MEMORY
);
4781 NS_ADDREF(*_retval
= walker
);
4788 nsDocument::GetDefaultView(nsIDOMAbstractView
** aDefaultView
)
4790 nsPIDOMWindow
* win
= GetWindow();
4792 return CallQueryInterface(win
, aDefaultView
);
4795 *aDefaultView
= nsnull
;
4801 nsDocument::GetLocation(nsIDOMLocation
**_retval
)
4803 NS_ENSURE_ARG_POINTER(_retval
);
4806 nsCOMPtr
<nsIDOMWindowInternal
> w(do_QueryInterface(mScriptGlobalObject
));
4812 return w
->GetLocation(_retval
);
4816 nsDocument::GetHtmlContent()
4818 nsIContent
* rootContent
= GetRootContent();
4819 if (rootContent
&& rootContent
->Tag() == nsGkAtoms::html
&&
4820 rootContent
->IsNodeOfType(nsINode::eHTML
))
4826 nsDocument::GetHtmlChildContent(nsIAtom
* aTag
)
4828 nsIContent
* html
= GetHtmlContent();
4832 // Look for the element with aTag inside html. This needs to run
4833 // forwards to find the first such element.
4834 for (PRUint32 i
= 0; i
< html
->GetChildCount(); ++i
) {
4835 nsIContent
* result
= html
->GetChildAt(i
);
4836 if (result
->Tag() == aTag
&& result
->IsNodeOfType(nsINode::eHTML
))
4843 nsDocument::GetTitleContent(PRUint32 aNodeType
)
4845 // mMayHaveTitleElement will have been set to true if any HTML or SVG
4846 // <title> element has been bound to this document. So if it's false,
4847 // we know there is nothing to do here. This avoids us having to search
4848 // the whole DOM if someone calls document.title on a large document
4850 if (!mMayHaveTitleElement
)
4853 nsRefPtr
<nsContentList
> list
=
4854 NS_GetContentList(this, nsGkAtoms::title
, kNameSpaceID_Unknown
);
4858 for (PRUint32 i
= 0; ; ++i
) {
4859 // Avoid calling list->Length --- by calling Item one at a time,
4860 // we can avoid scanning the whole document to build the list of all
4862 nsIContent
* elem
= list
->Item(i
, PR_FALSE
);
4865 if (elem
->IsNodeOfType(aNodeType
))
4871 nsDocument::GetTitleFromElement(PRUint32 aNodeType
, nsAString
& aTitle
)
4873 nsIContent
* title
= GetTitleContent(aNodeType
);
4876 nsContentUtils::GetNodeTextContent(title
, PR_FALSE
, aTitle
);
4880 nsDocument::GetTitle(nsAString
& aTitle
)
4884 nsIContent
*rootContent
= GetRootContent();
4890 switch (rootContent
->GetNameSpaceID()) {
4892 case kNameSpaceID_XUL
:
4893 rootContent
->GetAttr(kNameSpaceID_None
, nsGkAtoms::title
, tmp
);
4897 case kNameSpaceID_SVG
:
4898 if (rootContent
->Tag() == nsGkAtoms::svg
) {
4899 GetTitleFromElement(nsINode::eSVG
, tmp
);
4901 } // else fall through
4904 GetTitleFromElement(nsINode::eHTML
, tmp
);
4908 tmp
.CompressWhitespace();
4914 nsDocument::SetTitle(const nsAString
& aTitle
)
4916 nsIContent
*rootContent
= GetRootContent();
4920 switch (rootContent
->GetNameSpaceID()) {
4922 case kNameSpaceID_SVG
:
4923 return NS_OK
; // SVG doesn't support setting a title
4926 case kNameSpaceID_XUL
:
4927 return rootContent
->SetAttr(kNameSpaceID_None
, nsGkAtoms::title
,
4932 // Batch updates so that mutation events don't change "the title
4933 // element" under us
4934 mozAutoDocUpdate
updateBatch(this, UPDATE_CONTENT_MODEL
, PR_TRUE
);
4936 nsIContent
* title
= GetTitleContent(nsINode::eHTML
);
4938 nsIContent
*head
= GetHeadContent();
4943 nsCOMPtr
<nsINodeInfo
> titleInfo
;
4944 titleInfo
= mNodeInfoManager
->GetNodeInfo(nsGkAtoms::title
, nsnull
,
4948 title
= NS_NewHTMLTitleElement(titleInfo
);
4953 head
->AppendChildTo(title
, PR_TRUE
);
4956 return nsContentUtils::SetNodeTextContent(title
, aTitle
, PR_FALSE
);
4960 nsDocument::NotifyPossibleTitleChange(PRBool aBoundTitleElement
)
4962 if (aBoundTitleElement
) {
4963 mMayHaveTitleElement
= PR_TRUE
;
4965 if (mPendingTitleChangeEvent
.IsPending())
4968 nsRefPtr
<nsRunnableMethod
<nsDocument
> > event
=
4969 new nsRunnableMethod
<nsDocument
>(this,
4970 &nsDocument::DoNotifyPossibleTitleChange
);
4971 nsresult rv
= NS_DispatchToCurrentThread(event
);
4972 if (NS_SUCCEEDED(rv
)) {
4973 mPendingTitleChangeEvent
= event
;
4978 nsDocument::DoNotifyPossibleTitleChange()
4980 mPendingTitleChangeEvent
.Forget();
4981 mHaveFiredTitleChange
= PR_TRUE
;
4986 nsPresShellIterator
iter(this);
4987 nsCOMPtr
<nsIPresShell
> shell
;
4988 while ((shell
= iter
.GetNextShell())) {
4989 nsCOMPtr
<nsISupports
> container
= shell
->GetPresContext()->GetContainer();
4993 nsCOMPtr
<nsIBaseWindow
> docShellWin
= do_QueryInterface(container
);
4997 docShellWin
->SetTitle(PromiseFlatString(title
).get());
5000 // Fire a DOM event for the title change.
5001 nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument
*>(this),
5002 NS_LITERAL_STRING("DOMTitleChanged"),
5007 nsDocument::GetBoxObjectFor(nsIDOMElement
* aElement
, nsIBoxObject
** aResult
)
5009 nsCOMPtr
<nsIContent
> content(do_QueryInterface(aElement
));
5010 NS_ENSURE_TRUE(content
, NS_ERROR_UNEXPECTED
);
5012 nsIDocument
* doc
= content
->GetOwnerDoc();
5013 NS_ENSURE_TRUE(doc
== this, NS_ERROR_DOM_WRONG_DOCUMENT_ERR
);
5015 if (!mHasWarnedAboutBoxObjects
&& !content
->IsNodeOfType(eXUL
)) {
5016 mHasWarnedAboutBoxObjects
= PR_TRUE
;
5017 nsContentUtils::ReportToConsole(nsContentUtils::eDOM_PROPERTIES
,
5018 "UseOfGetBoxObjectForWarning",
5020 static_cast<nsIDocument
*>(this)->
5022 EmptyString(), 0, 0,
5023 nsIScriptError::warningFlag
,
5029 if (!mBoxObjectTable
) {
5030 mBoxObjectTable
= new nsInterfaceHashtable
<nsVoidPtrHashKey
, nsPIBoxObject
>;
5031 if (mBoxObjectTable
&& !mBoxObjectTable
->Init(12)) {
5032 mBoxObjectTable
= nsnull
;
5035 // Want to use Get(content, aResult); but it's the wrong type
5036 *aResult
= mBoxObjectTable
->GetWeak(content
);
5038 NS_ADDREF(*aResult
);
5043 PRInt32 namespaceID
;
5044 nsCOMPtr
<nsIAtom
> tag
= BindingManager()->ResolveTag(content
, &namespaceID
);
5046 nsCAutoString
contractID("@mozilla.org/layout/xul-boxobject");
5047 if (namespaceID
== kNameSpaceID_XUL
) {
5048 if (tag
== nsGkAtoms::browser
||
5049 tag
== nsGkAtoms::editor
||
5050 tag
== nsGkAtoms::iframe
)
5051 contractID
+= "-container";
5052 else if (tag
== nsGkAtoms::menu
)
5053 contractID
+= "-menu";
5054 else if (tag
== nsGkAtoms::popup
||
5055 tag
== nsGkAtoms::menupopup
||
5056 tag
== nsGkAtoms::panel
||
5057 tag
== nsGkAtoms::tooltip
)
5058 contractID
+= "-popup";
5059 else if (tag
== nsGkAtoms::tree
)
5060 contractID
+= "-tree";
5061 else if (tag
== nsGkAtoms::listbox
)
5062 contractID
+= "-listbox";
5063 else if (tag
== nsGkAtoms::scrollbox
)
5064 contractID
+= "-scrollbox";
5068 nsCOMPtr
<nsPIBoxObject
> boxObject(do_CreateInstance(contractID
.get()));
5070 return NS_ERROR_FAILURE
;
5072 boxObject
->Init(content
);
5074 if (mBoxObjectTable
) {
5075 mBoxObjectTable
->Put(content
, boxObject
.get());
5078 *aResult
= boxObject
;
5079 NS_ADDREF(*aResult
);
5085 nsDocument::ClearBoxObjectFor(nsIContent
* aContent
)
5087 if (mBoxObjectTable
) {
5088 nsPIBoxObject
*boxObject
= mBoxObjectTable
->GetWeak(aContent
);
5091 mBoxObjectTable
->Remove(aContent
);
5097 nsDocument::GetXBLChildNodesFor(nsIContent
* aContent
, nsIDOMNodeList
** aResult
)
5099 return BindingManager()->GetXBLChildNodesFor(aContent
, aResult
);
5103 nsDocument::GetContentListFor(nsIContent
* aContent
, nsIDOMNodeList
** aResult
)
5105 return BindingManager()->GetContentListFor(aContent
, aResult
);
5109 nsDocument::FlushSkinBindings()
5111 BindingManager()->FlushSkinBindings();
5115 nsDocument::InitializeFrameLoader(nsFrameLoader
* aLoader
)
5117 mInitializableFrameLoaders
.RemoveElement(aLoader
);
5118 // Don't even try to initialize.
5119 if (mInDestructor
) {
5120 NS_WARNING("Trying to initialize a frame loader while"
5121 "document is being deleted");
5122 return NS_ERROR_FAILURE
;
5124 if (mUpdateNestLevel
== 0 && !mDelayFrameLoaderInitialization
) {
5125 nsRefPtr
<nsFrameLoader
> loader
= aLoader
;
5126 return loader
->ReallyStartLoading();
5128 mInitializableFrameLoaders
.AppendElement(aLoader
);
5134 nsDocument::FinalizeFrameLoader(nsFrameLoader
* aLoader
)
5136 mInitializableFrameLoaders
.RemoveElement(aLoader
);
5137 if (mInDestructor
) {
5138 return NS_ERROR_FAILURE
;
5140 if (mUpdateNestLevel
== 0) {
5141 nsRefPtr
<nsFrameLoader
> loader
= aLoader
;
5144 mFinalizableFrameLoaders
.AppendElement(aLoader
);
5150 nsDocument::InitializeFinalizeFrameLoaders()
5152 NS_ASSERTION(mUpdateNestLevel
== 0 && !mDelayFrameLoaderInitialization
,
5153 "Wrong time to call InitializeFinalizeFrameLoaders!");
5154 // Don't use a temporary array for mInitializableFrameLoaders, because
5155 // loading a frame may cause some other frameloader to be removed from the
5156 // array. But be careful to keep the loader alive when starting the load!
5157 while (mInitializableFrameLoaders
.Length()) {
5158 nsRefPtr
<nsFrameLoader
> loader
= mInitializableFrameLoaders
[0];
5159 mInitializableFrameLoaders
.RemoveElementAt(0);
5160 NS_ASSERTION(loader
, "null frameloader in the array?");
5161 loader
->ReallyStartLoading();
5164 PRUint32 length
= mFinalizableFrameLoaders
.Length();
5166 nsTArray
<nsRefPtr
<nsFrameLoader
> > loaders
;
5167 mFinalizableFrameLoaders
.SwapElements(loaders
);
5168 for (PRUint32 i
= 0; i
< length
; ++i
) {
5169 loaders
[i
]->Finalize();
5175 nsDocument::TryCancelFrameLoaderInitialization(nsIDocShell
* aShell
)
5177 PRUint32 length
= mInitializableFrameLoaders
.Length();
5178 for (PRUint32 i
= 0; i
< length
; ++i
) {
5179 if (mInitializableFrameLoaders
[i
]->GetExistingDocShell() == aShell
) {
5180 mInitializableFrameLoaders
.RemoveElementAt(i
);
5187 nsDocument::FrameLoaderScheduledToBeFinalized(nsIDocShell
* aShell
)
5190 PRUint32 length
= mFinalizableFrameLoaders
.Length();
5191 for (PRUint32 i
= 0; i
< length
; ++i
) {
5192 if (mFinalizableFrameLoaders
[i
]->GetExistingDocShell() == aShell
) {
5201 nsDocument::RequestExternalResource(nsIURI
* aURI
,
5202 nsINode
* aRequestingNode
,
5203 ExternalResourceLoad
** aPendingLoad
)
5205 NS_PRECONDITION(aURI
, "Must have a URI");
5206 NS_PRECONDITION(aRequestingNode
, "Must have a node");
5207 if (mDisplayDocument
) {
5208 return mDisplayDocument
->RequestExternalResource(aURI
,
5213 return mExternalResourceMap
.RequestResource(aURI
, aRequestingNode
,
5214 this, aPendingLoad
);
5218 nsDocument::EnumerateExternalResources(nsSubDocEnumFunc aCallback
, void* aData
)
5220 mExternalResourceMap
.EnumerateResources(aCallback
, aData
);
5228 static const DirTable dirAttributes
[] = {
5229 {"ltr", IBMBIDI_TEXTDIRECTION_LTR
},
5230 {"rtl", IBMBIDI_TEXTDIRECTION_RTL
},
5235 * Retrieve the "direction" property of the document.
5240 nsDocument::GetDir(nsAString
& aDirection
)
5242 PRUint32 options
= GetBidiOptions();
5243 for (const DirTable
* elt
= dirAttributes
; elt
->mName
; elt
++) {
5244 if (GET_BIDI_OPTION_DIRECTION(options
) == elt
->mValue
) {
5245 CopyASCIItoUTF16(elt
->mName
, aDirection
);
5254 * Set the "direction" property of the document.
5259 nsDocument::SetDir(const nsAString
& aDirection
)
5261 PRUint32 options
= GetBidiOptions();
5263 for (const DirTable
* elt
= dirAttributes
; elt
->mName
; elt
++) {
5264 if (aDirection
== NS_ConvertASCIItoUTF16(elt
->mName
)) {
5265 if (GET_BIDI_OPTION_DIRECTION(options
) != elt
->mValue
) {
5266 SET_BIDI_OPTION_DIRECTION(options
, elt
->mValue
);
5267 nsIPresShell
*shell
= GetPrimaryShell();
5269 nsPresContext
*context
= shell
->GetPresContext();
5270 NS_ENSURE_TRUE(context
, NS_ERROR_UNEXPECTED
);
5271 context
->SetBidi(options
, PR_TRUE
);
5273 // No presentation; just set it on ourselves
5274 SetBidiOptions(options
);
5287 // nsIDOMNode methods
5290 nsDocument::GetNodeName(nsAString
& aNodeName
)
5292 aNodeName
.AssignLiteral("#document");
5298 nsDocument::GetNodeValue(nsAString
& aNodeValue
)
5300 SetDOMStringToNull(aNodeValue
);
5306 nsDocument::SetNodeValue(const nsAString
& aNodeValue
)
5308 // The DOM spec says that when nodeValue is defined to be null "setting it
5309 // has no effect", so we don't throw an exception.
5314 nsDocument::GetNodeType(PRUint16
* aNodeType
)
5316 *aNodeType
= nsIDOMNode::DOCUMENT_NODE
;
5322 nsDocument::GetParentNode(nsIDOMNode
** aParentNode
)
5324 *aParentNode
= nsnull
;
5330 nsDocument::GetChildNodes(nsIDOMNodeList
** aChildNodes
)
5332 nsSlots
*slots
= GetSlots();
5333 NS_ENSURE_TRUE(slots
, NS_ERROR_OUT_OF_MEMORY
);
5335 if (!slots
->mChildNodes
) {
5336 slots
->mChildNodes
= new nsChildContentList(this);
5337 NS_ENSURE_TRUE(slots
->mChildNodes
, NS_ERROR_OUT_OF_MEMORY
);
5338 NS_ADDREF(slots
->mChildNodes
);
5341 NS_ADDREF(*aChildNodes
= slots
->mChildNodes
);
5347 nsDocument::HasChildNodes(PRBool
* aHasChildNodes
)
5349 NS_ENSURE_ARG(aHasChildNodes
);
5351 *aHasChildNodes
= (mChildren
.ChildCount() != 0);
5357 nsDocument::HasAttributes(PRBool
* aHasAttributes
)
5359 NS_ENSURE_ARG(aHasAttributes
);
5361 *aHasAttributes
= PR_FALSE
;
5367 nsDocument::GetFirstChild(nsIDOMNode
** aFirstChild
)
5369 if (mChildren
.ChildCount()) {
5370 return CallQueryInterface(mChildren
.ChildAt(0), aFirstChild
);
5373 *aFirstChild
= nsnull
;
5379 nsDocument::GetLastChild(nsIDOMNode
** aLastChild
)
5381 PRInt32 count
= mChildren
.ChildCount();
5383 return CallQueryInterface(mChildren
.ChildAt(count
-1), aLastChild
);
5386 *aLastChild
= nsnull
;
5392 nsDocument::GetPreviousSibling(nsIDOMNode
** aPreviousSibling
)
5394 *aPreviousSibling
= nsnull
;
5400 nsDocument::GetNextSibling(nsIDOMNode
** aNextSibling
)
5402 *aNextSibling
= nsnull
;
5408 nsDocument::GetAttributes(nsIDOMNamedNodeMap
** aAttributes
)
5410 *aAttributes
= nsnull
;
5416 nsDocument::GetNamespaceURI(nsAString
& aNamespaceURI
)
5418 SetDOMStringToNull(aNamespaceURI
);
5424 nsDocument::GetPrefix(nsAString
& aPrefix
)
5426 SetDOMStringToNull(aPrefix
);
5432 nsDocument::SetPrefix(const nsAString
& aPrefix
)
5434 return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR
;
5438 nsDocument::GetLocalName(nsAString
& aLocalName
)
5440 SetDOMStringToNull(aLocalName
);
5446 nsDocument::InsertBefore(nsIDOMNode
* aNewChild
, nsIDOMNode
* aRefChild
,
5447 nsIDOMNode
** aReturn
)
5449 return nsGenericElement::doReplaceOrInsertBefore(PR_FALSE
, aNewChild
, aRefChild
, nsnull
, this,
5454 nsDocument::ReplaceChild(nsIDOMNode
* aNewChild
, nsIDOMNode
* aOldChild
,
5455 nsIDOMNode
** aReturn
)
5457 return nsGenericElement::doReplaceOrInsertBefore(PR_TRUE
, aNewChild
, aOldChild
, nsnull
, this,
5462 nsDocument::RemoveChild(nsIDOMNode
* aOldChild
, nsIDOMNode
** aReturn
)
5464 return nsGenericElement::doRemoveChild(aOldChild
, nsnull
, this, aReturn
);
5468 nsDocument::AppendChild(nsIDOMNode
* aNewChild
, nsIDOMNode
** aReturn
)
5470 return nsDocument::InsertBefore(aNewChild
, nsnull
, aReturn
);
5474 nsDocument::CloneNode(PRBool aDeep
, nsIDOMNode
** aReturn
)
5476 return nsNodeUtils::CloneNodeImpl(this, aDeep
, aReturn
);
5480 nsDocument::Normalize()
5482 PRInt32 count
= mChildren
.ChildCount();
5483 for (PRInt32 i
= 0; i
< count
; ++i
) {
5484 nsCOMPtr
<nsIDOMNode
> node(do_QueryInterface(mChildren
.ChildAt(i
)));
5495 nsDocument::IsSupported(const nsAString
& aFeature
, const nsAString
& aVersion
,
5498 return nsGenericElement::InternalIsSupported(static_cast<nsIDOMDocument
*>(this),
5499 aFeature
, aVersion
, aReturn
);
5503 nsDocument::GetBaseURI(nsAString
&aURI
)
5506 if (mDocumentBaseURI
) {
5507 mDocumentBaseURI
->GetSpec(spec
);
5510 CopyUTF8toUTF16(spec
, aURI
);
5516 nsDocument::GetTextContent(nsAString
&aTextContent
)
5518 SetDOMStringToNull(aTextContent
);
5524 nsDocument::SetTextContent(const nsAString
& aTextContent
)
5531 nsDocument::CompareDocumentPosition(nsIDOMNode
* aOther
, PRUint16
* aReturn
)
5533 NS_ENSURE_ARG_POINTER(aOther
);
5535 // We could optimize this by getting the other nodes current document
5536 // and comparing with ourself. But then we'd have to deal with the
5537 // current document being null and such so it's easier this way.
5538 // It's hardly a case to optimize anyway.
5540 nsCOMPtr
<nsINode
> other
= do_QueryInterface(aOther
);
5541 NS_ENSURE_TRUE(other
, NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
5543 *aReturn
= nsContentUtils::ComparePosition(other
, this);
5548 nsDocument::IsSameNode(nsIDOMNode
* aOther
, PRBool
* aReturn
)
5550 PRBool sameNode
= PR_FALSE
;
5552 if (this == aOther
) {
5556 *aReturn
= sameNode
;
5562 nsDocument::IsEqualNode(nsIDOMNode
* aOther
, PRBool
* aReturn
)
5564 NS_ENSURE_ARG_POINTER(aOther
);
5566 *aReturn
= PR_FALSE
;
5568 // Node type check by QI. We also reuse this later.
5569 nsCOMPtr
<nsIDocument
> aOtherDoc
= do_QueryInterface(aOther
);
5574 // Child nodes check.
5575 PRUint32 childCount
= GetChildCount();
5576 if (childCount
!= aOtherDoc
->GetChildCount()) {
5580 for (PRUint32 i
= 0; i
< childCount
; i
++) {
5581 nsIContent
* aChild1
= GetChildAt(i
);
5582 nsIContent
* aChild2
= aOtherDoc
->GetChildAt(i
);
5583 if (!nsNode3Tearoff::AreNodesEqual(aChild1
, aChild2
)) {
5588 /* Checks not needed: Prefix, namespace URI, local name, node name,
5589 node value, attributes.
5597 nsDocument::IsDefaultNamespace(const nsAString
& aNamespaceURI
,
5600 nsAutoString defaultNamespace
;
5601 LookupNamespaceURI(EmptyString(), defaultNamespace
);
5602 *aReturn
= aNamespaceURI
.Equals(defaultNamespace
);
5607 nsDocument::GetFeature(const nsAString
& aFeature
,
5608 const nsAString
& aVersion
,
5609 nsISupports
** aReturn
)
5611 return nsGenericElement::InternalGetFeature(static_cast<nsIDOMDocument
*>(this),
5612 aFeature
, aVersion
, aReturn
);
5616 nsDocument::SetUserData(const nsAString
&aKey
,
5618 nsIDOMUserDataHandler
*aHandler
,
5619 nsIVariant
**aResult
)
5621 return nsNodeUtils::SetUserData(this, aKey
, aData
, aHandler
, aResult
);
5625 nsDocument::GetUserData(const nsAString
&aKey
,
5626 nsIVariant
**aResult
)
5628 return nsNodeUtils::GetUserData(this, aKey
, aResult
);
5632 nsDocument::LookupPrefix(const nsAString
& aNamespaceURI
,
5635 nsCOMPtr
<nsIDOM3Node
> root(do_QueryInterface(GetRootContent()));
5637 return root
->LookupPrefix(aNamespaceURI
, aPrefix
);
5640 SetDOMStringToNull(aPrefix
);
5645 nsDocument::LookupNamespaceURI(const nsAString
& aNamespacePrefix
,
5646 nsAString
& aNamespaceURI
)
5648 if (NS_FAILED(nsContentUtils::LookupNamespaceURI(GetRootContent(),
5651 SetDOMStringToNull(aNamespaceURI
);
5657 nsDocument::GetInputEncoding(nsAString
& aInputEncoding
)
5659 if (mHaveInputEncoding
) {
5660 return GetCharacterSet(aInputEncoding
);
5663 SetDOMStringToNull(aInputEncoding
);
5668 nsDocument::GetXmlEncoding(nsAString
& aXmlEncoding
)
5670 if (mXMLDeclarationBits
& XML_DECLARATION_BITS_DECLARATION_EXISTS
&&
5671 mXMLDeclarationBits
& XML_DECLARATION_BITS_ENCODING_EXISTS
) {
5672 // XXX We don't store the encoding given in the xml declaration.
5673 // For now, just output the inputEncoding which we do store.
5674 GetInputEncoding(aXmlEncoding
);
5676 SetDOMStringToNull(aXmlEncoding
);
5683 nsDocument::GetXmlStandalone(PRBool
*aXmlStandalone
)
5686 mXMLDeclarationBits
& XML_DECLARATION_BITS_DECLARATION_EXISTS
&&
5687 mXMLDeclarationBits
& XML_DECLARATION_BITS_STANDALONE_EXISTS
&&
5688 mXMLDeclarationBits
& XML_DECLARATION_BITS_STANDALONE_YES
;
5694 nsDocument::SetXmlStandalone(PRBool aXmlStandalone
)
5696 return NS_ERROR_NOT_IMPLEMENTED
;
5700 nsDocument::GetXmlVersion(nsAString
& aXmlVersion
)
5702 // If there is no declaration, the value is "1.0".
5704 // XXX We only support "1.0", so always output "1.0" until that changes.
5705 aXmlVersion
.AssignLiteral("1.0");
5711 nsDocument::SetXmlVersion(const nsAString
& aXmlVersion
)
5713 return NS_ERROR_NOT_IMPLEMENTED
;
5717 nsDocument::GetStrictErrorChecking(PRBool
*aStrictErrorChecking
)
5719 // This attribute is true by default, and we don't really support it being false.
5720 *aStrictErrorChecking
= PR_TRUE
;
5725 nsDocument::SetStrictErrorChecking(PRBool aStrictErrorChecking
)
5727 // We don't really support non-strict error checking, so just no-op for now.
5732 nsDocument::GetDocumentURI(nsAString
& aDocumentURI
)
5736 mDocumentURI
->GetSpec(uri
);
5737 CopyUTF8toUTF16(uri
, aDocumentURI
);
5739 SetDOMStringToNull(aDocumentURI
);
5746 nsDocument::SetDocumentURI(const nsAString
& aDocumentURI
)
5748 // Not allowing this yet, need to think about security ramifications first.
5749 // We use mDocumentURI to get principals for this document.
5750 return NS_ERROR_NOT_IMPLEMENTED
;
5753 static void BlastSubtreeToPieces(nsINode
*aNode
);
5756 BlastFunc(nsAttrHashKey::KeyType aKey
, nsIDOMNode
*aData
, void* aUserArg
)
5758 nsCOMPtr
<nsIAttribute
> *attr
=
5759 static_cast<nsCOMPtr
<nsIAttribute
>*>(aUserArg
);
5761 *attr
= do_QueryInterface(aData
);
5763 NS_ASSERTION(attr
->get(),
5764 "non-nsIAttribute somehow made it into the hashmap?!");
5766 return PL_DHASH_STOP
;
5770 BlastSubtreeToPieces(nsINode
*aNode
)
5773 if (aNode
->IsNodeOfType(nsINode::eELEMENT
)) {
5774 nsGenericElement
*element
= static_cast<nsGenericElement
*>(aNode
);
5775 const nsDOMAttributeMap
*map
= element
->GetAttributeMap();
5777 nsCOMPtr
<nsIAttribute
> attr
;
5778 while (map
->Enumerate(BlastFunc
, &attr
) > 0) {
5779 BlastSubtreeToPieces(attr
);
5784 element
->UnsetAttr(attr
->NodeInfo()->NamespaceID(),
5785 attr
->NodeInfo()->NameAtom(),
5788 // XXX Should we abort here?
5789 NS_ASSERTION(NS_SUCCEEDED(rv
), "Uhoh, UnsetAttr shouldn't fail!");
5794 count
= aNode
->GetChildCount();
5795 for (i
= 0; i
< count
; ++i
) {
5796 BlastSubtreeToPieces(aNode
->GetChildAt(0));
5800 aNode
->RemoveChildAt(0, PR_FALSE
);
5802 // XXX Should we abort here?
5803 NS_ASSERTION(NS_SUCCEEDED(rv
), "Uhoh, RemoveChildAt shouldn't fail!");
5808 nsDocument::AdoptNode(nsIDOMNode
*aAdoptedNode
, nsIDOMNode
**aResult
)
5810 NS_ENSURE_ARG(aAdoptedNode
);
5814 nsresult rv
= nsContentUtils::CheckSameOrigin(this, aAdoptedNode
);
5815 NS_ENSURE_SUCCESS(rv
, rv
);
5817 nsCOMPtr
<nsINode
> adoptedNode
;
5819 aAdoptedNode
->GetNodeType(&nodeType
);
5821 case nsIDOMNode::ATTRIBUTE_NODE
:
5823 // Remove from ownerElement.
5824 nsCOMPtr
<nsIDOMAttr
> adoptedAttr
= do_QueryInterface(aAdoptedNode
, &rv
);
5825 NS_ENSURE_SUCCESS(rv
, rv
);
5827 nsCOMPtr
<nsIDOMElement
> ownerElement
;
5828 rv
= adoptedAttr
->GetOwnerElement(getter_AddRefs(ownerElement
));
5829 NS_ENSURE_SUCCESS(rv
, rv
);
5832 nsCOMPtr
<nsIDOMAttr
> newAttr
;
5833 rv
= ownerElement
->RemoveAttributeNode(adoptedAttr
,
5834 getter_AddRefs(newAttr
));
5835 NS_ENSURE_SUCCESS(rv
, rv
);
5837 newAttr
.swap(adoptedAttr
);
5840 adoptedNode
= do_QueryInterface(adoptedAttr
, &rv
);
5841 NS_ENSURE_SUCCESS(rv
, rv
);
5844 case nsIDOMNode::DOCUMENT_FRAGMENT_NODE
:
5845 case nsIDOMNode::ELEMENT_NODE
:
5846 case nsIDOMNode::PROCESSING_INSTRUCTION_NODE
:
5847 case nsIDOMNode::TEXT_NODE
:
5848 case nsIDOMNode::CDATA_SECTION_NODE
:
5849 case nsIDOMNode::COMMENT_NODE
:
5851 adoptedNode
= do_QueryInterface(aAdoptedNode
, &rv
);
5852 NS_ENSURE_SUCCESS(rv
, rv
);
5854 // We don't want to adopt an element into its own contentDocument or into
5855 // a descendant contentDocument, so we check if the frameElement of this
5856 // document or any of its parents is the adopted node or one of its
5858 nsIDocument
*doc
= this;
5860 nsPIDOMWindow
*win
= doc
->GetWindow();
5862 nsCOMPtr
<nsINode
> node
=
5863 do_QueryInterface(win
->GetFrameElementInternal());
5865 nsContentUtils::ContentIsDescendantOf(node
, adoptedNode
)) {
5866 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
;
5869 } while ((doc
= doc
->GetParentDocument()));
5871 // Remove from parent.
5872 nsCOMPtr
<nsIDOMNode
> parent
;
5873 aAdoptedNode
->GetParentNode(getter_AddRefs(parent
));
5874 NS_ENSURE_SUCCESS(rv
, rv
);
5877 nsCOMPtr
<nsIDOMNode
> newChild
;
5878 rv
= parent
->RemoveChild(aAdoptedNode
, getter_AddRefs(newChild
));
5879 NS_ENSURE_SUCCESS(rv
, rv
);
5884 case nsIDOMNode::ENTITY_REFERENCE_NODE
:
5886 return NS_ERROR_NOT_IMPLEMENTED
;
5888 case nsIDOMNode::DOCUMENT_NODE
:
5889 case nsIDOMNode::DOCUMENT_TYPE_NODE
:
5890 case nsIDOMNode::ENTITY_NODE
:
5891 case nsIDOMNode::NOTATION_NODE
:
5893 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
5897 NS_WARNING("Don't know how to adopt this nodetype for adoptNode.");
5899 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
5903 nsIDocument
*oldDocument
= adoptedNode
->GetOwnerDoc();
5904 PRBool sameDocument
= oldDocument
== this;
5906 JSContext
*cx
= nsnull
;
5907 JSObject
*oldScope
= nsnull
;
5908 JSObject
*newScope
= nsnull
;
5909 if (!sameDocument
&& oldDocument
) {
5910 rv
= nsContentUtils::GetContextAndScopes(oldDocument
, this, &cx
, &oldScope
,
5912 NS_ENSURE_SUCCESS(rv
, rv
);
5915 nsCOMArray
<nsINode
> nodesWithProperties
;
5916 rv
= nsNodeUtils::Adopt(adoptedNode
, sameDocument
? nsnull
: mNodeInfoManager
,
5917 cx
, oldScope
, newScope
, nodesWithProperties
);
5918 if (NS_FAILED(rv
)) {
5919 // Disconnect all nodes from their parents, since some have the old document
5920 // as their ownerDocument and some have this as their ownerDocument.
5921 BlastSubtreeToPieces(adoptedNode
);
5923 if (!sameDocument
&& oldDocument
) {
5924 PRUint32 i
, count
= nodesWithProperties
.Count();
5925 for (i
= 0; i
< count
; ++i
) {
5926 // Remove all properties.
5927 oldDocument
->PropertyTable()->
5928 DeleteAllPropertiesFor(nodesWithProperties
[i
]);
5935 PRUint32 i
, count
= nodesWithProperties
.Count();
5936 if (!sameDocument
&& oldDocument
) {
5937 nsPropertyTable
*oldTable
= oldDocument
->PropertyTable();
5938 nsPropertyTable
*newTable
= PropertyTable();
5939 for (i
= 0; i
< count
; ++i
) {
5940 rv
= oldTable
->TransferOrDeleteAllPropertiesFor(nodesWithProperties
[i
],
5942 if (NS_FAILED(rv
)) {
5943 while (++i
< count
) {
5944 oldTable
->DeleteAllPropertiesFor(nodesWithProperties
[i
]);
5947 // Disconnect all nodes from their parents.
5948 BlastSubtreeToPieces(adoptedNode
);
5955 rv
= nsNodeUtils::CallUserDataHandlers(nodesWithProperties
, this,
5956 nsIDOMUserDataHandler::NODE_ADOPTED
,
5958 NS_ENSURE_SUCCESS(rv
, rv
);
5960 return CallQueryInterface(adoptedNode
, aResult
);
5964 nsDocument::GetDomConfig(nsIDOMDOMConfiguration
**aConfig
)
5966 return NS_ERROR_NOT_IMPLEMENTED
;
5970 nsDocument::NormalizeDocument()
5972 // We don't support DOMConfigurations yet, so this just
5973 // does a straight shot of normalization.
5978 nsDocument::RenameNode(nsIDOMNode
*aNode
,
5979 const nsAString
& namespaceURI
,
5980 const nsAString
& qualifiedName
,
5981 nsIDOMNode
**aReturn
)
5983 return NS_ERROR_NOT_IMPLEMENTED
;
5988 nsDocument::GetOwnerDocument(nsIDOMDocument
** aOwnerDocument
)
5990 *aOwnerDocument
= nsnull
;
5996 nsDocument::GetListenerManager(PRBool aCreateIfNotFound
,
5997 nsIEventListenerManager
** aInstancePtrResult
)
5999 if (mListenerManager
) {
6000 *aInstancePtrResult
= mListenerManager
;
6001 NS_ADDREF(*aInstancePtrResult
);
6005 if (!aCreateIfNotFound
) {
6006 *aInstancePtrResult
= nsnull
;
6010 nsresult rv
= NS_NewEventListenerManager(getter_AddRefs(mListenerManager
));
6011 NS_ENSURE_SUCCESS(rv
, rv
);
6013 mListenerManager
->SetListenerTarget(static_cast<nsIDocument
*>(this));
6015 *aInstancePtrResult
= mListenerManager
;
6016 NS_ADDREF(*aInstancePtrResult
);
6022 nsDocument::GetSystemEventGroup(nsIDOMEventGroup
**aGroup
)
6024 nsCOMPtr
<nsIEventListenerManager
> manager
;
6025 if (NS_SUCCEEDED(GetListenerManager(PR_TRUE
, getter_AddRefs(manager
))) &&
6027 return manager
->GetSystemEventGroupLM(aGroup
);
6030 return NS_ERROR_FAILURE
;
6034 nsDocument::PreHandleEvent(nsEventChainPreVisitor
& aVisitor
)
6036 aVisitor
.mCanHandle
= PR_TRUE
;
6037 // FIXME! This is a hack to make middle mouse paste working also in Editor.
6039 aVisitor
.mForceContentDispatch
= PR_TRUE
;
6041 // Load events must not propagate to |window| object, see bug 335251.
6042 if (aVisitor
.mEvent
->message
!= NS_LOAD
) {
6043 nsCOMPtr
<nsPIDOMEventTarget
> parentTarget
= do_QueryInterface(GetWindow());
6044 aVisitor
.mParentTarget
= parentTarget
;
6050 nsDocument::PostHandleEvent(nsEventChainPostVisitor
& aVisitor
)
6056 nsDocument::DispatchDOMEvent(nsEvent
* aEvent
,
6057 nsIDOMEvent
* aDOMEvent
,
6058 nsPresContext
* aPresContext
,
6059 nsEventStatus
* aEventStatus
)
6061 return nsEventDispatcher::DispatchDOMEvent(static_cast<nsINode
*>(this),
6063 aPresContext
, aEventStatus
);
6067 nsDocument::AddEventListenerByIID(nsIDOMEventListener
*aListener
,
6070 nsCOMPtr
<nsIEventListenerManager
> manager
;
6072 GetListenerManager(PR_TRUE
, getter_AddRefs(manager
));
6074 manager
->AddEventListenerByIID(aListener
, aIID
, NS_EVENT_FLAG_BUBBLE
);
6078 return NS_ERROR_FAILURE
;
6082 nsDocument::RemoveEventListenerByIID(nsIDOMEventListener
*aListener
,
6085 if (!mListenerManager
) {
6086 return NS_ERROR_FAILURE
;
6089 mListenerManager
->RemoveEventListenerByIID(aListener
, aIID
,
6090 NS_EVENT_FLAG_BUBBLE
);
6095 nsDocument::AddEventListener(const nsAString
& aType
,
6096 nsIDOMEventListener
* aListener
,
6099 return AddEventListener(aType
, aListener
, aUseCapture
,
6100 !nsContentUtils::IsChromeDoc(this));
6104 nsDocument::RemoveEventListener(const nsAString
& aType
,
6105 nsIDOMEventListener
* aListener
,
6108 return RemoveGroupedEventListener(aType
, aListener
, aUseCapture
, nsnull
);
6112 nsDocument::DispatchEvent(nsIDOMEvent
* aEvent
, PRBool
*_retval
)
6114 // Obtain a presentation context
6115 nsIPresShell
*shell
= GetPrimaryShell();
6116 nsCOMPtr
<nsPresContext
> context
;
6118 context
= shell
->GetPresContext();
6121 nsEventStatus status
= nsEventStatus_eIgnore
;
6123 nsEventDispatcher::DispatchDOMEvent(static_cast<nsINode
*>(this),
6124 nsnull
, aEvent
, context
, &status
);
6126 *_retval
= (status
!= nsEventStatus_eConsumeNoDefault
);
6131 nsDocument::AddGroupedEventListener(const nsAString
& aType
,
6132 nsIDOMEventListener
*aListener
,
6134 nsIDOMEventGroup
*aEvtGrp
)
6136 nsCOMPtr
<nsIEventListenerManager
> manager
;
6138 nsresult rv
= GetListenerManager(PR_TRUE
, getter_AddRefs(manager
));
6139 if (NS_SUCCEEDED(rv
) && manager
) {
6140 PRInt32 flags
= aUseCapture
? NS_EVENT_FLAG_CAPTURE
: NS_EVENT_FLAG_BUBBLE
;
6142 manager
->AddEventListenerByType(aListener
, aType
, flags
, aEvtGrp
);
6150 nsDocument::RemoveGroupedEventListener(const nsAString
& aType
,
6151 nsIDOMEventListener
*aListener
,
6153 nsIDOMEventGroup
*aEvtGrp
)
6155 if (!mListenerManager
) {
6156 return NS_ERROR_FAILURE
;
6159 PRInt32 flags
= aUseCapture
? NS_EVENT_FLAG_CAPTURE
: NS_EVENT_FLAG_BUBBLE
;
6161 mListenerManager
->RemoveEventListenerByType(aListener
, aType
, flags
,
6167 nsDocument::CanTrigger(const nsAString
& type
, PRBool
*_retval
)
6169 return NS_ERROR_NOT_IMPLEMENTED
;
6173 nsDocument::IsRegisteredHere(const nsAString
& type
, PRBool
*_retval
)
6175 return NS_ERROR_NOT_IMPLEMENTED
;
6179 nsDocument::AddEventListener(const nsAString
& aType
,
6180 nsIDOMEventListener
*aListener
,
6181 PRBool aUseCapture
, PRBool aWantsUntrusted
)
6183 nsCOMPtr
<nsIEventListenerManager
> manager
;
6184 nsresult rv
= GetListenerManager(PR_TRUE
, getter_AddRefs(manager
));
6185 NS_ENSURE_SUCCESS(rv
, rv
);
6187 PRInt32 flags
= aUseCapture
? NS_EVENT_FLAG_CAPTURE
: NS_EVENT_FLAG_BUBBLE
;
6189 if (aWantsUntrusted
) {
6190 flags
|= NS_PRIV_EVENT_UNTRUSTED_PERMITTED
;
6193 return manager
->AddEventListenerByType(aListener
, aType
, flags
, nsnull
);
6197 nsDocument::CreateEvent(const nsAString
& aEventType
, nsIDOMEvent
** aReturn
)
6199 NS_ENSURE_ARG_POINTER(aReturn
);
6202 // Obtain a presentation shell
6204 nsIPresShell
*shell
= GetPrimaryShell();
6206 nsPresContext
*presContext
= nsnull
;
6209 // Retrieve the context
6210 presContext
= shell
->GetPresContext();
6213 // Create event even without presContext.
6214 return nsEventDispatcher::CreateEvent(presContext
, nsnull
,
6215 aEventType
, aReturn
);
6219 nsDocument::CreateEventGroup(nsIDOMEventGroup
**aInstancePtrResult
)
6222 nsCOMPtr
<nsIDOMEventGroup
> group(do_CreateInstance(kDOMEventGroupCID
, &rv
));
6223 NS_ENSURE_SUCCESS(rv
, rv
);
6225 *aInstancePtrResult
= group
;
6226 NS_ADDREF(*aInstancePtrResult
);
6232 nsDocument::FlushPendingNotifications(mozFlushType aType
)
6234 nsCOMPtr
<nsIContentSink
> sink
;
6236 sink
= mParser
->GetContentSink();
6238 sink
= do_QueryReferent(mWeakSink
);
6240 // Determine if it is safe to flush the sink notifications
6241 // by determining if it safe to flush all the presshells.
6242 if (sink
&& (aType
== Flush_Content
|| IsSafeToFlush())) {
6243 sink
->FlushPendingNotifications(aType
);
6246 // Should we be flushing pending binding constructors in here?
6248 if (aType
<= Flush_ContentAndNotify
) {
6249 // Nothing to do here
6253 // If we have a parent we must flush the parent too to ensure that our
6254 // container is reflown if its size was changed. But if it's not safe to
6255 // flush ourselves, then don't flush the parent, since that can cause things
6256 // like resizes of our frame's widget, which we can't handle while flushing
6258 // Since media queries mean that a size change of our container can
6259 // affect style, we need to promote a style flush on ourself to a
6260 // layout flush on our parent, since we need our container to be the
6261 // correct size to determine the correct style.
6262 if (mParentDocument
&& IsSafeToFlush()) {
6263 mozFlushType parentType
= aType
;
6264 if (aType
== Flush_Style
)
6265 parentType
= Flush_Layout
;
6266 mParentDocument
->FlushPendingNotifications(parentType
);
6269 nsPresShellIterator
iter(this);
6270 nsCOMPtr
<nsIPresShell
> shell
;
6271 while ((shell
= iter
.GetNextShell())) {
6272 shell
->FlushPendingNotifications(aType
);
6276 nsIScriptEventManager
*
6277 nsDocument::GetScriptEventManager()
6279 if (!mScriptEventManager
) {
6280 mScriptEventManager
= new nsScriptEventManager(this);
6281 // automatically AddRefs
6284 return mScriptEventManager
;
6288 nsDocument::SetXMLDeclaration(const PRUnichar
*aVersion
,
6289 const PRUnichar
*aEncoding
,
6290 const PRInt32 aStandalone
)
6292 if (!aVersion
|| *aVersion
== '\0') {
6293 mXMLDeclarationBits
= 0;
6297 mXMLDeclarationBits
= XML_DECLARATION_BITS_DECLARATION_EXISTS
;
6299 if (aEncoding
&& *aEncoding
!= '\0') {
6300 mXMLDeclarationBits
|= XML_DECLARATION_BITS_ENCODING_EXISTS
;
6303 if (aStandalone
== 1) {
6304 mXMLDeclarationBits
|= XML_DECLARATION_BITS_STANDALONE_EXISTS
|
6305 XML_DECLARATION_BITS_STANDALONE_YES
;
6307 else if (aStandalone
== 0) {
6308 mXMLDeclarationBits
|= XML_DECLARATION_BITS_STANDALONE_EXISTS
;
6313 nsDocument::GetXMLDeclaration(nsAString
& aVersion
, nsAString
& aEncoding
,
6314 nsAString
& aStandalone
)
6316 aVersion
.Truncate();
6317 aEncoding
.Truncate();
6318 aStandalone
.Truncate();
6320 if (!(mXMLDeclarationBits
& XML_DECLARATION_BITS_DECLARATION_EXISTS
)) {
6324 // always until we start supporting 1.1 etc.
6325 aVersion
.AssignLiteral("1.0");
6327 if (mXMLDeclarationBits
& XML_DECLARATION_BITS_ENCODING_EXISTS
) {
6328 // This is what we have stored, not necessarily what was written
6330 GetCharacterSet(aEncoding
);
6333 if (mXMLDeclarationBits
& XML_DECLARATION_BITS_STANDALONE_EXISTS
) {
6334 if (mXMLDeclarationBits
& XML_DECLARATION_BITS_STANDALONE_YES
) {
6335 aStandalone
.AssignLiteral("yes");
6337 aStandalone
.AssignLiteral("no");
6343 nsDocument::IsScriptEnabled()
6345 nsCOMPtr
<nsIScriptSecurityManager
> sm(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
));
6346 NS_ENSURE_TRUE(sm
, PR_FALSE
);
6348 nsIScriptGlobalObject
* globalObject
= GetScriptGlobalObject();
6349 NS_ENSURE_TRUE(globalObject
, PR_FALSE
);
6351 nsIScriptContext
*scriptContext
= globalObject
->GetContext();
6352 NS_ENSURE_TRUE(scriptContext
, PR_FALSE
);
6354 JSContext
* cx
= (JSContext
*) scriptContext
->GetNativeContext();
6355 NS_ENSURE_TRUE(cx
, PR_FALSE
);
6358 nsresult rv
= sm
->CanExecuteScripts(cx
, NodePrincipal(), &enabled
);
6359 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
6364 nsDocument::GetRadioGroup(const nsAString
& aName
,
6365 nsRadioGroupStruct
**aRadioGroup
)
6367 nsAutoString
tmKey(aName
);
6368 if(!IsCaseSensitive())
6369 ToLowerCase(tmKey
); //should case-insensitive.
6370 if (mRadioGroups
.Get(tmKey
, aRadioGroup
))
6373 nsAutoPtr
<nsRadioGroupStruct
> radioGroup(new nsRadioGroupStruct());
6374 NS_ENSURE_TRUE(radioGroup
, NS_ERROR_OUT_OF_MEMORY
);
6375 NS_ENSURE_TRUE(mRadioGroups
.Put(tmKey
, radioGroup
), NS_ERROR_OUT_OF_MEMORY
);
6377 *aRadioGroup
= radioGroup
;
6378 radioGroup
.forget();
6384 nsDocument::SetCurrentRadioButton(const nsAString
& aName
,
6385 nsIDOMHTMLInputElement
* aRadio
)
6387 nsRadioGroupStruct
* radioGroup
= nsnull
;
6388 GetRadioGroup(aName
, &radioGroup
);
6390 radioGroup
->mSelectedRadioButton
= aRadio
;
6397 nsDocument::GetCurrentRadioButton(const nsAString
& aName
,
6398 nsIDOMHTMLInputElement
** aRadio
)
6400 nsRadioGroupStruct
* radioGroup
= nsnull
;
6401 GetRadioGroup(aName
, &radioGroup
);
6403 *aRadio
= radioGroup
->mSelectedRadioButton
;
6404 NS_IF_ADDREF(*aRadio
);
6411 nsDocument::GetPositionInGroup(nsIDOMHTMLInputElement
*aRadio
,
6412 PRInt32
*aPositionIndex
,
6413 PRInt32
*aItemsInGroup
)
6415 *aPositionIndex
= 0;
6418 aRadio
->GetName(name
);
6419 if (name
.IsEmpty()) {
6423 nsRadioGroupStruct
* radioGroup
= nsnull
;
6424 nsresult rv
= GetRadioGroup(name
, &radioGroup
);
6425 NS_ENSURE_SUCCESS(rv
, rv
);
6427 nsCOMPtr
<nsIFormControl
> radioControl(do_QueryInterface(aRadio
));
6428 NS_ASSERTION(radioControl
, "Radio button should implement nsIFormControl");
6429 *aPositionIndex
= radioGroup
->mRadioButtons
.IndexOf(radioControl
);
6430 NS_ASSERTION(*aPositionIndex
>= 0, "Radio button not found in its own group");
6431 *aItemsInGroup
= radioGroup
->mRadioButtons
.Count();
6437 nsDocument::GetNextRadioButton(const nsAString
& aName
,
6438 const PRBool aPrevious
,
6439 nsIDOMHTMLInputElement
* aFocusedRadio
,
6440 nsIDOMHTMLInputElement
** aRadioOut
)
6442 // XXX Can we combine the HTML radio button method impls of
6443 // nsDocument and nsHTMLFormControl?
6444 // XXX Why is HTML radio button stuff in nsDocument, as
6445 // opposed to nsHTMLDocument?
6446 *aRadioOut
= nsnull
;
6448 nsRadioGroupStruct
* radioGroup
= nsnull
;
6449 GetRadioGroup(aName
, &radioGroup
);
6451 return NS_ERROR_FAILURE
;
6454 // Return the radio button relative to the focused radio button.
6455 // If no radio is focused, get the radio relative to the selected one.
6456 nsCOMPtr
<nsIDOMHTMLInputElement
> currentRadio
;
6457 if (aFocusedRadio
) {
6458 currentRadio
= aFocusedRadio
;
6461 currentRadio
= radioGroup
->mSelectedRadioButton
;
6462 if (!currentRadio
) {
6463 return NS_ERROR_FAILURE
;
6466 nsCOMPtr
<nsIFormControl
> radioControl(do_QueryInterface(currentRadio
));
6467 PRInt32 index
= radioGroup
->mRadioButtons
.IndexOf(radioControl
);
6469 return NS_ERROR_FAILURE
;
6472 PRInt32 numRadios
= radioGroup
->mRadioButtons
.Count();
6474 nsCOMPtr
<nsIDOMHTMLInputElement
> radio
;
6478 index
= numRadios
-1;
6481 else if (++index
>= numRadios
) {
6484 radio
= do_QueryInterface(radioGroup
->mRadioButtons
[index
]);
6485 NS_ASSERTION(radio
, "mRadioButtons holding a non-radio button");
6486 radio
->GetDisabled(&disabled
);
6487 } while (disabled
&& radio
!= currentRadio
);
6489 NS_IF_ADDREF(*aRadioOut
= radio
);
6494 nsDocument::AddToRadioGroup(const nsAString
& aName
,
6495 nsIFormControl
* aRadio
)
6497 nsRadioGroupStruct
* radioGroup
= nsnull
;
6498 GetRadioGroup(aName
, &radioGroup
);
6500 radioGroup
->mRadioButtons
.AppendObject(aRadio
);
6507 nsDocument::RemoveFromRadioGroup(const nsAString
& aName
,
6508 nsIFormControl
* aRadio
)
6510 nsRadioGroupStruct
* radioGroup
= nsnull
;
6511 GetRadioGroup(aName
, &radioGroup
);
6513 radioGroup
->mRadioButtons
.RemoveObject(aRadio
);
6520 nsDocument::WalkRadioGroup(const nsAString
& aName
,
6521 nsIRadioVisitor
* aVisitor
,
6522 PRBool aFlushContent
)
6524 nsRadioGroupStruct
* radioGroup
= nsnull
;
6525 GetRadioGroup(aName
, &radioGroup
);
6530 PRBool stop
= PR_FALSE
;
6531 for (int i
= 0; i
< radioGroup
->mRadioButtons
.Count(); i
++) {
6532 aVisitor
->Visit(radioGroup
->mRadioButtons
[i
], &stop
);
6542 nsDocument::RetrieveRelevantHeaders(nsIChannel
*aChannel
)
6544 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(aChannel
);
6545 PRTime modDate
= LL_ZERO
;
6550 rv
= httpChannel
->GetResponseHeader(NS_LITERAL_CSTRING("last-modified"),
6553 if (NS_SUCCEEDED(rv
)) {
6555 PRStatus st
= PR_ParseTimeString(tmp
.get(), PR_TRUE
, &time
);
6556 if (st
== PR_SUCCESS
) {
6561 // The misspelled key 'referer' is as per the HTTP spec
6562 rv
= httpChannel
->GetRequestHeader(NS_LITERAL_CSTRING("referer"),
6564 if (NS_FAILED(rv
)) {
6565 mReferrer
.Truncate();
6568 static const char *const headers
[] = {
6570 "content-style-type",
6572 "content-disposition",
6574 "x-dns-prefetch-control",
6575 // add more http headers if you need
6576 // XXXbz don't add content-location support without reading bug
6577 // 238654 and its dependencies/dups first.
6581 nsCAutoString headerVal
;
6582 const char *const *name
= headers
;
6585 httpChannel
->GetResponseHeader(nsDependentCString(*name
), headerVal
);
6586 if (NS_SUCCEEDED(rv
) && !headerVal
.IsEmpty()) {
6587 nsCOMPtr
<nsIAtom
> key
= do_GetAtom(*name
);
6588 SetHeaderData(key
, NS_ConvertASCIItoUTF16(headerVal
));
6593 nsCOMPtr
<nsIFileChannel
> fileChannel
= do_QueryInterface(aChannel
);
6595 nsCOMPtr
<nsIFile
> file
;
6596 fileChannel
->GetFile(getter_AddRefs(file
));
6599 rv
= file
->GetLastModifiedTime(&msecs
);
6601 if (NS_SUCCEEDED(rv
)) {
6602 PRInt64 intermediateValue
;
6603 LL_I2L(intermediateValue
, PR_USEC_PER_MSEC
);
6604 LL_MUL(modDate
, msecs
, intermediateValue
);
6608 nsCOMPtr
<nsIMultiPartChannel
> partChannel
= do_QueryInterface(aChannel
);
6610 nsCAutoString contentDisp
;
6611 rv
= partChannel
->GetContentDisposition(contentDisp
);
6612 if (NS_SUCCEEDED(rv
) && !contentDisp
.IsEmpty()) {
6613 SetHeaderData(nsGkAtoms::headerContentDisposition
,
6614 NS_ConvertASCIItoUTF16(contentDisp
));
6620 if (LL_IS_ZERO(modDate
)) {
6621 // We got nothing from our attempt to ask nsIFileChannel and
6622 // nsIHttpChannel for the last modified time. Return the current
6627 mLastModified
.Truncate();
6628 if (LL_NE(modDate
, LL_ZERO
)) {
6629 PRExplodedTime prtime
;
6630 PR_ExplodeTime(modDate
, PR_LocalTimeParameters
, &prtime
);
6631 // "MM/DD/YYYY hh:mm:ss"
6632 char formatedTime
[24];
6633 if (PR_snprintf(formatedTime
, sizeof(formatedTime
),
6634 "%02ld/%02ld/%04hd %02ld:%02ld:%02ld",
6635 prtime
.tm_month
+ 1, prtime
.tm_mday
, prtime
.tm_year
,
6636 prtime
.tm_hour
, prtime
.tm_min
, prtime
.tm_sec
)) {
6637 CopyASCIItoUTF16(nsDependentCString(formatedTime
), mLastModified
);
6643 nsDocument::CreateElem(nsIAtom
*aName
, nsIAtom
*aPrefix
, PRInt32 aNamespaceID
,
6644 PRBool aDocumentDefaultType
, nsIContent
**aResult
)
6649 aPrefix
->ToString(qName
);
6653 aName
->GetUTF8String(&name
);
6654 AppendUTF8toUTF16(name
, qName
);
6656 // Note: "a:b:c" is a valid name in non-namespaces XML, and
6657 // nsDocument::CreateElement can call us with such a name and no prefix,
6658 // which would cause an error if we just used PR_TRUE here.
6659 PRBool nsAware
= aPrefix
!= nsnull
|| aNamespaceID
!= GetDefaultNamespaceID();
6660 NS_ASSERTION(NS_SUCCEEDED(nsContentUtils::CheckQName(qName
, nsAware
)),
6661 "Don't pass invalid prefixes to nsDocument::CreateElem, "
6667 PRInt32 elementType
= aDocumentDefaultType
? mDefaultElementType
:
6670 nsCOMPtr
<nsINodeInfo
> nodeInfo
;
6671 nodeInfo
= mNodeInfoManager
->GetNodeInfo(aName
, aPrefix
, aNamespaceID
);
6672 NS_ENSURE_TRUE(nodeInfo
, NS_ERROR_OUT_OF_MEMORY
);
6674 return NS_NewElement(aResult
, elementType
, nodeInfo
, PR_FALSE
);
6678 nsDocument::IsSafeToFlush() const
6680 PRBool isSafeToFlush
= PR_TRUE
;
6681 nsPresShellIterator
iter(const_cast<nsIDocument
*>
6682 (static_cast<const nsIDocument
*>(this)));
6683 nsCOMPtr
<nsIPresShell
> shell
;
6684 while ((shell
= iter
.GetNextShell()) && isSafeToFlush
) {
6685 shell
->IsSafeToFlush(isSafeToFlush
);
6687 return isSafeToFlush
;
6691 nsDocument::Sanitize()
6693 // Sanitize the document by resetting all password fields and any form
6694 // fields with autocomplete=off to their default values. We do this now,
6695 // instead of when the presentation is restored, to offer some protection
6696 // in case there is ever an exploit that allows a cached document to be
6697 // accessed from a different document.
6699 // First locate all input elements, regardless of whether they are
6700 // in a form, and reset the password and autocomplete=off elements.
6702 nsCOMPtr
<nsIDOMNodeList
> nodes
;
6703 nsresult rv
= GetElementsByTagName(NS_LITERAL_STRING("input"),
6704 getter_AddRefs(nodes
));
6705 NS_ENSURE_SUCCESS(rv
, rv
);
6707 PRUint32 length
= 0;
6709 nodes
->GetLength(&length
);
6711 nsCOMPtr
<nsIDOMNode
> item
;
6715 for (i
= 0; i
< length
; ++i
) {
6716 nodes
->Item(i
, getter_AddRefs(item
));
6717 NS_ASSERTION(item
, "null item in node list!");
6719 nsCOMPtr
<nsIDOMHTMLInputElement
> input
= do_QueryInterface(item
);
6723 PRBool resetValue
= PR_FALSE
;
6725 input
->GetAttribute(NS_LITERAL_STRING("autocomplete"), value
);
6726 if (value
.LowerCaseEqualsLiteral("off")) {
6727 resetValue
= PR_TRUE
;
6729 input
->GetType(value
);
6730 if (value
.LowerCaseEqualsLiteral("password"))
6731 resetValue
= PR_TRUE
;
6735 nsCOMPtr
<nsIFormControl
> fc
= do_QueryInterface(input
);
6740 // Now locate all _form_ elements that have autocomplete=off and reset them
6741 rv
= GetElementsByTagName(NS_LITERAL_STRING("form"), getter_AddRefs(nodes
));
6742 NS_ENSURE_SUCCESS(rv
, rv
);
6746 nodes
->GetLength(&length
);
6748 for (i
= 0; i
< length
; ++i
) {
6749 nodes
->Item(i
, getter_AddRefs(item
));
6750 NS_ASSERTION(item
, "null item in nodelist");
6752 nsCOMPtr
<nsIDOMHTMLFormElement
> form
= do_QueryInterface(item
);
6756 form
->GetAttribute(NS_LITERAL_STRING("autocomplete"), value
);
6757 if (value
.LowerCaseEqualsLiteral("off"))
6764 struct SubDocEnumArgs
6766 nsIDocument::nsSubDocEnumFunc callback
;
6770 static PLDHashOperator
6771 SubDocHashEnum(PLDHashTable
*table
, PLDHashEntryHdr
*hdr
,
6772 PRUint32 number
, void *arg
)
6774 SubDocMapEntry
*entry
= static_cast<SubDocMapEntry
*>(hdr
);
6775 SubDocEnumArgs
*args
= static_cast<SubDocEnumArgs
*>(arg
);
6777 nsIDocument
*subdoc
= entry
->mSubDocument
;
6778 PRBool next
= subdoc
? args
->callback(subdoc
, args
->data
) : PR_TRUE
;
6780 return next
? PL_DHASH_NEXT
: PL_DHASH_STOP
;
6784 nsDocument::EnumerateSubDocuments(nsSubDocEnumFunc aCallback
, void *aData
)
6786 if (mSubDocuments
) {
6787 SubDocEnumArgs args
= { aCallback
, aData
};
6788 PL_DHashTableEnumerate(mSubDocuments
, SubDocHashEnum
, &args
);
6792 static PLDHashOperator
6793 CanCacheSubDocument(PLDHashTable
*table
, PLDHashEntryHdr
*hdr
,
6794 PRUint32 number
, void *arg
)
6796 SubDocMapEntry
*entry
= static_cast<SubDocMapEntry
*>(hdr
);
6797 PRBool
*canCacheArg
= static_cast<PRBool
*>(arg
);
6799 nsIDocument
*subdoc
= entry
->mSubDocument
;
6801 // The aIgnoreRequest we were passed is only for us, so don't pass it on.
6802 PRBool canCache
= subdoc
? subdoc
->CanSavePresentation(nsnull
) : PR_FALSE
;
6804 *canCacheArg
= PR_FALSE
;
6805 return PL_DHASH_STOP
;
6808 return PL_DHASH_NEXT
;
6812 #define DEBUG_PAGE_CACHE
6816 nsDocument::CanSavePresentation(nsIRequest
*aNewRequest
)
6818 // Check our event listener manager for unload/beforeunload listeners.
6819 nsCOMPtr
<nsPIDOMEventTarget
> piTarget
= do_QueryInterface(mScriptGlobalObject
);
6821 nsCOMPtr
<nsIEventListenerManager
> manager
;
6822 piTarget
->GetListenerManager(PR_FALSE
, getter_AddRefs(manager
));
6823 if (manager
&& manager
->HasUnloadListeners()) {
6828 nsCOMPtr
<nsILoadGroup
> loadGroup
= GetDocumentLoadGroup();
6830 nsCOMPtr
<nsISimpleEnumerator
> requests
;
6831 loadGroup
->GetRequests(getter_AddRefs(requests
));
6833 PRBool hasMore
= PR_FALSE
;
6835 while (NS_SUCCEEDED(requests
->HasMoreElements(&hasMore
)) && hasMore
) {
6836 nsCOMPtr
<nsISupports
> elem
;
6837 requests
->GetNext(getter_AddRefs(elem
));
6839 nsCOMPtr
<nsIRequest
> request
= do_QueryInterface(elem
);
6840 if (request
&& request
!= aNewRequest
) {
6841 #ifdef DEBUG_PAGE_CACHE
6842 nsCAutoString requestName
, docSpec
;
6843 request
->GetName(requestName
);
6845 mDocumentURI
->GetSpec(docSpec
);
6847 printf("document %s has request %s\n",
6848 docSpec
.get(), requestName
.get());
6855 PRBool canCache
= PR_TRUE
;
6857 PL_DHashTableEnumerate(mSubDocuments
, CanCacheSubDocument
, &canCache
);
6863 nsDocument::Destroy()
6865 // The ContentViewer wants to release the document now. So, tell our content
6866 // to drop any references to the document so that it can be destroyed.
6870 mIsGoingAway
= PR_TRUE
;
6872 RemovedFromDocShell();
6874 PRUint32 i
, count
= mChildren
.ChildCount();
6875 for (i
= 0; i
< count
; ++i
) {
6876 mChildren
.ChildAt(i
)->DestroyContent();
6879 mLayoutHistoryState
= nsnull
;
6881 nsContentList::OnDocumentDestroy(this);
6883 // Shut down our external resource map. We might not need this for
6884 // leak-fixing if we fix DocumentViewerImpl to do cycle-collection, but
6885 // tearing down all those frame trees right now is the right thing to do.
6886 mExternalResourceMap
.Shutdown();
6888 // XXX We really should let cycle collection do this, but that currently still
6889 // leaks (see https://bugzilla.mozilla.org/show_bug.cgi?id=406684).
6894 nsDocument::RemovedFromDocShell()
6896 if (mRemovedFromDocShell
)
6899 mRemovedFromDocShell
= PR_TRUE
;
6901 PRUint32 i
, count
= mChildren
.ChildCount();
6902 for (i
= 0; i
< count
; ++i
) {
6903 mChildren
.ChildAt(i
)->SaveSubtreeState();
6907 already_AddRefed
<nsILayoutHistoryState
>
6908 nsDocument::GetLayoutHistoryState() const
6910 nsILayoutHistoryState
* state
= nsnull
;
6911 if (!mScriptGlobalObject
) {
6912 NS_IF_ADDREF(state
= mLayoutHistoryState
);
6914 nsCOMPtr
<nsIDocShell
> docShell(do_QueryReferent(mDocumentContainer
));
6916 docShell
->GetLayoutHistoryState(&state
);
6924 nsDocument::BlockOnload()
6926 if (mDisplayDocument
) {
6927 mDisplayDocument
->BlockOnload();
6931 // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
6932 // -- it's not ours.
6933 if (mOnloadBlockCount
== 0 && mScriptGlobalObject
) {
6934 nsCOMPtr
<nsILoadGroup
> loadGroup
= GetDocumentLoadGroup();
6936 loadGroup
->AddRequest(mOnloadBlocker
, nsnull
);
6939 ++mOnloadBlockCount
;
6943 nsDocument::UnblockOnload(PRBool aFireSync
)
6945 if (mDisplayDocument
) {
6946 mDisplayDocument
->UnblockOnload(aFireSync
);
6950 if (mOnloadBlockCount
== 0) {
6951 NS_NOTREACHED("More UnblockOnload() calls than BlockOnload() calls; dropping call");
6955 --mOnloadBlockCount
;
6957 // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
6958 // -- it's not ours.
6959 if (mOnloadBlockCount
== 0 && mScriptGlobalObject
) {
6961 // Increment mOnloadBlockCount, since DoUnblockOnload will decrement it
6962 ++mOnloadBlockCount
;
6965 PostUnblockOnloadEvent();
6970 class nsUnblockOnloadEvent
: public nsRunnable
{
6972 nsUnblockOnloadEvent(nsDocument
*doc
) : mDoc(doc
) {}
6974 mDoc
->DoUnblockOnload();
6978 nsRefPtr
<nsDocument
> mDoc
;
6982 nsDocument::PostUnblockOnloadEvent()
6984 nsCOMPtr
<nsIRunnable
> evt
= new nsUnblockOnloadEvent(this);
6985 nsresult rv
= NS_DispatchToCurrentThread(evt
);
6986 if (NS_SUCCEEDED(rv
)) {
6987 // Stabilize block count so we don't post more events while this one is up
6988 ++mOnloadBlockCount
;
6990 NS_WARNING("failed to dispatch nsUnblockOnloadEvent");
6995 nsDocument::DoUnblockOnload()
6997 NS_PRECONDITION(!mDisplayDocument
,
6998 "Shouldn't get here for resource document");
6999 NS_PRECONDITION(mOnloadBlockCount
!= 0,
7000 "Shouldn't have a count of zero here, since we stabilized in "
7001 "PostUnblockOnloadEvent");
7003 --mOnloadBlockCount
;
7005 if (mOnloadBlockCount
!= 0) {
7006 // We blocked again after the last unblock. Nothing to do here. We'll
7007 // post a new event when we unblock again.
7011 // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
7012 // -- it's not ours.
7013 if (mScriptGlobalObject
) {
7014 nsCOMPtr
<nsILoadGroup
> loadGroup
= GetDocumentLoadGroup();
7016 loadGroup
->RemoveRequest(mOnloadBlocker
, nsnull
, NS_OK
);
7021 /* See if document is a child of this. If so, return the frame element in this
7022 * document that holds currentDoc (or an ancestor). */
7023 already_AddRefed
<nsIDOMElement
>
7024 nsDocument::CheckAncestryAndGetFrame(nsIDocument
* aDocument
) const
7026 nsIDocument
* parentDoc
;
7027 for (parentDoc
= aDocument
->GetParentDocument();
7028 parentDoc
!= static_cast<const nsIDocument
* const>(this);
7029 parentDoc
= parentDoc
->GetParentDocument()) {
7034 aDocument
= parentDoc
;
7037 // In a child document. Get the appropriate frame.
7038 nsPIDOMWindow
* currentWindow
= aDocument
->GetWindow();
7039 if (!currentWindow
) {
7042 nsIDOMElement
* frameElement
= currentWindow
->GetFrameElementInternal();
7043 if (!frameElement
) {
7047 // Sanity check result
7048 nsCOMPtr
<nsIDOMDocument
> domDocument
;
7049 frameElement
->GetOwnerDocument(getter_AddRefs(domDocument
));
7050 if (domDocument
!= this) {
7051 NS_ERROR("Child documents should live in windows the parent owns");
7055 NS_ADDREF(frameElement
);
7056 return frameElement
;
7060 nsDocument::DispatchEventToWindow(nsEvent
*aEvent
)
7062 nsPIDOMWindow
*window
= GetWindow();
7066 aEvent
->target
= static_cast<nsIDocument
*>(this);
7067 nsEventDispatcher::Dispatch(window
, nsnull
, aEvent
);
7071 nsDocument::OnPageShow(PRBool aPersisted
)
7076 nsIContent
* root
= GetRootContent();
7077 if (aPersisted
&& root
) {
7078 // Send out notifications that our <link> elements are attached.
7079 nsRefPtr
<nsContentList
> links
= NS_GetContentList(root
,
7081 kNameSpaceID_Unknown
);
7084 PRUint32 linkCount
= links
->Length(PR_TRUE
);
7085 for (PRUint32 i
= 0; i
< linkCount
; ++i
) {
7086 nsCOMPtr
<nsILink
> link
= do_QueryInterface(links
->Item(i
, PR_FALSE
));
7094 nsPageTransitionEvent
event(PR_TRUE
, NS_PAGE_SHOW
, aPersisted
);
7095 DispatchEventToWindow(&event
);
7099 nsDocument::OnPageHide(PRBool aPersisted
)
7101 // Send out notifications that our <link> elements are detached,
7102 // but only if this is not a full unload.
7103 nsIContent
* root
= GetRootContent();
7104 if (aPersisted
&& root
) {
7105 nsRefPtr
<nsContentList
> links
= NS_GetContentList(root
,
7107 kNameSpaceID_Unknown
);
7110 PRUint32 linkCount
= links
->Length(PR_TRUE
);
7111 for (PRUint32 i
= 0; i
< linkCount
; ++i
) {
7112 nsCOMPtr
<nsILink
> link
= do_QueryInterface(links
->Item(i
, PR_FALSE
));
7114 link
->LinkRemoved();
7120 // Now send out a PageHide event.
7121 nsPageTransitionEvent
event(PR_TRUE
, NS_PAGE_HIDE
, aPersisted
);
7122 DispatchEventToWindow(&event
);
7124 mVisible
= PR_FALSE
;
7128 nsDocument::WillDispatchMutationEvent(nsINode
* aTarget
)
7130 NS_ASSERTION(mSubtreeModifiedDepth
!= 0 ||
7131 mSubtreeModifiedTargets
.Count() == 0,
7132 "mSubtreeModifiedTargets not cleared after dispatching?");
7133 ++mSubtreeModifiedDepth
;
7135 // MayDispatchMutationEvent is often called just before this method,
7136 // so it has already appended the node to mSubtreeModifiedTargets.
7137 PRInt32 count
= mSubtreeModifiedTargets
.Count();
7138 if (!count
|| mSubtreeModifiedTargets
[count
- 1] != aTarget
) {
7139 mSubtreeModifiedTargets
.AppendObject(aTarget
);
7145 nsDocument::MutationEventDispatched(nsINode
* aTarget
)
7147 --mSubtreeModifiedDepth
;
7148 if (mSubtreeModifiedDepth
== 0) {
7149 PRInt32 count
= mSubtreeModifiedTargets
.Count();
7154 nsCOMPtr
<nsPIDOMWindow
> window
;
7155 window
= do_QueryInterface(GetScriptGlobalObject());
7157 !window
->HasMutationListeners(NS_EVENT_BITS_MUTATION_SUBTREEMODIFIED
)) {
7158 mSubtreeModifiedTargets
.Clear();
7162 nsCOMArray
<nsINode
> realTargets
;
7163 for (PRInt32 i
= 0; i
< count
; ++i
) {
7164 nsINode
* possibleTarget
= mSubtreeModifiedTargets
[i
];
7165 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(possibleTarget
);
7166 if (content
&& content
->IsInNativeAnonymousSubtree()) {
7170 nsINode
* commonAncestor
= nsnull
;
7171 PRInt32 realTargetCount
= realTargets
.Count();
7172 for (PRInt32 j
= 0; j
< realTargetCount
; ++j
) {
7174 nsContentUtils::GetCommonAncestor(possibleTarget
, realTargets
[j
]);
7175 if (commonAncestor
) {
7176 realTargets
.ReplaceObjectAt(commonAncestor
, j
);
7180 if (!commonAncestor
) {
7181 realTargets
.AppendObject(possibleTarget
);
7185 mSubtreeModifiedTargets
.Clear();
7187 PRInt32 realTargetCount
= realTargets
.Count();
7188 for (PRInt32 k
= 0; k
< realTargetCount
; ++k
) {
7189 mozAutoRemovableBlockerRemover blockerRemover
;
7191 nsMutationEvent
mutation(PR_TRUE
, NS_MUTATION_SUBTREEMODIFIED
);
7192 nsEventDispatcher::Dispatch(realTargets
[k
], nsnull
, &mutation
);
7197 static PRUint32
GetURIHash(nsIURI
* aURI
)
7201 return HashString(str
);
7205 nsDocument::AddStyleRelevantLink(nsIContent
* aContent
, nsIURI
* aURI
)
7207 nsUint32ToContentHashEntry
* entry
= mLinkMap
.PutEntry(GetURIHash(aURI
));
7208 if (!entry
) // out of memory?
7210 entry
->PutContent(aContent
);
7214 nsDocument::ForgetLink(nsIContent
* aContent
)
7216 // Important optimization! If the link map is empty (as it will be
7217 // during teardown because we destroy the map early), then stop
7218 // now before we waste time constructing a URI object.
7219 if (mLinkMap
.Count() == 0)
7222 nsCOMPtr
<nsIURI
> uri
;
7223 if (!aContent
->IsLink(getter_AddRefs(uri
)))
7225 PRUint32 hash
= GetURIHash(uri
);
7226 nsUint32ToContentHashEntry
* entry
= mLinkMap
.GetEntry(hash
);
7230 entry
->RemoveContent(aContent
);
7231 if (entry
->IsEmpty()) {
7232 // Remove the entry and allow the table to resize, in case
7233 // a lot of links are being removed from the document or modified
7234 mLinkMap
.RemoveEntry(hash
);
7238 class URIVisitNotifier
: public nsUint32ToContentHashEntry::Visitor
7241 nsCAutoString matchURISpec
;
7242 nsCOMArray
<nsIContent
> contentVisited
;
7244 virtual void Visit(nsIContent
* aContent
) {
7245 // Ensure that the URIs really match before we try to do anything
7246 nsCOMPtr
<nsIURI
> uri
;
7247 if (!aContent
->IsLink(getter_AddRefs(uri
))) {
7248 NS_ERROR("Should have found a URI for content in the link map");
7253 // We use nsCString::Equals here instead of nsIURI::Equals because
7254 // history matching is all based on spec equality
7255 if (!spec
.Equals(matchURISpec
))
7258 // Throw away the cached link state so it gets refetched by the style
7260 nsCOMPtr
<nsILink
> link
= do_QueryInterface(aContent
);
7262 link
->SetLinkState(eLinkState_Unknown
);
7264 contentVisited
.AppendObject(aContent
);
7269 nsDocument::NotifyURIVisitednessChanged(nsIURI
* aURI
)
7272 mVisitednessChangedURIs
.AppendObject(aURI
);
7276 nsUint32ToContentHashEntry
* entry
= mLinkMap
.GetEntry(GetURIHash(aURI
));
7280 URIVisitNotifier visitor
;
7281 aURI
->GetSpec(visitor
.matchURISpec
);
7282 entry
->VisitContent(&visitor
);
7283 for (PRUint32 count
= visitor
.contentVisited
.Count(), i
= 0; i
< count
; ++i
) {
7284 ContentStatesChanged(visitor
.contentVisited
[i
],
7285 nsnull
, NS_EVENT_STATE_VISITED
);
7290 nsDocument::DestroyLinkMap()
7292 mVisitednessChangedURIs
.Clear();
7297 nsDocument::UpdateLinkMap()
7299 NS_ASSERTION(mVisible
,
7300 "Should only be updating the link map in visible documents");
7304 PRInt32 count
= mVisitednessChangedURIs
.Count();
7305 for (PRInt32 i
= 0; i
< count
; ++i
) {
7306 NotifyURIVisitednessChanged(mVisitednessChangedURIs
[i
]);
7308 mVisitednessChangedURIs
.Clear();
7312 nsDocument::GetScriptTypeID(PRUint32
*aScriptType
)
7314 NS_ERROR("No default script type here - ask some element");
7315 return nsIProgrammingLanguage::UNKNOWN
;
7319 nsDocument::SetScriptTypeID(PRUint32 aScriptType
)
7321 NS_ERROR("Can't change default script type for a document");
7322 return NS_ERROR_NOT_IMPLEMENTED
;
7326 nsDocument::QuerySelector(const nsAString
& aSelector
,
7327 nsIDOMElement
**aReturn
)
7329 return nsGenericElement::doQuerySelector(this, aSelector
, aReturn
);
7333 nsDocument::QuerySelectorAll(const nsAString
& aSelector
,
7334 nsIDOMNodeList
**aReturn
)
7336 return nsGenericElement::doQuerySelectorAll(this, aSelector
, aReturn
);
7340 nsDocument::CloneDocHelper(nsDocument
* clone
) const
7343 nsresult rv
= clone
->Init();
7344 NS_ENSURE_SUCCESS(rv
, rv
);
7346 // Set URI/principal
7347 clone
->nsDocument::SetDocumentURI(nsIDocument::GetDocumentURI());
7348 // Must set the principal first, since SetBaseURI checks it.
7349 clone
->SetPrincipal(NodePrincipal());
7350 rv
= clone
->SetBaseURI(nsIDocument::GetBaseURI());
7351 NS_ENSURE_SUCCESS(rv
, rv
);
7353 // Set scripting object
7354 PRBool hasHadScriptObject
= PR_TRUE
;
7355 nsIScriptGlobalObject
* scriptObject
=
7356 GetScriptHandlingObject(hasHadScriptObject
);
7357 NS_ENSURE_STATE(scriptObject
|| !hasHadScriptObject
);
7358 clone
->SetScriptHandlingObject(scriptObject
);
7360 // Make the clone a data document
7361 clone
->SetLoadedAsData(PR_TRUE
);
7365 // State from nsIDocument
7366 clone
->mCharacterSet
= mCharacterSet
;
7367 clone
->mCharacterSetSource
= mCharacterSetSource
;
7368 clone
->mCompatMode
= mCompatMode
;
7369 clone
->mBidiOptions
= mBidiOptions
;
7370 clone
->mContentLanguage
= mContentLanguage
;
7371 clone
->mContentType
= mContentType
;
7372 clone
->mSecurityInfo
= mSecurityInfo
;
7374 // State from nsDocument
7375 clone
->mIsRegularHTML
= mIsRegularHTML
;
7376 clone
->mXMLDeclarationBits
= mXMLDeclarationBits
;
7377 clone
->mBaseTarget
= mBaseTarget
;