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 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 * Base class for all our document implementations.
11 #include "nsDocument.h"
13 #include "mozilla/ArrayUtils.h"
14 #include "mozilla/AutoRestore.h"
15 #include "mozilla/BinarySearch.h"
16 #include "mozilla/DebugOnly.h"
17 #include "mozilla/MemoryReporting.h"
18 #include "mozilla/Likely.h"
25 #include "mozilla/Telemetry.h"
26 #include "nsIInterfaceRequestor.h"
27 #include "nsIInterfaceRequestorUtils.h"
28 #include "nsILoadContext.h"
29 #include "nsUnicharUtils.h"
30 #include "nsContentList.h"
31 #include "nsIObserver.h"
32 #include "nsIBaseWindow.h"
33 #include "mozilla/css/Loader.h"
34 #include "mozilla/css/ImageLoader.h"
35 #include "nsDocShell.h"
36 #include "nsIDocShellTreeItem.h"
37 #include "nsCOMArray.h"
38 #include "nsDOMClassInfo.h"
39 #include "mozilla/Services.h"
41 #include "mozilla/AsyncEventDispatcher.h"
42 #include "mozilla/BasicEvents.h"
43 #include "mozilla/EventListenerManager.h"
44 #include "mozilla/EventStateManager.h"
45 #include "nsIDOMNodeFilter.h"
47 #include "nsIDOMStyleSheet.h"
48 #include "mozilla/dom/Attr.h"
49 #include "nsIDOMDOMImplementation.h"
50 #include "nsIDOMDocumentXBL.h"
51 #include "mozilla/dom/Element.h"
52 #include "nsGenericHTMLElement.h"
53 #include "mozilla/dom/CDATASection.h"
54 #include "mozilla/dom/ProcessingInstruction.h"
55 #include "nsDOMString.h"
56 #include "nsNodeUtils.h"
57 #include "nsLayoutUtils.h" // for GetFrameForPoint
59 #include "nsITabChild.h"
62 #include "nsIDOMText.h"
63 #include "nsIDOMComment.h"
64 #include "mozilla/dom/DocumentType.h"
65 #include "mozilla/dom/NodeIterator.h"
66 #include "mozilla/dom/TreeWalker.h"
68 #include "nsIServiceManager.h"
69 #include "nsIServiceWorkerManager.h"
71 #include "nsCanvasFrame.h"
72 #include "nsContentCID.h"
74 #include "nsPresShell.h"
75 #include "nsPresContext.h"
77 #include "nsThreadUtils.h"
78 #include "nsNodeInfoManager.h"
79 #include "nsIFileChannel.h"
80 #include "nsIMultiPartChannel.h"
81 #include "nsIRefreshURI.h"
82 #include "nsIWebNavigation.h"
83 #include "nsIScriptError.h"
84 #include "nsStyleSheetService.h"
86 #include "nsNetUtil.h" // for NS_MakeAbsoluteURI
88 #include "nsIScriptSecurityManager.h"
89 #include "nsIPrincipal.h"
91 #include "nsIDOMWindow.h"
92 #include "nsPIDOMWindow.h"
93 #include "nsIDOMElement.h"
94 #include "nsFocusManager.h"
96 // for radio group stuff
97 #include "nsIDOMHTMLInputElement.h"
98 #include "nsIRadioVisitor.h"
99 #include "nsIFormControl.h"
101 #include "nsBidiUtils.h"
103 #include "nsIParserService.h"
104 #include "nsContentCreatorFunctions.h"
106 #include "nsIScriptContext.h"
107 #include "nsBindingManager.h"
108 #include "nsIDOMHTMLDocument.h"
109 #include "nsHTMLDocument.h"
110 #include "nsIDOMHTMLFormElement.h"
111 #include "nsIRequest.h"
112 #include "nsHostObjectProtocolHandler.h"
114 #include "nsCharsetSource.h"
115 #include "nsIParser.h"
116 #include "nsIContentSink.h"
118 #include "nsDateTimeFormatCID.h"
119 #include "nsIDateTimeFormat.h"
120 #include "mozilla/EventDispatcher.h"
121 #include "mozilla/EventStates.h"
122 #include "mozilla/InternalMutationEvent.h"
123 #include "nsDOMCID.h"
126 #include "nsIXPConnect.h"
127 #include "nsCCUncollectableMarker.h"
128 #include "nsIContentPolicy.h"
129 #include "nsContentPolicyUtils.h"
130 #include "nsICategoryManager.h"
131 #include "nsIDocumentLoaderFactory.h"
132 #include "nsIDocumentLoader.h"
133 #include "nsIContentViewer.h"
134 #include "nsIXMLContentSink.h"
135 #include "nsIXULDocument.h"
136 #include "nsIPrompt.h"
137 #include "nsIPropertyBag2.h"
138 #include "mozilla/dom/PageTransitionEvent.h"
139 #include "mozilla/dom/StyleRuleChangeEvent.h"
140 #include "mozilla/dom/StyleSheetChangeEvent.h"
141 #include "mozilla/dom/StyleSheetApplicableStateChangeEvent.h"
142 #include "nsJSUtils.h"
143 #include "nsFrameLoader.h"
144 #include "nsEscape.h"
145 #include "nsObjectLoadingContent.h"
146 #include "nsHtml5TreeOpExecutor.h"
147 #include "mozilla/dom/HTMLLinkElement.h"
148 #include "mozilla/dom/HTMLMediaElement.h"
150 #include "mozAutoDocUpdate.h"
151 #include "nsGlobalWindow.h"
152 #include "mozilla/dom/EncodingUtils.h"
153 #include "nsDOMNavigationTiming.h"
155 #include "nsSMILAnimationController.h"
156 #include "imgIContainer.h"
157 #include "nsSVGUtils.h"
158 #include "SVGElementFactory.h"
160 #include "nsRefreshDriver.h"
162 // FOR CSP (autogenerated by xpidl)
163 #include "nsIContentSecurityPolicy.h"
164 #include "mozilla/dom/nsCSPService.h"
165 #include "nsHTMLStyleSheet.h"
166 #include "nsHTMLCSSStyleSheet.h"
167 #include "SVGAttrAnimationRuleProcessor.h"
168 #include "mozilla/dom/DOMImplementation.h"
169 #include "mozilla/dom/ShadowRoot.h"
170 #include "mozilla/dom/Comment.h"
171 #include "nsTextNode.h"
172 #include "mozilla/dom/Link.h"
173 #include "mozilla/dom/HTMLElementBinding.h"
174 #include "mozilla/dom/SVGElementBinding.h"
175 #include "nsXULAppAPI.h"
176 #include "mozilla/dom/Touch.h"
177 #include "mozilla/dom/TouchEvent.h"
179 #include "mozilla/Preferences.h"
181 #include "imgILoader.h"
182 #include "imgRequestProxy.h"
183 #include "nsWrapperCacheInlines.h"
184 #include "nsSandboxFlags.h"
185 #include "nsIAppsService.h"
186 #include "mozilla/dom/AnonymousContent.h"
187 #include "mozilla/dom/AnimationTimeline.h"
188 #include "mozilla/dom/BindingUtils.h"
189 #include "mozilla/dom/DocumentFragment.h"
190 #include "mozilla/dom/Event.h"
191 #include "mozilla/dom/HTMLBodyElement.h"
192 #include "mozilla/dom/HTMLInputElement.h"
193 #include "mozilla/dom/MediaQueryList.h"
194 #include "mozilla/dom/NodeFilterBinding.h"
195 #include "mozilla/dom/OwningNonNull.h"
196 #include "mozilla/dom/TabChild.h"
197 #include "mozilla/dom/UndoManager.h"
198 #include "mozilla/dom/WebComponentsBinding.h"
200 #include "nsDOMCaretPosition.h"
201 #include "nsIDOMHTMLTextAreaElement.h"
202 #include "nsViewportInfo.h"
203 #include "nsIContentPermissionPrompt.h"
204 #include "mozilla/StaticPtr.h"
205 #include "nsITextControlElement.h"
206 #include "nsIDOMNSEditableElement.h"
207 #include "nsIEditor.h"
208 #include "nsIDOMCSSStyleRule.h"
209 #include "mozilla/css/Rule.h"
210 #include "nsIDOMLocation.h"
211 #include "nsIHttpChannelInternal.h"
212 #include "nsISecurityConsoleMessage.h"
213 #include "nsCharSeparatedTokenizer.h"
214 #include "mozilla/dom/XPathEvaluator.h"
215 #include "mozilla/dom/XPathNSResolverBinding.h"
216 #include "mozilla/dom/XPathResult.h"
217 #include "nsIDocumentEncoder.h"
218 #include "nsIDocumentActivity.h"
219 #include "nsIStructuredCloneContainer.h"
220 #include "nsIMutableArray.h"
221 #include "nsContentPermissionHelper.h"
222 #include "mozilla/dom/DOMStringList.h"
223 #include "nsWindowMemoryReporter.h"
224 #include "nsLocation.h"
225 #include "mozilla/dom/FontFaceSet.h"
226 #include "mozilla/dom/BoxObject.h"
228 #ifdef MOZ_MEDIA_NAVIGATOR
229 #include "mozilla/MediaManager.h"
230 #endif // MOZ_MEDIA_NAVIGATOR
232 #include "IPeerConnection.h"
235 using namespace mozilla
;
236 using namespace mozilla::dom
;
238 typedef nsTArray
<Link
*> LinkArray
;
241 static PRLogModuleInfo
* gDocumentLeakPRLog
;
242 static PRLogModuleInfo
* gCspPRLog
;
245 #define NAME_NOT_VALID ((nsSimpleContentList*)1)
247 nsIdentifierMapEntry::~nsIdentifierMapEntry()
252 nsIdentifierMapEntry::Traverse(nsCycleCollectionTraversalCallback
* aCallback
)
254 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback
,
255 "mIdentifierMap mNameContentList");
256 aCallback
->NoteXPCOMChild(static_cast<nsIDOMNodeList
*>(mNameContentList
));
259 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback
,
260 "mIdentifierMap mImageElement element");
261 nsIContent
* imageElement
= mImageElement
;
262 aCallback
->NoteXPCOMChild(imageElement
);
267 nsIdentifierMapEntry::IsEmpty()
269 return mIdContentList
.Count() == 0 && !mNameContentList
&&
270 !mChangeCallbacks
&& !mImageElement
;
274 nsIdentifierMapEntry::GetIdElement()
276 return static_cast<Element
*>(mIdContentList
.SafeElementAt(0));
280 nsIdentifierMapEntry::GetImageIdElement()
282 return mImageElement
? mImageElement
.get() : GetIdElement();
286 nsIdentifierMapEntry::AppendAllIdContent(nsCOMArray
<nsIContent
>* aElements
)
288 for (int32_t i
= 0; i
< mIdContentList
.Count(); ++i
) {
289 aElements
->AppendObject(static_cast<Element
*>(mIdContentList
[i
]));
294 nsIdentifierMapEntry::AddContentChangeCallback(nsIDocument::IDTargetObserver aCallback
,
295 void* aData
, bool aForImage
)
297 if (!mChangeCallbacks
) {
298 mChangeCallbacks
= new nsTHashtable
<ChangeCallbackEntry
>;
299 if (!mChangeCallbacks
)
303 ChangeCallback cc
= { aCallback
, aData
, aForImage
};
304 mChangeCallbacks
->PutEntry(cc
);
308 nsIdentifierMapEntry::RemoveContentChangeCallback(nsIDocument::IDTargetObserver aCallback
,
309 void* aData
, bool aForImage
)
311 if (!mChangeCallbacks
)
313 ChangeCallback cc
= { aCallback
, aData
, aForImage
};
314 mChangeCallbacks
->RemoveEntry(cc
);
315 if (mChangeCallbacks
->Count() == 0) {
316 mChangeCallbacks
= nullptr;
320 struct FireChangeArgs
{
324 bool mHaveImageOverride
;
327 // XXX Workaround for bug 980560 to maintain the existing broken semantics
329 struct nsIStyleRule::COMTypeInfo
<css::Rule
, void> {
330 static const nsIID kIID
;
332 const nsIID
nsIStyleRule::COMTypeInfo
<css::Rule
, void>::kIID
= NS_ISTYLE_RULE_IID
;
337 static PLDHashOperator
338 CustomDefinitionsTraverse(CustomElementHashKey
* aKey
,
339 CustomElementDefinition
* aDefinition
,
342 nsCycleCollectionTraversalCallback
* cb
=
343 static_cast<nsCycleCollectionTraversalCallback
*>(aArg
);
345 nsAutoPtr
<LifecycleCallbacks
>& callbacks
= aDefinition
->mCallbacks
;
347 if (callbacks
->mAttributeChangedCallback
.WasPassed()) {
348 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
349 "mCustomDefinitions->mCallbacks->mAttributeChangedCallback");
350 cb
->NoteXPCOMChild(aDefinition
->mCallbacks
->mAttributeChangedCallback
.Value());
353 if (callbacks
->mCreatedCallback
.WasPassed()) {
354 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
355 "mCustomDefinitions->mCallbacks->mCreatedCallback");
356 cb
->NoteXPCOMChild(aDefinition
->mCallbacks
->mCreatedCallback
.Value());
359 if (callbacks
->mAttachedCallback
.WasPassed()) {
360 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
361 "mCustomDefinitions->mCallbacks->mAttachedCallback");
362 cb
->NoteXPCOMChild(aDefinition
->mCallbacks
->mAttachedCallback
.Value());
365 if (callbacks
->mDetachedCallback
.WasPassed()) {
366 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
367 "mCustomDefinitions->mCallbacks->mDetachedCallback");
368 cb
->NoteXPCOMChild(aDefinition
->mCallbacks
->mDetachedCallback
.Value());
371 return PL_DHASH_NEXT
;
374 static PLDHashOperator
375 CandidatesTraverse(CustomElementHashKey
* aKey
,
376 nsTArray
<nsRefPtr
<Element
>>* aData
,
379 nsCycleCollectionTraversalCallback
*cb
=
380 static_cast<nsCycleCollectionTraversalCallback
*>(aArg
);
381 for (size_t i
= 0; i
< aData
->Length(); ++i
) {
382 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
, "mCandidatesMap->Element");
383 cb
->NoteXPCOMChild(aData
->ElementAt(i
));
385 return PL_DHASH_NEXT
;
388 struct CustomDefinitionTraceArgs
390 const TraceCallbacks
& callbacks
;
394 static PLDHashOperator
395 CustomDefinitionTrace(CustomElementHashKey
*aKey
,
396 CustomElementDefinition
*aData
,
399 CustomDefinitionTraceArgs
* traceArgs
= static_cast<CustomDefinitionTraceArgs
*>(aArg
);
400 MOZ_ASSERT(aData
, "Definition must not be null");
401 traceArgs
->callbacks
.Trace(&aData
->mPrototype
, "mCustomDefinitions prototype",
403 return PL_DHASH_NEXT
;
406 NS_IMPL_CYCLE_COLLECTION_CLASS(Registry
)
408 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Registry
)
409 CustomDefinitionTraceArgs customDefinitionArgs
= { aCallbacks
, aClosure
};
410 tmp
->mCustomDefinitions
.EnumerateRead(CustomDefinitionTrace
,
411 &customDefinitionArgs
);
412 NS_IMPL_CYCLE_COLLECTION_TRACE_END
414 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Registry
)
415 tmp
->mCustomDefinitions
.EnumerateRead(CustomDefinitionsTraverse
, &cb
);
416 tmp
->mCandidatesMap
.EnumerateRead(CandidatesTraverse
, &cb
);
417 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
418 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
420 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Registry
)
421 tmp
->mCustomDefinitions
.Clear();
422 tmp
->mCandidatesMap
.Clear();
423 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
425 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Registry
)
426 NS_INTERFACE_MAP_ENTRY(nsISupports
)
429 NS_IMPL_CYCLE_COLLECTING_ADDREF(Registry
)
430 NS_IMPL_CYCLE_COLLECTING_RELEASE(Registry
)
434 mozilla::HoldJSObjects(this);
437 Registry::~Registry()
439 mozilla::DropJSObjects(this);
443 CustomElementCallback::Call()
447 case nsIDocument::eCreated
:
449 // For the duration of this callback invocation, the element is being created
450 // flag must be set to true.
451 mOwnerData
->mElementIsBeingCreated
= true;
453 // The callback hasn't actually been invoked yet, but we need to flip
454 // this now in order to enqueue the attached callback. This is a spec
455 // bug (w3c bug 27437).
456 mOwnerData
->mCreatedCallbackInvoked
= true;
458 // If ELEMENT is in a document and this document has a browsing context,
459 // enqueue attached callback for ELEMENT.
460 nsIDocument
* document
= mThisObject
->GetUncomposedDoc();
461 if (document
&& document
->GetDocShell()) {
462 document
->EnqueueLifecycleCallback(nsIDocument::eAttached
, mThisObject
);
465 static_cast<LifecycleCreatedCallback
*>(mCallback
.get())->Call(mThisObject
, rv
);
466 mOwnerData
->mElementIsBeingCreated
= false;
469 case nsIDocument::eAttached
:
470 static_cast<LifecycleAttachedCallback
*>(mCallback
.get())->Call(mThisObject
, rv
);
472 case nsIDocument::eDetached
:
473 static_cast<LifecycleDetachedCallback
*>(mCallback
.get())->Call(mThisObject
, rv
);
475 case nsIDocument::eAttributeChanged
:
476 static_cast<LifecycleAttributeChangedCallback
*>(mCallback
.get())->Call(mThisObject
,
477 mArgs
.name
, mArgs
.oldValue
, mArgs
.newValue
, rv
);
483 CustomElementCallback::Traverse(nsCycleCollectionTraversalCallback
& aCb
) const
485 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb
, "mThisObject");
486 aCb
.NoteXPCOMChild(mThisObject
);
488 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb
, "mCallback");
489 aCb
.NoteXPCOMChild(mCallback
);
492 CustomElementCallback::CustomElementCallback(Element
* aThisObject
,
493 nsIDocument::ElementCallbackType aCallbackType
,
494 mozilla::dom::CallbackFunction
* aCallback
,
495 CustomElementData
* aOwnerData
)
496 : mThisObject(aThisObject
),
497 mCallback(aCallback
),
498 mType(aCallbackType
),
499 mOwnerData(aOwnerData
)
503 CustomElementDefinition::CustomElementDefinition(JSObject
* aPrototype
,
506 LifecycleCallbacks
* aCallbacks
,
507 uint32_t aNamespaceID
,
509 : mPrototype(aPrototype
),
511 mLocalName(aLocalName
),
512 mCallbacks(aCallbacks
),
513 mNamespaceID(aNamespaceID
),
518 CustomElementData::CustomElementData(nsIAtom
* aType
)
520 mCurrentCallback(-1),
521 mElementIsBeingCreated(false),
522 mCreatedCallbackInvoked(true),
523 mAssociatedMicroTask(-1)
528 CustomElementData::RunCallbackQueue()
530 // Note: It's possible to re-enter this method.
531 while (static_cast<uint32_t>(++mCurrentCallback
) < mCallbackQueue
.Length()) {
532 mCallbackQueue
[mCurrentCallback
]->Call();
535 mCallbackQueue
.Clear();
536 mCurrentCallback
= -1;
540 } // namespace mozilla
542 static PLDHashOperator
543 FireChangeEnumerator(nsIdentifierMapEntry::ChangeCallbackEntry
*aEntry
, void *aArg
)
545 FireChangeArgs
* args
= static_cast<FireChangeArgs
*>(aArg
);
546 // Don't fire image changes for non-image observers, and don't fire element
547 // changes for image observers when an image override is active.
548 if (aEntry
->mKey
.mForImage
? (args
->mHaveImageOverride
&& !args
->mImageOnly
) :
550 return PL_DHASH_NEXT
;
551 return aEntry
->mKey
.mCallback(args
->mFrom
, args
->mTo
, aEntry
->mKey
.mData
)
552 ? PL_DHASH_NEXT
: PL_DHASH_REMOVE
;
556 nsIdentifierMapEntry::FireChangeCallbacks(Element
* aOldElement
,
557 Element
* aNewElement
,
560 if (!mChangeCallbacks
)
563 FireChangeArgs args
= { aOldElement
, aNewElement
, aImageOnly
, !!mImageElement
};
564 mChangeCallbacks
->EnumerateEntries(FireChangeEnumerator
, &args
);
569 struct PositionComparator
571 Element
* const mElement
;
572 explicit PositionComparator(Element
* const aElement
) : mElement(aElement
) {}
574 int operator()(void* aElement
) const {
575 Element
* curElement
= static_cast<Element
*>(aElement
);
576 if (mElement
== curElement
) {
579 if (nsContentUtils::PositionIsBefore(mElement
, curElement
)) {
588 nsIdentifierMapEntry::AddIdElement(Element
* aElement
)
590 NS_PRECONDITION(aElement
, "Must have element");
591 NS_PRECONDITION(mIdContentList
.IndexOf(nullptr) < 0,
592 "Why is null in our list?");
595 Element
* currentElement
=
596 static_cast<Element
*>(mIdContentList
.SafeElementAt(0));
600 if (mIdContentList
.Count() == 0) {
601 if (!mIdContentList
.AppendElement(aElement
))
603 NS_ASSERTION(currentElement
== nullptr, "How did that happen?");
604 FireChangeCallbacks(nullptr, aElement
);
608 // We seem to have multiple content nodes for the same id, or XUL is messing
609 // with us. Search for the right place to insert the content.
612 if (BinarySearchIf(mIdContentList
, 0, mIdContentList
.Count(),
613 PositionComparator(aElement
), &idx
)) {
614 // Already in the list, so already in the right spot. Get out of here.
615 // XXXbz this only happens because XUL does all sorts of random
616 // UpdateIdTableEntry calls. Hate, hate, hate!
620 if (!mIdContentList
.InsertElementAt(aElement
, idx
))
624 Element
* oldElement
=
625 static_cast<Element
*>(mIdContentList
.SafeElementAt(1));
626 NS_ASSERTION(currentElement
== oldElement
, "How did that happen?");
627 FireChangeCallbacks(oldElement
, aElement
);
633 nsIdentifierMapEntry::RemoveIdElement(Element
* aElement
)
635 NS_PRECONDITION(aElement
, "Missing element");
637 // This should only be called while the document is in an update.
638 // Assertions near the call to this method guarantee this.
640 // This could fire in OOM situations
641 // Only assert this in HTML documents for now as XUL does all sorts of weird
643 NS_ASSERTION(!aElement
->OwnerDoc()->IsHTML() ||
644 mIdContentList
.IndexOf(aElement
) >= 0,
645 "Removing id entry that doesn't exist");
647 // XXXbz should this ever Compact() I guess when all the content is gone
648 // we'll just get cleaned up in the natural order of things...
649 Element
* currentElement
=
650 static_cast<Element
*>(mIdContentList
.SafeElementAt(0));
651 mIdContentList
.RemoveElement(aElement
);
652 if (currentElement
== aElement
) {
653 FireChangeCallbacks(currentElement
,
654 static_cast<Element
*>(mIdContentList
.SafeElementAt(0)));
659 nsIdentifierMapEntry::SetImageElement(Element
* aElement
)
661 Element
* oldElement
= GetImageIdElement();
662 mImageElement
= aElement
;
663 Element
* newElement
= GetImageIdElement();
664 if (oldElement
!= newElement
) {
665 FireChangeCallbacks(oldElement
, newElement
, true);
670 nsIdentifierMapEntry::AddNameElement(nsINode
* aNode
, Element
* aElement
)
672 if (!mNameContentList
) {
673 mNameContentList
= new nsSimpleContentList(aNode
);
676 mNameContentList
->AppendElement(aElement
);
680 nsIdentifierMapEntry::RemoveNameElement(Element
* aElement
)
682 if (mNameContentList
) {
683 mNameContentList
->RemoveElement(aElement
);
688 nsIdentifierMapEntry::HasIdElementExposedAsHTMLDocumentProperty()
690 Element
* idElement
= GetIdElement();
692 nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(idElement
);
696 nsIdentifierMapEntry::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf
) const
698 return nsStringHashKey::SizeOfExcludingThis(aMallocSizeOf
);
701 // Helper structs for the content->subdoc map
703 class SubDocMapEntry
: public PLDHashEntryHdr
706 // Both of these are strong references
707 Element
*mKey
; // must be first, to look like PLDHashEntryStub
708 nsIDocument
*mSubDocument
;
711 struct FindContentData
713 explicit FindContentData(nsIDocument
* aSubDoc
)
714 : mSubDocument(aSubDoc
), mResult(nullptr)
718 nsISupports
*mSubDocument
;
724 * A struct that holds all the information about a radio group.
726 struct nsRadioGroupStruct
729 : mRequiredRadioCount(0)
730 , mGroupSuffersFromValueMissing(false)
734 * A strong pointer to the currently selected radio button.
736 nsRefPtr
<HTMLInputElement
> mSelectedRadioButton
;
737 nsCOMArray
<nsIFormControl
> mRadioButtons
;
738 uint32_t mRequiredRadioCount
;
739 bool mGroupSuffersFromValueMissing
;
743 nsDOMStyleSheetList::nsDOMStyleSheetList(nsIDocument
*aDocument
)
746 // Not reference counted to avoid circular references.
747 // The document will tell us when its going away.
748 mDocument
= aDocument
;
749 mDocument
->AddObserver(this);
752 nsDOMStyleSheetList::~nsDOMStyleSheetList()
755 mDocument
->RemoveObserver(this);
759 NS_IMPL_ISUPPORTS_INHERITED(nsDOMStyleSheetList
, StyleSheetList
,
764 nsDOMStyleSheetList::Length()
770 // XXX Find the number and then cache it. We'll use the
771 // observer notification to figure out if new ones have
772 // been added or removed.
774 mLength
= mDocument
->GetNumberOfStyleSheets();
778 for (i
= 0; i
< mLength
; i
++) {
779 nsIStyleSheet
*sheet
= mDocument
->GetStyleSheetAt(i
);
780 nsCOMPtr
<nsIDOMStyleSheet
> domss(do_QueryInterface(sheet
));
781 NS_ASSERTION(domss
, "All \"normal\" sheets implement nsIDOMStyleSheet");
789 nsDOMStyleSheetList::IndexedGetter(uint32_t aIndex
, bool& aFound
)
791 if (!mDocument
|| aIndex
>= (uint32_t)mDocument
->GetNumberOfStyleSheets()) {
797 nsIStyleSheet
*sheet
= mDocument
->GetStyleSheetAt(aIndex
);
798 NS_ASSERTION(sheet
, "Must have a sheet");
800 return static_cast<CSSStyleSheet
*>(sheet
);
804 nsDOMStyleSheetList::NodeWillBeDestroyed(const nsINode
*aNode
)
810 nsDOMStyleSheetList::StyleSheetAdded(nsIDocument
*aDocument
,
811 nsIStyleSheet
* aStyleSheet
,
814 if (aDocumentSheet
&& -1 != mLength
) {
815 nsCOMPtr
<nsIDOMStyleSheet
> domss(do_QueryInterface(aStyleSheet
));
823 nsDOMStyleSheetList::StyleSheetRemoved(nsIDocument
*aDocument
,
824 nsIStyleSheet
* aStyleSheet
,
827 if (aDocumentSheet
&& -1 != mLength
) {
828 nsCOMPtr
<nsIDOMStyleSheet
> domss(do_QueryInterface(aStyleSheet
));
835 // nsOnloadBlocker implementation
836 NS_IMPL_ISUPPORTS(nsOnloadBlocker
, nsIRequest
)
839 nsOnloadBlocker::GetName(nsACString
&aResult
)
841 aResult
.AssignLiteral("about:document-onload-blocker");
846 nsOnloadBlocker::IsPending(bool *_retval
)
853 nsOnloadBlocker::GetStatus(nsresult
*status
)
860 nsOnloadBlocker::Cancel(nsresult status
)
865 nsOnloadBlocker::Suspend(void)
870 nsOnloadBlocker::Resume(void)
876 nsOnloadBlocker::GetLoadGroup(nsILoadGroup
* *aLoadGroup
)
878 *aLoadGroup
= nullptr;
883 nsOnloadBlocker::SetLoadGroup(nsILoadGroup
* aLoadGroup
)
889 nsOnloadBlocker::GetLoadFlags(nsLoadFlags
*aLoadFlags
)
891 *aLoadFlags
= nsIRequest::LOAD_NORMAL
;
896 nsOnloadBlocker::SetLoadFlags(nsLoadFlags aLoadFlags
)
901 // ==================================================================
903 nsExternalResourceMap::nsExternalResourceMap()
904 : mHaveShutDown(false)
909 nsExternalResourceMap::RequestResource(nsIURI
* aURI
,
910 nsINode
* aRequestingNode
,
911 nsDocument
* aDisplayDocument
,
912 ExternalResourceLoad
** aPendingLoad
)
914 // If we ever start allowing non-same-origin loads here, we might need to do
915 // something interesting with aRequestingPrincipal even for the hashtable
917 NS_PRECONDITION(aURI
, "Must have a URI");
918 NS_PRECONDITION(aRequestingNode
, "Must have a node");
919 *aPendingLoad
= nullptr;
924 // First, make sure we strip the ref from aURI.
925 nsCOMPtr
<nsIURI
> clone
;
926 nsresult rv
= aURI
->CloneIgnoringRef(getter_AddRefs(clone
));
927 if (NS_FAILED(rv
) || !clone
) {
931 ExternalResource
* resource
;
932 mMap
.Get(clone
, &resource
);
934 return resource
->mDocument
;
937 nsRefPtr
<PendingLoad
> load
;
938 mPendingLoads
.Get(clone
, getter_AddRefs(load
));
940 load
.forget(aPendingLoad
);
944 load
= new PendingLoad(aDisplayDocument
);
946 mPendingLoads
.Put(clone
, load
);
948 if (NS_FAILED(load
->StartLoad(clone
, aRequestingNode
))) {
949 // Make sure we don't thrash things by trying this load again, since
950 // chances are it failed for good reasons (security check, etc).
951 AddExternalResource(clone
, nullptr, nullptr, aDisplayDocument
);
953 load
.forget(aPendingLoad
);
960 nsExternalResourceEnumArgs
962 nsIDocument::nsSubDocEnumFunc callback
;
966 static PLDHashOperator
967 ExternalResourceEnumerator(nsIURI
* aKey
,
968 nsExternalResourceMap::ExternalResource
* aData
,
971 nsExternalResourceEnumArgs
* args
=
972 static_cast<nsExternalResourceEnumArgs
*>(aClosure
);
974 aData
->mDocument
? args
->callback(aData
->mDocument
, args
->data
) : true;
975 return next
? PL_DHASH_NEXT
: PL_DHASH_STOP
;
979 nsExternalResourceMap::EnumerateResources(nsIDocument::nsSubDocEnumFunc aCallback
,
982 nsExternalResourceEnumArgs args
= { aCallback
, aData
};
983 mMap
.EnumerateRead(ExternalResourceEnumerator
, &args
);
986 static PLDHashOperator
987 ExternalResourceTraverser(nsIURI
* aKey
,
988 nsExternalResourceMap::ExternalResource
* aData
,
991 nsCycleCollectionTraversalCallback
*cb
=
992 static_cast<nsCycleCollectionTraversalCallback
*>(aClosure
);
994 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
995 "mExternalResourceMap.mMap entry"
997 cb
->NoteXPCOMChild(aData
->mDocument
);
999 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
1000 "mExternalResourceMap.mMap entry"
1002 cb
->NoteXPCOMChild(aData
->mViewer
);
1004 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
1005 "mExternalResourceMap.mMap entry"
1007 cb
->NoteXPCOMChild(aData
->mLoadGroup
);
1009 return PL_DHASH_NEXT
;
1013 nsExternalResourceMap::Traverse(nsCycleCollectionTraversalCallback
* aCallback
) const
1015 // mPendingLoads will get cleared out as the requests complete, so
1016 // no need to worry about those here.
1017 mMap
.EnumerateRead(ExternalResourceTraverser
, aCallback
);
1020 static PLDHashOperator
1021 ExternalResourceHider(nsIURI
* aKey
,
1022 nsExternalResourceMap::ExternalResource
* aData
,
1025 if (aData
->mViewer
) {
1026 aData
->mViewer
->Hide();
1028 return PL_DHASH_NEXT
;
1032 nsExternalResourceMap::HideViewers()
1034 mMap
.EnumerateRead(ExternalResourceHider
, nullptr);
1037 static PLDHashOperator
1038 ExternalResourceShower(nsIURI
* aKey
,
1039 nsExternalResourceMap::ExternalResource
* aData
,
1042 if (aData
->mViewer
) {
1043 aData
->mViewer
->Show();
1045 return PL_DHASH_NEXT
;
1049 nsExternalResourceMap::ShowViewers()
1051 mMap
.EnumerateRead(ExternalResourceShower
, nullptr);
1055 TransferZoomLevels(nsIDocument
* aFromDoc
,
1056 nsIDocument
* aToDoc
)
1058 NS_ABORT_IF_FALSE(aFromDoc
&& aToDoc
,
1059 "transferring zoom levels from/to null doc");
1061 nsIPresShell
* fromShell
= aFromDoc
->GetShell();
1065 nsPresContext
* fromCtxt
= fromShell
->GetPresContext();
1069 nsIPresShell
* toShell
= aToDoc
->GetShell();
1073 nsPresContext
* toCtxt
= toShell
->GetPresContext();
1077 toCtxt
->SetFullZoom(fromCtxt
->GetFullZoom());
1078 toCtxt
->SetBaseMinFontSize(fromCtxt
->BaseMinFontSize());
1079 toCtxt
->SetTextZoom(fromCtxt
->TextZoom());
1083 TransferShowingState(nsIDocument
* aFromDoc
, nsIDocument
* aToDoc
)
1085 NS_ABORT_IF_FALSE(aFromDoc
&& aToDoc
,
1086 "transferring showing state from/to null doc");
1088 if (aFromDoc
->IsShowing()) {
1089 aToDoc
->OnPageShow(true, nullptr);
1094 nsExternalResourceMap::AddExternalResource(nsIURI
* aURI
,
1095 nsIContentViewer
* aViewer
,
1096 nsILoadGroup
* aLoadGroup
,
1097 nsIDocument
* aDisplayDocument
)
1099 NS_PRECONDITION(aURI
, "Unexpected call");
1100 NS_PRECONDITION((aViewer
&& aLoadGroup
) || (!aViewer
&& !aLoadGroup
),
1101 "Must have both or neither");
1103 nsRefPtr
<PendingLoad
> load
;
1104 mPendingLoads
.Get(aURI
, getter_AddRefs(load
));
1105 mPendingLoads
.Remove(aURI
);
1107 nsresult rv
= NS_OK
;
1109 nsCOMPtr
<nsIDocument
> doc
;
1111 doc
= aViewer
->GetDocument();
1112 NS_ASSERTION(doc
, "Must have a document");
1114 nsCOMPtr
<nsIXULDocument
> xulDoc
= do_QueryInterface(doc
);
1116 // We don't handle XUL stuff here yet.
1117 rv
= NS_ERROR_NOT_AVAILABLE
;
1119 doc
->SetDisplayDocument(aDisplayDocument
);
1121 // Make sure that hiding our viewer will tear down its presentation.
1122 aViewer
->SetSticky(false);
1124 rv
= aViewer
->Init(nullptr, nsIntRect(0, 0, 0, 0));
1125 if (NS_SUCCEEDED(rv
)) {
1126 rv
= aViewer
->Open(nullptr, nullptr);
1130 if (NS_FAILED(rv
)) {
1133 aLoadGroup
= nullptr;
1137 ExternalResource
* newResource
= new ExternalResource();
1138 mMap
.Put(aURI
, newResource
);
1140 newResource
->mDocument
= doc
;
1141 newResource
->mViewer
= aViewer
;
1142 newResource
->mLoadGroup
= aLoadGroup
;
1144 TransferZoomLevels(aDisplayDocument
, doc
);
1145 TransferShowingState(aDisplayDocument
, doc
);
1148 const nsTArray
< nsCOMPtr
<nsIObserver
> > & obs
= load
->Observers();
1149 for (uint32_t i
= 0; i
< obs
.Length(); ++i
) {
1150 obs
[i
]->Observe(doc
, "external-resource-document-created", nullptr);
1156 NS_IMPL_ISUPPORTS(nsExternalResourceMap::PendingLoad
,
1161 nsExternalResourceMap::PendingLoad::OnStartRequest(nsIRequest
*aRequest
,
1162 nsISupports
*aContext
)
1164 nsExternalResourceMap
& map
= mDisplayDocument
->ExternalResourceMap();
1165 if (map
.HaveShutDown()) {
1166 return NS_BINDING_ABORTED
;
1169 nsCOMPtr
<nsIContentViewer
> viewer
;
1170 nsCOMPtr
<nsILoadGroup
> loadGroup
;
1171 nsresult rv
= SetupViewer(aRequest
, getter_AddRefs(viewer
),
1172 getter_AddRefs(loadGroup
));
1174 // Make sure to do this no matter what
1175 nsresult rv2
= map
.AddExternalResource(mURI
, viewer
, loadGroup
,
1177 if (NS_FAILED(rv
)) {
1180 if (NS_FAILED(rv2
)) {
1181 mTargetListener
= nullptr;
1185 return mTargetListener
->OnStartRequest(aRequest
, aContext
);
1189 nsExternalResourceMap::PendingLoad::SetupViewer(nsIRequest
* aRequest
,
1190 nsIContentViewer
** aViewer
,
1191 nsILoadGroup
** aLoadGroup
)
1193 NS_PRECONDITION(!mTargetListener
, "Unexpected call to OnStartRequest");
1195 *aLoadGroup
= nullptr;
1197 nsCOMPtr
<nsIChannel
> chan(do_QueryInterface(aRequest
));
1198 NS_ENSURE_TRUE(chan
, NS_ERROR_UNEXPECTED
);
1200 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aRequest
));
1202 bool requestSucceeded
;
1203 if (NS_FAILED(httpChannel
->GetRequestSucceeded(&requestSucceeded
)) ||
1204 !requestSucceeded
) {
1205 // Bail out on this load, since it looks like we have an HTTP error page
1206 return NS_BINDING_ABORTED
;
1211 chan
->GetContentType(type
);
1213 nsCOMPtr
<nsILoadGroup
> loadGroup
;
1214 chan
->GetLoadGroup(getter_AddRefs(loadGroup
));
1216 // Give this document its own loadgroup
1217 nsCOMPtr
<nsILoadGroup
> newLoadGroup
=
1218 do_CreateInstance(NS_LOADGROUP_CONTRACTID
);
1219 NS_ENSURE_TRUE(newLoadGroup
, NS_ERROR_OUT_OF_MEMORY
);
1220 newLoadGroup
->SetLoadGroup(loadGroup
);
1222 nsCOMPtr
<nsIInterfaceRequestor
> callbacks
;
1223 loadGroup
->GetNotificationCallbacks(getter_AddRefs(callbacks
));
1225 nsCOMPtr
<nsIInterfaceRequestor
> newCallbacks
=
1226 new LoadgroupCallbacks(callbacks
);
1227 newLoadGroup
->SetNotificationCallbacks(newCallbacks
);
1229 // This is some serious hackery cribbed from docshell
1230 nsCOMPtr
<nsICategoryManager
> catMan
=
1231 do_GetService(NS_CATEGORYMANAGER_CONTRACTID
);
1232 NS_ENSURE_TRUE(catMan
, NS_ERROR_NOT_AVAILABLE
);
1233 nsXPIDLCString contractId
;
1234 nsresult rv
= catMan
->GetCategoryEntry("Gecko-Content-Viewers", type
.get(),
1235 getter_Copies(contractId
));
1236 NS_ENSURE_SUCCESS(rv
, rv
);
1237 nsCOMPtr
<nsIDocumentLoaderFactory
> docLoaderFactory
=
1238 do_GetService(contractId
);
1239 NS_ENSURE_TRUE(docLoaderFactory
, NS_ERROR_NOT_AVAILABLE
);
1241 nsCOMPtr
<nsIContentViewer
> viewer
;
1242 nsCOMPtr
<nsIStreamListener
> listener
;
1243 rv
= docLoaderFactory
->CreateInstance("external-resource", chan
, newLoadGroup
,
1244 type
.get(), nullptr, nullptr,
1245 getter_AddRefs(listener
),
1246 getter_AddRefs(viewer
));
1247 NS_ENSURE_SUCCESS(rv
, rv
);
1248 NS_ENSURE_TRUE(viewer
, NS_ERROR_UNEXPECTED
);
1250 nsCOMPtr
<nsIParser
> parser
= do_QueryInterface(listener
);
1252 /// We don't want to deal with the various fake documents yet
1253 return NS_ERROR_NOT_IMPLEMENTED
;
1256 // We can't handle HTML and other weird things here yet.
1257 nsIContentSink
* sink
= parser
->GetContentSink();
1258 nsCOMPtr
<nsIXMLContentSink
> xmlSink
= do_QueryInterface(sink
);
1260 return NS_ERROR_NOT_IMPLEMENTED
;
1263 listener
.swap(mTargetListener
);
1264 viewer
.forget(aViewer
);
1265 newLoadGroup
.forget(aLoadGroup
);
1270 nsExternalResourceMap::PendingLoad::OnDataAvailable(nsIRequest
* aRequest
,
1271 nsISupports
* aContext
,
1272 nsIInputStream
* aStream
,
1276 NS_PRECONDITION(mTargetListener
, "Shouldn't be getting called!");
1277 if (mDisplayDocument
->ExternalResourceMap().HaveShutDown()) {
1278 return NS_BINDING_ABORTED
;
1280 return mTargetListener
->OnDataAvailable(aRequest
, aContext
, aStream
, aOffset
,
1285 nsExternalResourceMap::PendingLoad::OnStopRequest(nsIRequest
* aRequest
,
1286 nsISupports
* aContext
,
1289 // mTargetListener might be null if SetupViewer or AddExternalResource failed
1290 if (mTargetListener
) {
1291 nsCOMPtr
<nsIStreamListener
> listener
;
1292 mTargetListener
.swap(listener
);
1293 return listener
->OnStopRequest(aRequest
, aContext
, aStatus
);
1300 nsExternalResourceMap::PendingLoad::StartLoad(nsIURI
* aURI
,
1301 nsINode
* aRequestingNode
)
1303 NS_PRECONDITION(aURI
, "Must have a URI");
1304 NS_PRECONDITION(aRequestingNode
, "Must have a node");
1306 // Time to start a load. First, the security checks.
1308 nsIPrincipal
* requestingPrincipal
= aRequestingNode
->NodePrincipal();
1310 nsresult rv
= nsContentUtils::GetSecurityManager()->
1311 CheckLoadURIWithPrincipal(requestingPrincipal
, aURI
,
1312 nsIScriptSecurityManager::STANDARD
);
1313 NS_ENSURE_SUCCESS(rv
, rv
);
1315 // Allow data URIs and other URI's that inherit their principal by passing
1316 // true as the 3rd argument of CheckMayLoad, since we want
1317 // to allow external resources from data URIs regardless of the difference
1319 rv
= requestingPrincipal
->CheckMayLoad(aURI
, true, true);
1320 NS_ENSURE_SUCCESS(rv
, rv
);
1322 int16_t shouldLoad
= nsIContentPolicy::ACCEPT
;
1323 rv
= NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OTHER
,
1325 requestingPrincipal
,
1327 EmptyCString(), //mime guess
1330 nsContentUtils::GetContentPolicy(),
1331 nsContentUtils::GetSecurityManager());
1332 if (NS_FAILED(rv
)) return rv
;
1333 if (NS_CP_REJECTED(shouldLoad
)) {
1334 // Disallowed by content policy
1335 return NS_ERROR_CONTENT_BLOCKED
;
1338 nsIDocument
* doc
= aRequestingNode
->OwnerDoc();
1340 nsCOMPtr
<nsIInterfaceRequestor
> req
= nsContentUtils::GetSameOriginChecker();
1341 NS_ENSURE_TRUE(req
, NS_ERROR_OUT_OF_MEMORY
);
1343 nsCOMPtr
<nsILoadGroup
> loadGroup
= doc
->GetDocumentLoadGroup();
1344 nsCOMPtr
<nsIChannel
> channel
;
1345 rv
= NS_NewChannel(getter_AddRefs(channel
),
1348 nsILoadInfo::SEC_NORMAL
,
1349 nsIContentPolicy::TYPE_OTHER
,
1353 NS_ENSURE_SUCCESS(rv
, rv
);
1357 return channel
->AsyncOpen(this, nullptr);
1360 NS_IMPL_ISUPPORTS(nsExternalResourceMap::LoadgroupCallbacks
,
1361 nsIInterfaceRequestor
)
1363 #define IMPL_SHIM(_i) \
1364 NS_IMPL_ISUPPORTS(nsExternalResourceMap::LoadgroupCallbacks::_i##Shim, _i)
1366 IMPL_SHIM(nsILoadContext
)
1367 IMPL_SHIM(nsIProgressEventSink
)
1368 IMPL_SHIM(nsIChannelEventSink
)
1369 IMPL_SHIM(nsISecurityEventSink
)
1370 IMPL_SHIM(nsIApplicationCacheContainer
)
1374 #define IID_IS(_i) aIID.Equals(NS_GET_IID(_i))
1376 #define TRY_SHIM(_i) \
1379 nsCOMPtr<_i> real = do_GetInterface(mCallbacks); \
1381 return NS_NOINTERFACE; \
1383 nsCOMPtr<_i> shim = new _i##Shim(this, real); \
1385 return NS_ERROR_OUT_OF_MEMORY; \
1387 shim.forget(aSink); \
1393 nsExternalResourceMap::LoadgroupCallbacks::GetInterface(const nsIID
& aIID
,
1397 (IID_IS(nsIPrompt
) || IID_IS(nsIAuthPrompt
) || IID_IS(nsIAuthPrompt2
) ||
1398 IID_IS(nsITabChild
))) {
1399 return mCallbacks
->GetInterface(aIID
, aSink
);
1404 TRY_SHIM(nsILoadContext
);
1405 TRY_SHIM(nsIProgressEventSink
);
1406 TRY_SHIM(nsIChannelEventSink
);
1407 TRY_SHIM(nsISecurityEventSink
);
1408 TRY_SHIM(nsIApplicationCacheContainer
);
1410 return NS_NOINTERFACE
;
1416 nsExternalResourceMap::ExternalResource::~ExternalResource()
1419 mViewer
->Close(nullptr);
1424 // ==================================================================
1426 // ==================================================================
1428 // If we ever have an nsIDocumentObserver notification for stylesheet title
1429 // changes we should update the list from that instead of overriding
1431 class nsDOMStyleSheetSetList MOZ_FINAL
: public DOMStringList
1434 explicit nsDOMStyleSheetSetList(nsIDocument
* aDocument
);
1438 mDocument
= nullptr;
1441 virtual void EnsureFresh() MOZ_OVERRIDE
;
1444 nsIDocument
* mDocument
; // Our document; weak ref. It'll let us know if it
1448 nsDOMStyleSheetSetList::nsDOMStyleSheetSetList(nsIDocument
* aDocument
)
1449 : mDocument(aDocument
)
1451 NS_ASSERTION(mDocument
, "Must have document!");
1455 nsDOMStyleSheetSetList::EnsureFresh()
1457 MOZ_ASSERT(NS_IsMainThread());
1462 return; // Spec says "no exceptions", and we have no style sets if we have
1463 // no document, for sure
1466 int32_t count
= mDocument
->GetNumberOfStyleSheets();
1468 for (int32_t index
= 0; index
< count
; index
++) {
1469 nsIStyleSheet
* sheet
= mDocument
->GetStyleSheetAt(index
);
1470 NS_ASSERTION(sheet
, "Null sheet in sheet list!");
1471 sheet
->GetTitle(title
);
1472 if (!title
.IsEmpty() && !mNames
.Contains(title
) && !Add(title
)) {
1478 // ==================================================================
1479 nsIDocument::SelectorCache::SelectorCache()
1480 : nsExpirationTracker
<SelectorCacheKey
, 4>(1000) { }
1482 // CacheList takes ownership of aSelectorList.
1483 void nsIDocument::SelectorCache::CacheList(const nsAString
& aSelector
,
1484 nsCSSSelectorList
* aSelectorList
)
1486 SelectorCacheKey
* key
= new SelectorCacheKey(aSelector
);
1487 mTable
.Put(key
->mKey
, aSelectorList
);
1491 class nsIDocument::SelectorCacheKeyDeleter MOZ_FINAL
: public nsRunnable
1494 explicit SelectorCacheKeyDeleter(SelectorCacheKey
* aToDelete
)
1495 : mSelector(aToDelete
)
1497 MOZ_COUNT_CTOR(SelectorCacheKeyDeleter
);
1501 ~SelectorCacheKeyDeleter()
1503 MOZ_COUNT_DTOR(SelectorCacheKeyDeleter
);
1513 nsAutoPtr
<SelectorCacheKey
> mSelector
;
1516 void nsIDocument::SelectorCache::NotifyExpired(SelectorCacheKey
* aSelector
)
1518 RemoveObject(aSelector
);
1519 mTable
.Remove(aSelector
->mKey
);
1520 nsCOMPtr
<nsIRunnable
> runnable
= new SelectorCacheKeyDeleter(aSelector
);
1521 NS_DispatchToCurrentThread(runnable
);
1525 struct nsIDocument::FrameRequest
1527 FrameRequest(const FrameRequestCallbackHolder
& aCallback
,
1529 mCallback(aCallback
),
1533 // Conversion operator so that we can append these to a
1534 // FrameRequestCallbackList
1535 operator const FrameRequestCallbackHolder
& () const {
1539 // Comparator operators to allow RemoveElementSorted with an
1540 // integer argument on arrays of FrameRequest
1541 bool operator==(int32_t aHandle
) const {
1542 return mHandle
== aHandle
;
1544 bool operator<(int32_t aHandle
) const {
1545 return mHandle
< aHandle
;
1548 FrameRequestCallbackHolder mCallback
;
1552 static already_AddRefed
<mozilla::dom::NodeInfo
> nullNodeInfo
;
1554 // ==================================================================
1556 // ==================================================================
1557 nsIDocument::nsIDocument()
1558 : nsINode(nullNodeInfo
),
1559 mReferrerPolicySet(false),
1560 mReferrerPolicy(mozilla::net::RP_Default
),
1561 mCharacterSet(NS_LITERAL_CSTRING("ISO-8859-1")),
1562 mNodeInfoManager(nullptr),
1563 mCompatMode(eCompatibility_FullStandards
),
1564 mVisibilityState(dom::VisibilityState::Hidden
),
1565 mIsInitialDocumentInWindow(false),
1566 mMayStartLayout(true),
1568 mRemovedFromDocShell(false),
1569 // mAllowDNSPrefetch starts true, so that we can always reliably && it
1570 // with various values that might disable it. Since we never prefetch
1571 // unless we get a window, and in that case the docshell value will get
1572 // &&-ed in, this is safe.
1573 mAllowDNSPrefetch(true),
1574 mIsBeingUsedAsImage(false),
1575 mHasLinksToUpdate(false),
1577 mDidFireDOMContentLoaded(true)
1581 PR_INIT_CLIST(&mDOMMediaQueryLists
);
1584 // NOTE! nsDocument::operator new() zeroes out all members, so don't
1585 // bother initializing members to 0.
1587 nsDocument::nsDocument(const char* aContentType
)
1589 , mAnimatingImages(true)
1590 , mViewportType(Unknown
)
1592 SetContentTypeInternal(nsDependentCString(aContentType
));
1595 if (!gDocumentLeakPRLog
)
1596 gDocumentLeakPRLog
= PR_NewLogModule("DocumentLeak");
1598 if (gDocumentLeakPRLog
)
1599 PR_LOG(gDocumentLeakPRLog
, PR_LOG_DEBUG
,
1600 ("DOCUMENT %p created", this));
1603 gCspPRLog
= PR_NewLogModule("CSP");
1606 // Start out mLastStyleSheetSet as null, per spec
1607 SetDOMStringToNull(mLastStyleSheetSet
);
1609 if (!sProcessingStack
) {
1610 sProcessingStack
.emplace();
1611 // Add the base queue sentinel to the processing stack.
1612 sProcessingStack
->AppendElement((CustomElementData
*) nullptr);
1616 static PLDHashOperator
1617 ClearAllBoxObjects(nsIContent
* aKey
, nsPIBoxObject
* aBoxObject
, void* aUserArg
)
1620 aBoxObject
->Clear();
1622 return PL_DHASH_NEXT
;
1625 nsIDocument::~nsIDocument()
1627 NS_ABORT_IF_FALSE(PR_CLIST_IS_EMPTY(&mDOMMediaQueryLists
),
1628 "must not have media query lists left");
1630 if (mNodeInfoManager
) {
1631 mNodeInfoManager
->DropDocumentReference();
1636 nsDocument::~nsDocument()
1639 if (gDocumentLeakPRLog
)
1640 PR_LOG(gDocumentLeakPRLog
, PR_LOG_DEBUG
,
1641 ("DOCUMENT %p destroyed", this));
1644 NS_ASSERTION(!mIsShowing
, "Destroying a currently-showing document");
1646 // Note: This assert is only non-fatal because mochitest-bc triggers
1647 // it... as well as the preceding assert about !mIsShowing.
1648 NS_ASSERTION(!mObservingAppThemeChanged
,
1649 "Document leaked to shutdown, then the observer service dropped "
1650 "its ref to us so we were able to go away.");
1652 if (IsTopLevelContentDocument()) {
1653 //don't report for about: pages
1654 nsCOMPtr
<nsIPrincipal
> principal
= GetPrincipal();
1655 nsCOMPtr
<nsIURI
> uri
;
1656 principal
->GetURI(getter_AddRefs(uri
));
1657 bool isAboutScheme
= true;
1659 uri
->SchemeIs("about", &isAboutScheme
);
1662 if (!isAboutScheme
) {
1663 // Record the page load
1664 uint32_t pageLoaded
= 1;
1665 Accumulate(Telemetry::MIXED_CONTENT_UNBLOCK_COUNTER
, pageLoaded
);
1666 // Record the mixed content status of the docshell in Telemetry
1668 NO_MIXED_CONTENT
= 0, // There is no Mixed Content on the page
1669 MIXED_DISPLAY_CONTENT
= 1, // The page attempted to load Mixed Display Content
1670 MIXED_ACTIVE_CONTENT
= 2, // The page attempted to load Mixed Active Content
1671 MIXED_DISPLAY_AND_ACTIVE_CONTENT
= 3 // The page attempted to load Mixed Display & Mixed Active Content
1674 bool mixedActiveLoaded
= GetHasMixedActiveContentLoaded();
1675 bool mixedActiveBlocked
= GetHasMixedActiveContentBlocked();
1677 bool mixedDisplayLoaded
= GetHasMixedDisplayContentLoaded();
1678 bool mixedDisplayBlocked
= GetHasMixedDisplayContentBlocked();
1680 bool hasMixedDisplay
= (mixedDisplayBlocked
|| mixedDisplayLoaded
);
1681 bool hasMixedActive
= (mixedActiveBlocked
|| mixedActiveLoaded
);
1683 uint32_t mixedContentLevel
= NO_MIXED_CONTENT
;
1684 if (hasMixedDisplay
&& hasMixedActive
) {
1685 mixedContentLevel
= MIXED_DISPLAY_AND_ACTIVE_CONTENT
;
1686 } else if (hasMixedActive
){
1687 mixedContentLevel
= MIXED_ACTIVE_CONTENT
;
1688 } else if (hasMixedDisplay
) {
1689 mixedContentLevel
= MIXED_DISPLAY_CONTENT
;
1691 Accumulate(Telemetry::MIXED_CONTENT_PAGE_LOAD
, mixedContentLevel
);
1695 mInDestructor
= true;
1696 mInUnlinkOrDeletion
= true;
1698 mRegistry
= nullptr;
1700 mozilla::DropJSObjects(this);
1702 // Clear mObservers to keep it in sync with the mutationobserver list
1705 if (mStyleSheetSetList
) {
1706 mStyleSheetSetList
->Disconnect();
1709 if (mAnimationController
) {
1710 mAnimationController
->Disconnect();
1713 mParentDocument
= nullptr;
1715 // Kill the subdocument map, doing this will release its strong
1716 // references, if any.
1717 if (mSubDocuments
) {
1718 PL_DHashTableDestroy(mSubDocuments
);
1720 mSubDocuments
= nullptr;
1723 // Destroy link map now so we don't waste time removing
1725 DestroyElementMaps();
1727 nsAutoScriptBlocker scriptBlocker
;
1729 int32_t indx
; // must be signed
1730 uint32_t count
= mChildren
.ChildCount();
1731 for (indx
= int32_t(count
) - 1; indx
>= 0; --indx
) {
1732 mChildren
.ChildAt(indx
)->UnbindFromTree();
1733 mChildren
.RemoveChildAt(indx
);
1735 mFirstChild
= nullptr;
1736 mCachedRootElement
= nullptr;
1738 // Let the stylesheets know we're going away
1739 indx
= mStyleSheets
.Count();
1740 while (--indx
>= 0) {
1741 mStyleSheets
[indx
]->SetOwningDocument(nullptr);
1743 if (mAttrStyleSheet
) {
1744 mAttrStyleSheet
->SetOwningDocument(nullptr);
1746 // We don't own the mOnDemandBuiltInUASheets, so we don't need to reset them.
1748 if (mListenerManager
) {
1749 mListenerManager
->Disconnect();
1750 UnsetFlags(NODE_HAS_LISTENERMANAGER
);
1753 if (mScriptLoader
) {
1754 mScriptLoader
->DropDocumentReference();
1758 // Could be null here if Init() failed or if we have been unlinked.
1759 mCSSLoader
->DropDocumentReference();
1762 if (mStyleImageLoader
) {
1763 mStyleImageLoader
->DropDocumentReference();
1768 if (mBoxObjectTable
) {
1769 mBoxObjectTable
->EnumerateRead(ClearAllBoxObjects
, nullptr);
1770 delete mBoxObjectTable
;
1773 mPendingTitleChangeEvent
.Revoke();
1775 for (uint32_t i
= 0; i
< mHostObjectURIs
.Length(); ++i
) {
1776 nsHostObjectProtocolHandler::RemoveDataEntry(mHostObjectURIs
[i
]);
1779 // We don't want to leave residual locks on images. Make sure we're in an
1780 // unlocked state, and then clear the table.
1781 SetImageLockingState(false);
1782 mImageTracker
.Clear();
1787 NS_INTERFACE_TABLE_HEAD(nsDocument
)
1788 NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
1789 NS_INTERFACE_TABLE_BEGIN
1790 NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(nsDocument
, nsISupports
, nsINode
)
1791 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsINode
)
1792 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIDocument
)
1793 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIDOMDocument
)
1794 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIDOMNode
)
1795 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIDOMDocumentXBL
)
1796 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIScriptObjectPrincipal
)
1797 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIDOMEventTarget
)
1798 NS_INTERFACE_TABLE_ENTRY(nsDocument
, mozilla::dom::EventTarget
)
1799 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsISupportsWeakReference
)
1800 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIRadioGroupContainer
)
1801 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIMutationObserver
)
1802 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIApplicationCacheContainer
)
1803 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIObserver
)
1804 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIDOMXPathEvaluator
)
1805 NS_INTERFACE_TABLE_END
1806 NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsDocument
)
1807 NS_INTERFACE_MAP_END
1810 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDocument
)
1811 NS_IMETHODIMP_(MozExternalRefCountType
)
1812 nsDocument::Release()
1814 NS_PRECONDITION(0 != mRefCnt
, "dup release");
1815 NS_ASSERT_OWNINGTHREAD(nsDocument
);
1816 nsISupports
* base
= NS_CYCLE_COLLECTION_CLASSNAME(nsDocument
)::Upcast(this);
1817 bool shouldDelete
= false;
1818 nsrefcnt count
= mRefCnt
.decr(base
, &shouldDelete
);
1819 NS_LOG_RELEASE(this, count
, "nsDocument");
1821 if (mStackRefCnt
&& !mNeedsReleaseAfterStackRefCntRelease
) {
1822 mNeedsReleaseAfterStackRefCntRelease
= true;
1824 return mRefCnt
.get();
1827 nsNodeUtils::LastRelease(this);
1830 mRefCnt
.stabilizeForDeletion();
1831 DeleteCycleCollectable();
1837 NS_IMETHODIMP_(void)
1838 nsDocument::DeleteCycleCollectable()
1843 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsDocument
)
1844 if (Element::CanSkip(tmp
, aRemovingAllowed
)) {
1845 EventListenerManager
* elm
= tmp
->GetExistingListenerManager();
1851 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
1853 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsDocument
)
1854 return Element::CanSkipInCC(tmp
);
1855 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
1857 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsDocument
)
1858 return Element::CanSkipThis(tmp
);
1859 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
1861 static PLDHashOperator
1862 SubDocTraverser(PLDHashTable
*table
, PLDHashEntryHdr
*hdr
, uint32_t number
,
1865 SubDocMapEntry
*entry
= static_cast<SubDocMapEntry
*>(hdr
);
1866 nsCycleCollectionTraversalCallback
*cb
=
1867 static_cast<nsCycleCollectionTraversalCallback
*>(arg
);
1869 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
, "mSubDocuments entry->mKey");
1870 cb
->NoteXPCOMChild(entry
->mKey
);
1871 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
, "mSubDocuments entry->mSubDocument");
1872 cb
->NoteXPCOMChild(entry
->mSubDocument
);
1874 return PL_DHASH_NEXT
;
1877 static PLDHashOperator
1878 RadioGroupsTraverser(const nsAString
& aKey
, nsRadioGroupStruct
* aData
,
1881 nsCycleCollectionTraversalCallback
*cb
=
1882 static_cast<nsCycleCollectionTraversalCallback
*>(aClosure
);
1884 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
1885 "mRadioGroups entry->mSelectedRadioButton");
1886 cb
->NoteXPCOMChild(ToSupports(aData
->mSelectedRadioButton
));
1888 uint32_t i
, count
= aData
->mRadioButtons
.Count();
1889 for (i
= 0; i
< count
; ++i
) {
1890 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
1891 "mRadioGroups entry->mRadioButtons[i]");
1892 cb
->NoteXPCOMChild(aData
->mRadioButtons
[i
]);
1895 return PL_DHASH_NEXT
;
1898 static PLDHashOperator
1899 BoxObjectTraverser(nsIContent
* key
, nsPIBoxObject
* boxObject
, void* userArg
)
1901 nsCycleCollectionTraversalCallback
*cb
=
1902 static_cast<nsCycleCollectionTraversalCallback
*>(userArg
);
1904 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
, "mBoxObjectTable entry");
1905 cb
->NoteXPCOMChild(boxObject
);
1907 return PL_DHASH_NEXT
;
1910 static PLDHashOperator
1911 IdentifierMapEntryTraverse(nsIdentifierMapEntry
*aEntry
, void *aArg
)
1913 nsCycleCollectionTraversalCallback
*cb
=
1914 static_cast<nsCycleCollectionTraversalCallback
*>(aArg
);
1915 aEntry
->Traverse(cb
);
1916 return PL_DHASH_NEXT
;
1919 static const char* kNSURIs
[] = {
1932 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument
)
1933 if (MOZ_UNLIKELY(cb
.WantDebugInfo())) {
1935 nsAutoCString loadedAsData
;
1936 if (tmp
->IsLoadedAsData()) {
1937 loadedAsData
.AssignLiteral("data");
1939 loadedAsData
.AssignLiteral("normal");
1941 uint32_t nsid
= tmp
->GetDefaultNamespaceID();
1943 if (tmp
->mDocumentURI
)
1944 tmp
->mDocumentURI
->GetSpec(uri
);
1945 if (nsid
< ArrayLength(kNSURIs
)) {
1946 PR_snprintf(name
, sizeof(name
), "nsDocument %s %s %s",
1947 loadedAsData
.get(), kNSURIs
[nsid
], uri
.get());
1950 PR_snprintf(name
, sizeof(name
), "nsDocument %s %s",
1951 loadedAsData
.get(), uri
.get());
1953 cb
.DescribeRefCountedNode(tmp
->mRefCnt
.get(), name
);
1956 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsDocument
, tmp
->mRefCnt
.get())
1959 // Always need to traverse script objects, so do that before we check
1960 // if we're uncollectable.
1961 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
1963 if (!nsINode::Traverse(tmp
, cb
)) {
1964 return NS_SUCCESS_INTERRUPTED_TRAVERSE
;
1967 tmp
->mIdentifierMap
.EnumerateEntries(IdentifierMapEntryTraverse
, &cb
);
1969 tmp
->mExternalResourceMap
.Traverse(&cb
);
1971 // Traverse the mChildren nsAttrAndChildArray.
1972 for (int32_t indx
= int32_t(tmp
->mChildren
.ChildCount()); indx
> 0; --indx
) {
1973 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mChildren[i]");
1974 cb
.NoteXPCOMChild(tmp
->mChildren
.ChildAt(indx
- 1));
1977 // Traverse all nsIDocument pointer members.
1978 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSecurityInfo
)
1979 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDisplayDocument
)
1981 // Traverse all nsDocument nsCOMPtrs.
1982 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParser
)
1983 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptGlobalObject
)
1984 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager
)
1985 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets
)
1986 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetSetList
)
1987 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptLoader
)
1988 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMasterDocument
)
1989 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImportManager
)
1991 tmp
->mRadioGroups
.EnumerateRead(RadioGroupsTraverser
, &cb
);
1993 // The boxobject for an element will only exist as long as it's in the
1994 // document, so we'll traverse the table here instead of from the element.
1995 if (tmp
->mBoxObjectTable
) {
1996 tmp
->mBoxObjectTable
->EnumerateRead(BoxObjectTraverser
, &cb
);
1999 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannel
)
2000 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleAttrStyleSheet
)
2001 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mXPathEvaluator
)
2002 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLayoutHistoryState
)
2003 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnloadBlocker
)
2004 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFirstBaseNodeWithHref
)
2005 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMImplementation
)
2006 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImageMaps
)
2007 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOriginalDocument
)
2008 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedEncoder
)
2009 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStateObjectCached
)
2010 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUndoManager
)
2011 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnimationTimeline
)
2012 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingPlayerTracker
)
2013 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTemplateContentsOwner
)
2014 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildrenCollection
)
2015 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRegistry
)
2016 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnonymousContents
)
2018 // Traverse all our nsCOMArrays.
2019 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets
)
2020 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnDemandBuiltInUASheets
)
2021 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPreloadingImages
)
2023 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSubImportLinks
)
2025 for (uint32_t i
= 0; i
< tmp
->mFrameRequestCallbacks
.Length(); ++i
) {
2026 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mFrameRequestCallbacks[i]");
2027 cb
.NoteXPCOMChild(tmp
->mFrameRequestCallbacks
[i
].mCallback
.GetISupports());
2030 // Traverse animation components
2031 if (tmp
->mAnimationController
) {
2032 tmp
->mAnimationController
->Traverse(&cb
);
2035 if (tmp
->mSubDocuments
&& tmp
->mSubDocuments
->ops
) {
2036 PL_DHashTableEnumerate(tmp
->mSubDocuments
, SubDocTraverser
, &cb
);
2039 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCSSLoader
)
2041 for (uint32_t i
= 0; i
< tmp
->mHostObjectURIs
.Length(); ++i
) {
2042 nsHostObjectProtocolHandler::Traverse(tmp
->mHostObjectURIs
[i
], cb
);
2045 // We own only the items in mDOMMediaQueryLists that have listeners;
2046 // this reference is managed by their AddListener and RemoveListener
2048 for (PRCList
*l
= PR_LIST_HEAD(&tmp
->mDOMMediaQueryLists
);
2049 l
!= &tmp
->mDOMMediaQueryLists
; l
= PR_NEXT_LINK(l
)) {
2050 MediaQueryList
*mql
= static_cast<MediaQueryList
*>(l
);
2051 if (mql
->HasListeners()) {
2052 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mDOMMediaQueryLists item");
2053 cb
.NoteXPCOMChild(mql
);
2056 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
2058 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocument
)
2060 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDocument
)
2061 if (tmp
->PreservingWrapper()) {
2062 NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mExpandoAndGeneration
.expando
);
2064 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
2065 NS_IMPL_CYCLE_COLLECTION_TRACE_END
2068 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument
)
2069 tmp
->mInUnlinkOrDeletion
= true;
2071 // Clear out our external resources
2072 tmp
->mExternalResourceMap
.Shutdown();
2074 nsAutoScriptBlocker scriptBlocker
;
2076 nsINode::Unlink(tmp
);
2078 // Unlink the mChildren nsAttrAndChildArray.
2079 for (int32_t indx
= int32_t(tmp
->mChildren
.ChildCount()) - 1;
2080 indx
>= 0; --indx
) {
2081 tmp
->mChildren
.ChildAt(indx
)->UnbindFromTree();
2082 tmp
->mChildren
.RemoveChildAt(indx
);
2084 tmp
->mFirstChild
= nullptr;
2086 NS_IMPL_CYCLE_COLLECTION_UNLINK(mXPathEvaluator
)
2087 tmp
->mCachedRootElement
= nullptr; // Avoid a dangling pointer
2088 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDisplayDocument
)
2089 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFirstBaseNodeWithHref
)
2090 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMImplementation
)
2091 NS_IMPL_CYCLE_COLLECTION_UNLINK(mImageMaps
)
2092 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOriginalDocument
)
2093 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedEncoder
)
2094 NS_IMPL_CYCLE_COLLECTION_UNLINK(mUndoManager
)
2095 NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnimationTimeline
)
2096 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingPlayerTracker
)
2097 NS_IMPL_CYCLE_COLLECTION_UNLINK(mTemplateContentsOwner
)
2098 NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildrenCollection
)
2099 NS_IMPL_CYCLE_COLLECTION_UNLINK(mRegistry
)
2100 NS_IMPL_CYCLE_COLLECTION_UNLINK(mMasterDocument
)
2101 NS_IMPL_CYCLE_COLLECTION_UNLINK(mImportManager
)
2102 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSubImportLinks
)
2104 tmp
->mParentDocument
= nullptr;
2106 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPreloadingImages
)
2109 if (tmp
->mBoxObjectTable
) {
2110 tmp
->mBoxObjectTable
->EnumerateRead(ClearAllBoxObjects
, nullptr);
2111 delete tmp
->mBoxObjectTable
;
2112 tmp
->mBoxObjectTable
= nullptr;
2115 if (tmp
->mListenerManager
) {
2116 tmp
->mListenerManager
->Disconnect();
2117 tmp
->UnsetFlags(NODE_HAS_LISTENERMANAGER
);
2118 tmp
->mListenerManager
= nullptr;
2121 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets
)
2123 if (tmp
->mStyleSheetSetList
) {
2124 tmp
->mStyleSheetSetList
->Disconnect();
2125 tmp
->mStyleSheetSetList
= nullptr;
2128 if (tmp
->mSubDocuments
) {
2129 PL_DHashTableDestroy(tmp
->mSubDocuments
);
2130 tmp
->mSubDocuments
= nullptr;
2133 tmp
->mFrameRequestCallbacks
.Clear();
2135 tmp
->mRadioGroups
.Clear();
2137 // nsDocument has a pretty complex destructor, so we're going to
2138 // assume that *most* cycles you actually want to break somewhere
2139 // else, and not unlink an awful lot here.
2141 tmp
->mIdentifierMap
.Clear();
2142 tmp
->mExpandoAndGeneration
.Unlink();
2144 if (tmp
->mAnimationController
) {
2145 tmp
->mAnimationController
->Unlink();
2148 tmp
->mPendingTitleChangeEvent
.Revoke();
2150 if (tmp
->mCSSLoader
) {
2151 tmp
->mCSSLoader
->DropDocumentReference();
2152 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCSSLoader
)
2155 for (uint32_t i
= 0; i
< tmp
->mHostObjectURIs
.Length(); ++i
) {
2156 nsHostObjectProtocolHandler::RemoveDataEntry(tmp
->mHostObjectURIs
[i
]);
2159 // We own only the items in mDOMMediaQueryLists that have listeners;
2160 // this reference is managed by their AddListener and RemoveListener
2162 for (PRCList
*l
= PR_LIST_HEAD(&tmp
->mDOMMediaQueryLists
);
2163 l
!= &tmp
->mDOMMediaQueryLists
; ) {
2164 PRCList
*next
= PR_NEXT_LINK(l
);
2165 MediaQueryList
*mql
= static_cast<MediaQueryList
*>(l
);
2166 mql
->RemoveAllListeners();
2170 tmp
->mInUnlinkOrDeletion
= false;
2171 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
2173 static bool sPrefsInitialized
= false;
2174 static uint32_t sOnloadDecodeLimit
= 0;
2179 if (mCSSLoader
|| mStyleImageLoader
|| mNodeInfoManager
|| mScriptLoader
) {
2180 return NS_ERROR_ALREADY_INITIALIZED
;
2183 if (!sPrefsInitialized
) {
2184 sPrefsInitialized
= true;
2185 Preferences::AddUintVarCache(&sOnloadDecodeLimit
, "image.onload.decode.limit", 0);
2188 // Force initialization.
2189 nsINode::nsSlots
* slots
= Slots();
2191 // Prepend self as mutation-observer whether we need it or not (some
2192 // subclasses currently do, other don't). This is because the code in
2193 // nsNodeUtils always notifies the first observer first, expecting the
2194 // first observer to be the document.
2195 NS_ENSURE_TRUE(slots
->mMutationObservers
.PrependElementUnlessExists(static_cast<nsIMutationObserver
*>(this)),
2196 NS_ERROR_OUT_OF_MEMORY
);
2199 mOnloadBlocker
= new nsOnloadBlocker();
2200 mCSSLoader
= new mozilla::css::Loader(this);
2201 // Assume we're not quirky, until we know otherwise
2202 mCSSLoader
->SetCompatibilityMode(eCompatibility_FullStandards
);
2204 mStyleImageLoader
= new mozilla::css::ImageLoader(this);
2206 mNodeInfoManager
= new nsNodeInfoManager();
2207 nsresult rv
= mNodeInfoManager
->Init(this);
2208 NS_ENSURE_SUCCESS(rv
, rv
);
2210 // mNodeInfo keeps NodeInfoManager alive!
2211 mNodeInfo
= mNodeInfoManager
->GetDocumentNodeInfo();
2212 NS_ENSURE_TRUE(mNodeInfo
, NS_ERROR_OUT_OF_MEMORY
);
2213 NS_ABORT_IF_FALSE(mNodeInfo
->NodeType() == nsIDOMNode::DOCUMENT_NODE
,
2214 "Bad NodeType in aNodeInfo");
2216 NS_ASSERTION(OwnerDoc() == this, "Our nodeinfo is busted!");
2218 // If after creation the owner js global is not set for a document
2219 // we use the default compartment for this document, instead of creating
2220 // wrapper in some random compartment when the document is exposed to js
2222 nsCOMPtr
<nsIGlobalObject
> global
= xpc::NativeGlobal(xpc::PrivilegedJunkScope());
2223 NS_ENSURE_TRUE(global
, NS_ERROR_FAILURE
);
2224 mScopeObject
= do_GetWeakReference(global
);
2225 MOZ_ASSERT(mScopeObject
);
2227 mScriptLoader
= new nsScriptLoader(this);
2229 mozilla::HoldJSObjects(this);
2235 nsIDocument::DeleteAllProperties()
2237 for (uint32_t i
= 0; i
< GetPropertyTableCount(); ++i
) {
2238 PropertyTable(i
)->DeleteAllProperties();
2243 nsIDocument::DeleteAllPropertiesFor(nsINode
* aNode
)
2245 for (uint32_t i
= 0; i
< GetPropertyTableCount(); ++i
) {
2246 PropertyTable(i
)->DeleteAllPropertiesFor(aNode
);
2251 nsIDocument::GetExtraPropertyTable(uint16_t aCategory
)
2253 NS_ASSERTION(aCategory
> 0, "Category 0 should have already been handled");
2254 while (aCategory
>= mExtraPropertyTables
.Length() + 1) {
2255 mExtraPropertyTables
.AppendElement(new nsPropertyTable());
2257 return mExtraPropertyTables
[aCategory
- 1];
2261 nsIDocument::IsVisibleConsideringAncestors() const
2263 const nsIDocument
*parent
= this;
2265 if (!parent
->IsVisible()) {
2268 } while ((parent
= parent
->GetParentDocument()));
2274 nsDocument::Reset(nsIChannel
* aChannel
, nsILoadGroup
* aLoadGroup
)
2276 nsCOMPtr
<nsIURI
> uri
;
2277 nsCOMPtr
<nsIPrincipal
> principal
;
2279 // Note: this code is duplicated in XULDocument::StartDocumentLoad and
2280 // nsScriptSecurityManager::GetChannelResultPrincipal.
2281 // Note: this should match nsDocShell::OnLoadingSite
2282 NS_GetFinalChannelURI(aChannel
, getter_AddRefs(uri
));
2284 nsIScriptSecurityManager
*securityManager
=
2285 nsContentUtils::GetSecurityManager();
2286 if (securityManager
) {
2287 securityManager
->GetChannelResultPrincipal(aChannel
,
2288 getter_AddRefs(principal
));
2292 ResetToURI(uri
, aLoadGroup
, principal
);
2294 nsCOMPtr
<nsIPropertyBag2
> bag
= do_QueryInterface(aChannel
);
2296 nsCOMPtr
<nsIURI
> baseURI
;
2297 bag
->GetPropertyAsInterface(NS_LITERAL_STRING("baseURI"),
2298 NS_GET_IID(nsIURI
), getter_AddRefs(baseURI
));
2300 mDocumentBaseURI
= baseURI
;
2301 mChromeXHRDocBaseURI
= baseURI
;
2305 mChannel
= aChannel
;
2309 nsDocument::ResetToURI(nsIURI
*aURI
, nsILoadGroup
*aLoadGroup
,
2310 nsIPrincipal
* aPrincipal
)
2312 NS_PRECONDITION(aURI
, "Null URI passed to ResetToURI");
2315 if (gDocumentLeakPRLog
&& PR_LOG_TEST(gDocumentLeakPRLog
, PR_LOG_DEBUG
)) {
2317 aURI
->GetSpec(spec
);
2318 PR_LogPrint("DOCUMENT %p ResetToURI %s", this, spec
.get());
2322 mSecurityInfo
= nullptr;
2324 mDocumentLoadGroup
= nullptr;
2326 // Delete references to sub-documents and kill the subdocument map,
2327 // if any. It holds strong references
2328 if (mSubDocuments
) {
2329 PL_DHashTableDestroy(mSubDocuments
);
2331 mSubDocuments
= nullptr;
2334 // Destroy link map now so we don't waste time removing
2336 DestroyElementMaps();
2338 bool oldVal
= mInUnlinkOrDeletion
;
2339 mInUnlinkOrDeletion
= true;
2340 uint32_t count
= mChildren
.ChildCount();
2341 { // Scope for update
2342 MOZ_AUTO_DOC_UPDATE(this, UPDATE_CONTENT_MODEL
, true);
2343 for (int32_t i
= int32_t(count
) - 1; i
>= 0; i
--) {
2344 nsCOMPtr
<nsIContent
> content
= mChildren
.ChildAt(i
);
2346 nsIContent
* previousSibling
= content
->GetPreviousSibling();
2348 if (nsINode::GetFirstChild() == content
) {
2349 mFirstChild
= content
->GetNextSibling();
2351 mChildren
.RemoveChildAt(i
);
2352 nsNodeUtils::ContentRemoved(this, content
, i
, previousSibling
);
2353 content
->UnbindFromTree();
2355 mCachedRootElement
= nullptr;
2357 mInUnlinkOrDeletion
= oldVal
;
2359 if (!mMasterDocument
) {
2360 // "When creating an import, use the registry of the master document."
2361 // Note: at this point the mMasterDocument is already set for imports
2362 // (and only for imports)
2363 mRegistry
= nullptr;
2366 // Reset our stylesheets
2367 ResetStylesheetsToURI(aURI
);
2369 // Release the listener manager
2370 if (mListenerManager
) {
2371 mListenerManager
->Disconnect();
2372 mListenerManager
= nullptr;
2375 // Release the stylesheets list.
2376 mDOMStyleSheets
= nullptr;
2378 // Release our principal after tearing down the document, rather than before.
2379 // This ensures that, during teardown, the document and the dying window (which
2380 // already nulled out its document pointer and cached the principal) have
2381 // matching principals.
2382 SetPrincipal(nullptr);
2384 // Clear the original URI so SetDocumentURI sets it.
2385 mOriginalURI
= nullptr;
2387 SetDocumentURI(aURI
);
2388 mChromeXHRDocURI
= aURI
;
2389 // If mDocumentBaseURI is null, nsIDocument::GetBaseURI() returns
2391 mDocumentBaseURI
= nullptr;
2392 mChromeXHRDocBaseURI
= nullptr;
2395 mDocumentLoadGroup
= do_GetWeakReference(aLoadGroup
);
2396 // there was an assertion here that aLoadGroup was not null. This
2397 // is no longer valid: nsDocShell::SetDocument does not create a
2398 // load group, and it works just fine
2400 // XXXbz what does "just fine" mean exactly? And given that there
2401 // is no nsDocShell::SetDocument, what is this talking about?
2404 mLastModified
.Truncate();
2405 // XXXbz I guess we're assuming that the caller will either pass in
2406 // a channel with a useful type or call SetContentType?
2407 SetContentTypeInternal(EmptyCString());
2408 mContentLanguage
.Truncate();
2409 mBaseTarget
.Truncate();
2410 mReferrer
.Truncate();
2412 mXMLDeclarationBits
= 0;
2414 // Now get our new principal
2416 SetPrincipal(aPrincipal
);
2418 nsIScriptSecurityManager
*securityManager
=
2419 nsContentUtils::GetSecurityManager();
2420 if (securityManager
) {
2421 nsCOMPtr
<nsILoadContext
> loadContext(mDocumentContainer
);
2423 if (!loadContext
&& aLoadGroup
) {
2424 nsCOMPtr
<nsIInterfaceRequestor
> cbs
;
2425 aLoadGroup
->GetNotificationCallbacks(getter_AddRefs(cbs
));
2426 loadContext
= do_GetInterface(cbs
);
2429 MOZ_ASSERT(loadContext
,
2430 "must have a load context or pass in an explicit principal");
2432 nsCOMPtr
<nsIPrincipal
> principal
;
2433 nsresult rv
= securityManager
->
2434 GetLoadContextCodebasePrincipal(mDocumentURI
, loadContext
,
2435 getter_AddRefs(principal
));
2436 if (NS_SUCCEEDED(rv
)) {
2437 SetPrincipal(principal
);
2442 // Refresh the principal on the compartment.
2443 nsPIDOMWindow
* win
= GetInnerWindow();
2445 win
->RefreshCompartmentPrincipal();
2450 nsDocument::RemoveDocStyleSheetsFromStyleSets()
2452 // The stylesheets should forget us
2453 int32_t indx
= mStyleSheets
.Count();
2454 while (--indx
>= 0) {
2455 nsIStyleSheet
* sheet
= mStyleSheets
[indx
];
2456 sheet
->SetOwningDocument(nullptr);
2458 if (sheet
->IsApplicable()) {
2459 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
2461 shell
->StyleSet()->RemoveDocStyleSheet(sheet
);
2464 // XXX Tell observers?
2469 nsDocument::RemoveStyleSheetsFromStyleSets(nsCOMArray
<nsIStyleSheet
>& aSheets
, nsStyleSet::sheetType aType
)
2471 // The stylesheets should forget us
2472 int32_t indx
= aSheets
.Count();
2473 while (--indx
>= 0) {
2474 nsIStyleSheet
* sheet
= aSheets
[indx
];
2475 sheet
->SetOwningDocument(nullptr);
2477 if (sheet
->IsApplicable()) {
2478 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
2480 shell
->StyleSet()->RemoveStyleSheet(aType
, sheet
);
2484 // XXX Tell observers?
2490 nsDocument::ResetStylesheetsToURI(nsIURI
* aURI
)
2494 mozAutoDocUpdate
upd(this, UPDATE_STYLE
, true);
2495 RemoveDocStyleSheetsFromStyleSets();
2496 RemoveStyleSheetsFromStyleSets(mOnDemandBuiltInUASheets
, nsStyleSet::eAgentSheet
);
2497 RemoveStyleSheetsFromStyleSets(mAdditionalSheets
[eAgentSheet
], nsStyleSet::eAgentSheet
);
2498 RemoveStyleSheetsFromStyleSets(mAdditionalSheets
[eUserSheet
], nsStyleSet::eUserSheet
);
2499 RemoveStyleSheetsFromStyleSets(mAdditionalSheets
[eAuthorSheet
], nsStyleSet::eDocSheet
);
2501 // Release all the sheets
2502 mStyleSheets
.Clear();
2503 mOnDemandBuiltInUASheets
.Clear();
2504 for (uint32_t i
= 0; i
< SheetTypeCount
; ++i
)
2505 mAdditionalSheets
[i
].Clear();
2507 // NOTE: We don't release the catalog sheets. It doesn't really matter
2508 // now, but it could in the future -- in which case not releasing them
2509 // is probably the right thing to do.
2511 // Now reset our inline style and attribute sheets.
2512 if (mAttrStyleSheet
) {
2513 mAttrStyleSheet
->Reset();
2514 mAttrStyleSheet
->SetOwningDocument(this);
2516 mAttrStyleSheet
= new nsHTMLStyleSheet(this);
2519 if (!mStyleAttrStyleSheet
) {
2520 mStyleAttrStyleSheet
= new nsHTMLCSSStyleSheet();
2523 if (!mSVGAttrAnimationRuleProcessor
) {
2524 mSVGAttrAnimationRuleProcessor
=
2525 new mozilla::SVGAttrAnimationRuleProcessor();
2528 // Now set up our style sets
2529 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
2531 FillStyleSet(shell
->StyleSet());
2536 AppendAuthorSheet(nsIStyleSheet
*aSheet
, void *aData
)
2538 nsStyleSet
*styleSet
= static_cast<nsStyleSet
*>(aData
);
2539 styleSet
->AppendStyleSheet(nsStyleSet::eDocSheet
, aSheet
);
2544 AppendSheetsToStyleSet(nsStyleSet
* aStyleSet
,
2545 const nsCOMArray
<nsIStyleSheet
>& aSheets
,
2546 nsStyleSet::sheetType aType
)
2548 for (int32_t i
= aSheets
.Count() - 1; i
>= 0; --i
) {
2549 aStyleSet
->AppendStyleSheet(aType
, aSheets
[i
]);
2555 nsDocument::FillStyleSet(nsStyleSet
* aStyleSet
)
2557 NS_PRECONDITION(aStyleSet
, "Must have a style set");
2558 NS_PRECONDITION(aStyleSet
->SheetCount(nsStyleSet::eDocSheet
) == 0,
2559 "Style set already has document sheets?");
2561 // We could consider moving this to nsStyleSet::Init, to match its
2562 // handling of the eAnimationSheet and eTransitionSheet levels.
2563 aStyleSet
->DirtyRuleProcessors(nsStyleSet::ePresHintSheet
);
2564 aStyleSet
->DirtyRuleProcessors(nsStyleSet::eStyleAttrSheet
);
2567 for (i
= mStyleSheets
.Count() - 1; i
>= 0; --i
) {
2568 nsIStyleSheet
* sheet
= mStyleSheets
[i
];
2569 if (sheet
->IsApplicable()) {
2570 aStyleSet
->AddDocStyleSheet(sheet
, this);
2574 nsStyleSheetService
*sheetService
= nsStyleSheetService::GetInstance();
2576 sheetService
->AuthorStyleSheets()->EnumerateForwards(AppendAuthorSheet
,
2580 // Iterate backwards to maintain order
2581 for (i
= mOnDemandBuiltInUASheets
.Count() - 1; i
>= 0; --i
) {
2582 nsIStyleSheet
* sheet
= mOnDemandBuiltInUASheets
[i
];
2583 if (sheet
->IsApplicable()) {
2584 aStyleSet
->PrependStyleSheet(nsStyleSet::eAgentSheet
, sheet
);
2588 AppendSheetsToStyleSet(aStyleSet
, mAdditionalSheets
[eAgentSheet
],
2589 nsStyleSet::eAgentSheet
);
2590 AppendSheetsToStyleSet(aStyleSet
, mAdditionalSheets
[eUserSheet
],
2591 nsStyleSet::eUserSheet
);
2592 AppendSheetsToStyleSet(aStyleSet
, mAdditionalSheets
[eAuthorSheet
],
2593 nsStyleSet::eDocSheet
);
2597 WarnIfSandboxIneffective(nsIDocShell
* aDocShell
,
2598 uint32_t aSandboxFlags
,
2599 nsIChannel
* aChannel
)
2601 // If the document is sandboxed (via the HTML5 iframe sandbox
2602 // attribute) and both the allow-scripts and allow-same-origin
2603 // keywords are supplied, the sandboxed document can call into its
2604 // parent document and remove its sandboxing entirely - we print a
2605 // warning to the web console in this case.
2606 if (aSandboxFlags
& SANDBOXED_NAVIGATION
&&
2607 !(aSandboxFlags
& SANDBOXED_SCRIPTS
) &&
2608 !(aSandboxFlags
& SANDBOXED_ORIGIN
)) {
2609 nsCOMPtr
<nsIDocShellTreeItem
> parentAsItem
;
2610 aDocShell
->GetSameTypeParent(getter_AddRefs(parentAsItem
));
2611 nsCOMPtr
<nsIDocShell
> parentDocShell
= do_QueryInterface(parentAsItem
);
2612 if (!parentDocShell
) {
2616 // Don't warn if our parent is not the top-level document.
2617 nsCOMPtr
<nsIDocShellTreeItem
> grandParentAsItem
;
2618 parentDocShell
->GetSameTypeParent(getter_AddRefs(grandParentAsItem
));
2619 if (grandParentAsItem
) {
2623 nsCOMPtr
<nsIChannel
> parentChannel
;
2624 parentDocShell
->GetCurrentDocumentChannel(getter_AddRefs(parentChannel
));
2625 if (!parentChannel
) {
2628 nsresult rv
= nsContentUtils::CheckSameOrigin(aChannel
, parentChannel
);
2629 if (NS_FAILED(rv
)) {
2633 nsCOMPtr
<nsIDocument
> parentDocument
= do_GetInterface(parentDocShell
);
2634 nsCOMPtr
<nsIURI
> iframeUri
;
2635 parentChannel
->GetURI(getter_AddRefs(iframeUri
));
2636 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag
,
2637 NS_LITERAL_CSTRING("Iframe Sandbox"),
2639 nsContentUtils::eSECURITY_PROPERTIES
,
2640 "BothAllowScriptsAndSameOriginPresent",
2641 nullptr, 0, iframeUri
);
2646 nsDocument::StartDocumentLoad(const char* aCommand
, nsIChannel
* aChannel
,
2647 nsILoadGroup
* aLoadGroup
,
2648 nsISupports
* aContainer
,
2649 nsIStreamListener
**aDocListener
,
2650 bool aReset
, nsIContentSink
* aSink
)
2653 if (gDocumentLeakPRLog
&& PR_LOG_TEST(gDocumentLeakPRLog
, PR_LOG_DEBUG
)) {
2654 nsCOMPtr
<nsIURI
> uri
;
2655 aChannel
->GetURI(getter_AddRefs(uri
));
2659 PR_LogPrint("DOCUMENT %p StartDocumentLoad %s", this, spec
.get());
2666 nsresult rv
= NodePrincipal()->GetAppId(&appId
);
2667 NS_ENSURE_SUCCESS(rv
, rv
);
2668 MOZ_ASSERT(appId
!= nsIScriptSecurityManager::UNKNOWN_APP_ID
,
2669 "Document should never have UNKNOWN_APP_ID");
2673 MOZ_ASSERT(GetReadyStateEnum() == nsIDocument::READYSTATE_UNINITIALIZED
,
2675 SetReadyStateInternal(READYSTATE_LOADING
);
2677 if (nsCRT::strcmp(kLoadAsData
, aCommand
) == 0) {
2678 mLoadedAsData
= true;
2679 // We need to disable script & style loading in this case.
2680 // We leave them disabled even in EndLoad(), and let anyone
2681 // who puts the document on display to worry about enabling.
2683 // Do not load/process scripts when loading as data
2684 ScriptLoader()->SetEnabled(false);
2687 CSSLoader()->SetEnabled(false); // Do not load/process styles when loading as data
2688 } else if (nsCRT::strcmp("external-resource", aCommand
) == 0) {
2689 // Allow CSS, but not scripts
2690 ScriptLoader()->SetEnabled(false);
2693 mMayStartLayout
= false;
2695 mHaveInputEncoding
= true;
2698 Reset(aChannel
, aLoadGroup
);
2701 nsAutoCString contentType
;
2702 nsCOMPtr
<nsIPropertyBag2
> bag
= do_QueryInterface(aChannel
);
2703 if ((bag
&& NS_SUCCEEDED(bag
->GetPropertyAsACString(
2704 NS_LITERAL_STRING("contentType"), contentType
))) ||
2705 NS_SUCCEEDED(aChannel
->GetContentType(contentType
))) {
2706 // XXX this is only necessary for viewsource:
2707 nsACString::const_iterator start
, end
, semicolon
;
2708 contentType
.BeginReading(start
);
2709 contentType
.EndReading(end
);
2711 FindCharInReadable(';', semicolon
, end
);
2712 SetContentTypeInternal(Substring(start
, semicolon
));
2715 RetrieveRelevantHeaders(aChannel
);
2717 mChannel
= aChannel
;
2718 nsCOMPtr
<nsIInputStreamChannel
> inStrmChan
= do_QueryInterface(mChannel
);
2720 bool isSrcdocChannel
;
2721 inStrmChan
->GetIsSrcdocChannel(&isSrcdocChannel
);
2722 if (isSrcdocChannel
) {
2723 mIsSrcdocDocument
= true;
2727 // If this document is being loaded by a docshell, copy its sandbox flags
2728 // to the document. These are immutable after being set here.
2729 nsCOMPtr
<nsIDocShell
> docShell
= do_QueryInterface(aContainer
);
2732 nsresult rv
= docShell
->GetSandboxFlags(&mSandboxFlags
);
2733 NS_ENSURE_SUCCESS(rv
, rv
);
2734 WarnIfSandboxIneffective(docShell
, mSandboxFlags
, GetChannel());
2737 // If this is not a data document, set CSP.
2738 if (!mLoadedAsData
) {
2739 nsresult rv
= InitCSP(aChannel
);
2740 NS_ENSURE_SUCCESS(rv
, rv
);
2747 CSPErrorQueue::Add(const char* aMessageName
)
2749 mErrors
.AppendElement(aMessageName
);
2753 CSPErrorQueue::Flush(nsIDocument
* aDocument
)
2755 for (uint32_t i
= 0; i
< mErrors
.Length(); i
++) {
2756 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag
,
2757 NS_LITERAL_CSTRING("CSP"), aDocument
,
2758 nsContentUtils::eSECURITY_PROPERTIES
,
2765 nsDocument::SendToConsole(nsCOMArray
<nsISecurityConsoleMessage
>& aMessages
)
2767 for (uint32_t i
= 0; i
< aMessages
.Length(); ++i
) {
2768 nsAutoString messageTag
;
2769 aMessages
[i
]->GetTag(messageTag
);
2771 nsAutoString category
;
2772 aMessages
[i
]->GetCategory(category
);
2774 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag
,
2775 NS_ConvertUTF16toUTF8(category
),
2776 this, nsContentUtils::eSECURITY_PROPERTIES
,
2777 NS_ConvertUTF16toUTF8(messageTag
).get());
2782 AppendCSPFromHeader(nsIContentSecurityPolicy
* csp
,
2783 const nsAString
& aHeaderValue
,
2786 // Need to tokenize the header value since multiple headers could be
2787 // concatenated into one comma-separated list of policies.
2788 // See RFC2616 section 4.2 (last paragraph)
2789 nsresult rv
= NS_OK
;
2790 nsCharSeparatedTokenizer
tokenizer(aHeaderValue
, ',');
2791 while (tokenizer
.hasMoreTokens()) {
2792 const nsSubstring
& policy
= tokenizer
.nextToken();
2793 rv
= csp
->AppendPolicy(policy
, aReportOnly
);
2794 NS_ENSURE_SUCCESS(rv
, rv
);
2797 PR_LOG(gCspPRLog
, PR_LOG_DEBUG
,
2798 ("CSP refined with policy: \"%s\"",
2799 NS_ConvertUTF16toUTF8(policy
).get()));
2807 nsDocument::IsLoopDocument(nsIChannel
*aChannel
)
2809 nsCOMPtr
<nsIURI
> chanURI
;
2810 nsresult rv
= aChannel
->GetOriginalURI(getter_AddRefs(chanURI
));
2811 NS_ENSURE_SUCCESS(rv
, false);
2813 bool isAbout
= false;
2814 bool isLoop
= false;
2815 rv
= chanURI
->SchemeIs("about", &isAbout
);
2816 NS_ENSURE_SUCCESS(rv
, false);
2818 nsCOMPtr
<nsIURI
> loopURI
;
2819 rv
= NS_NewURI(getter_AddRefs(loopURI
), "about:loopconversation");
2820 NS_ENSURE_SUCCESS(rv
, false);
2821 rv
= chanURI
->EqualsExceptRef(loopURI
, &isLoop
);
2822 NS_ENSURE_SUCCESS(rv
, false);
2824 rv
= NS_NewURI(getter_AddRefs(loopURI
), "about:looppanel");
2825 NS_ENSURE_SUCCESS(rv
, false);
2826 rv
= chanURI
->EqualsExceptRef(loopURI
, &isLoop
);
2827 NS_ENSURE_SUCCESS(rv
, false);
2834 nsDocument::InitCSP(nsIChannel
* aChannel
)
2836 nsCOMPtr
<nsIContentSecurityPolicy
> csp
;
2837 if (!CSPService::sCSPEnabled
) {
2839 PR_LOG(gCspPRLog
, PR_LOG_DEBUG
,
2840 ("CSP is disabled, skipping CSP init for document %p", this));
2845 nsAutoCString tCspHeaderValue
, tCspROHeaderValue
;
2847 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(aChannel
);
2849 httpChannel
->GetResponseHeader(
2850 NS_LITERAL_CSTRING("content-security-policy"),
2853 httpChannel
->GetResponseHeader(
2854 NS_LITERAL_CSTRING("content-security-policy-report-only"),
2857 NS_ConvertASCIItoUTF16
cspHeaderValue(tCspHeaderValue
);
2858 NS_ConvertASCIItoUTF16
cspROHeaderValue(tCspROHeaderValue
);
2860 // Figure out if we need to apply an app default CSP or a CSP from an app manifest
2861 nsIPrincipal
* principal
= NodePrincipal();
2863 uint16_t appStatus
= principal
->GetAppStatus();
2864 bool applyAppDefaultCSP
= false;
2865 bool applyAppManifestCSP
= false;
2867 nsAutoString appManifestCSP
;
2868 nsAutoString appDefaultCSP
;
2869 if (appStatus
!= nsIPrincipal::APP_STATUS_NOT_INSTALLED
) {
2870 nsCOMPtr
<nsIAppsService
> appsService
= do_GetService(APPS_SERVICE_CONTRACTID
);
2873 if (NS_SUCCEEDED(principal
->GetAppId(&appId
))) {
2874 appsService
->GetManifestCSPByLocalId(appId
, appManifestCSP
);
2875 if (!appManifestCSP
.IsEmpty()) {
2876 applyAppManifestCSP
= true;
2878 appsService
->GetDefaultCSPByLocalId(appId
, appDefaultCSP
);
2879 if (!appDefaultCSP
.IsEmpty()) {
2880 applyAppDefaultCSP
= true;
2886 // Check if this is part of the Loop/Hello service
2887 bool applyLoopCSP
= IsLoopDocument(aChannel
);
2889 // If there's no CSP to apply, go ahead and return early
2890 if (!applyAppDefaultCSP
&&
2891 !applyAppManifestCSP
&&
2893 cspHeaderValue
.IsEmpty() &&
2894 cspROHeaderValue
.IsEmpty()) {
2896 nsCOMPtr
<nsIURI
> chanURI
;
2897 aChannel
->GetURI(getter_AddRefs(chanURI
));
2898 nsAutoCString aspec
;
2899 chanURI
->GetAsciiSpec(aspec
);
2900 PR_LOG(gCspPRLog
, PR_LOG_DEBUG
,
2901 ("no CSP for document, %s, %s",
2903 applyAppDefaultCSP
? "is app" : "not an app"));
2909 PR_LOG(gCspPRLog
, PR_LOG_DEBUG
, ("Document is an app or CSP header specified %p", this));
2914 // If Document is an app check to see if we already set CSP and return early
2915 // if that is indeed the case.
2917 // In general (see bug 947831), we should not be setting CSP on a principal
2918 // that aliases another document. For non-app code this is not a problem
2919 // since we only share the underlying principal with nested browsing
2920 // contexts for which a header cannot be set (e.g., about:blank and
2921 // about:srcodoc iframes) and thus won't try to set the CSP again. This
2922 // check ensures that we do not try to set CSP for an app.
2923 if (applyAppDefaultCSP
|| applyAppManifestCSP
) {
2924 nsCOMPtr
<nsIContentSecurityPolicy
> csp
;
2925 rv
= principal
->GetCsp(getter_AddRefs(csp
));
2926 NS_ENSURE_SUCCESS(rv
, rv
);
2930 PR_LOG(gCspPRLog
, PR_LOG_DEBUG
, ("%s %s %s",
2931 "This document is sharing principal with another document.",
2932 "Since the document is an app, CSP was already set.",
2933 "Skipping attempt to set CSP."));
2939 csp
= do_CreateInstance("@mozilla.org/cspcontext;1", &rv
);
2941 if (NS_FAILED(rv
)) {
2943 PR_LOG(gCspPRLog
, PR_LOG_DEBUG
, ("Failed to create CSP object: %x", rv
));
2948 // used as a "self" identifier for the CSP.
2949 nsCOMPtr
<nsIURI
> selfURI
;
2950 aChannel
->GetURI(getter_AddRefs(selfURI
));
2952 // Store the request context for violation reports
2953 csp
->SetRequestContext(nullptr, nullptr, aChannel
);
2955 // ----- if the doc is an app and we want a default CSP, apply it.
2956 if (applyAppDefaultCSP
) {
2957 csp
->AppendPolicy(appDefaultCSP
, false);
2960 // ----- if the doc is an app and specifies a CSP in its manifest, apply it.
2961 if (applyAppManifestCSP
) {
2962 csp
->AppendPolicy(appManifestCSP
, false);
2965 // ----- if the doc is part of Loop, apply the loop CSP
2967 nsAdoptingString loopCSP
;
2968 loopCSP
= Preferences::GetString("loop.CSP");
2969 NS_ASSERTION(loopCSP
, "Missing loop.CSP preference");
2970 // If the pref has been removed, we continue without setting a CSP
2972 csp
->AppendPolicy(loopCSP
, false);
2976 // ----- if there's a full-strength CSP header, apply it.
2977 if (!cspHeaderValue
.IsEmpty()) {
2978 rv
= AppendCSPFromHeader(csp
, cspHeaderValue
, false);
2979 NS_ENSURE_SUCCESS(rv
, rv
);
2982 // ----- if there's a report-only CSP header, apply it.
2983 if (!cspROHeaderValue
.IsEmpty()) {
2984 rv
= AppendCSPFromHeader(csp
, cspROHeaderValue
, true);
2985 NS_ENSURE_SUCCESS(rv
, rv
);
2988 // ----- Enforce frame-ancestor policy on any applied policies
2989 nsCOMPtr
<nsIDocShell
> docShell(mDocumentContainer
);
2991 bool safeAncestry
= false;
2993 // PermitsAncestry sends violation reports when necessary
2994 rv
= csp
->PermitsAncestry(docShell
, &safeAncestry
);
2996 if (NS_FAILED(rv
) || !safeAncestry
) {
2998 PR_LOG(gCspPRLog
, PR_LOG_DEBUG
,
2999 ("CSP doesn't like frame's ancestry, not loading."));
3001 // stop! ERROR page!
3002 aChannel
->Cancel(NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION
);
3006 // ----- Set up any Referrer Policy specified by CSP
3007 bool hasReferrerPolicy
= false;
3008 uint32_t referrerPolicy
= mozilla::net::RP_Default
;
3009 rv
= csp
->GetReferrerPolicy(&referrerPolicy
, &hasReferrerPolicy
);
3010 NS_ENSURE_SUCCESS(rv
, rv
);
3011 if (hasReferrerPolicy
) {
3012 // Referrer policy spec (section 6.1) says that once the referrer policy
3013 // is set, any future attempts to change it result in No-Referrer.
3014 if (!mReferrerPolicySet
) {
3015 mReferrerPolicy
= static_cast<ReferrerPolicy
>(referrerPolicy
);
3016 mReferrerPolicySet
= true;
3017 } else if (mReferrerPolicy
!= referrerPolicy
) {
3018 mReferrerPolicy
= mozilla::net::RP_No_Referrer
;
3021 PR_LOG(gCspPRLog
, PR_LOG_DEBUG
, ("%s %s",
3022 "CSP wants to set referrer, but nsDocument"
3023 "already has it set. No referrers will be sent"));
3028 // Referrer Policy is set separately for the speculative parser in
3029 // nsHTMLDocument::StartDocumentLoad() so there's nothing to do here for
3030 // speculative loads.
3033 rv
= principal
->SetCsp(csp
);
3034 NS_ENSURE_SUCCESS(rv
, rv
);
3036 PR_LOG(gCspPRLog
, PR_LOG_DEBUG
,
3037 ("Inserted CSP into principal %p", principal
));
3044 nsDocument::StopDocumentLoad()
3047 mParserAborted
= true;
3048 mParser
->Terminate();
3053 nsDocument::SetDocumentURI(nsIURI
* aURI
)
3055 nsCOMPtr
<nsIURI
> oldBase
= GetDocBaseURI();
3056 mDocumentURI
= NS_TryToMakeImmutable(aURI
);
3057 nsIURI
* newBase
= GetDocBaseURI();
3059 bool equalBases
= false;
3060 // Changing just the ref of a URI does not change how relative URIs would
3061 // resolve wrt to it, so we can treat the bases as equal as long as they're
3062 // equal ignoring the ref.
3063 if (oldBase
&& newBase
) {
3064 oldBase
->EqualsExceptRef(newBase
, &equalBases
);
3067 equalBases
= !oldBase
&& !newBase
;
3070 // If this is the first time we're setting the document's URI, set the
3071 // document's original URI.
3073 mOriginalURI
= mDocumentURI
;
3075 // If changing the document's URI changed the base URI of the document, we
3076 // need to refresh the hrefs of all the links on the page.
3083 nsDocument::SetChromeXHRDocURI(nsIURI
* aURI
)
3085 mChromeXHRDocURI
= aURI
;
3089 nsDocument::SetChromeXHRDocBaseURI(nsIURI
* aURI
)
3091 mChromeXHRDocBaseURI
= aURI
;
3095 nsDocument::GetLastModified(nsAString
& aLastModified
)
3097 nsIDocument::GetLastModified(aLastModified
);
3102 nsIDocument::GetLastModified(nsAString
& aLastModified
) const
3104 if (!mLastModified
.IsEmpty()) {
3105 aLastModified
.Assign(mLastModified
);
3107 // If we for whatever reason failed to find the last modified time
3108 // (or even the current time), fall back to what NS4.x returned.
3109 aLastModified
.AssignLiteral(MOZ_UTF16("01/01/1970 00:00:00"));
3114 nsDocument::AddToNameTable(Element
*aElement
, nsIAtom
* aName
)
3116 MOZ_ASSERT(nsGenericHTMLElement::ShouldExposeNameAsHTMLDocumentProperty(aElement
),
3117 "Only put elements that need to be exposed as document['name'] in "
3118 "the named table.");
3120 nsIdentifierMapEntry
*entry
=
3121 mIdentifierMap
.PutEntry(nsDependentAtomString(aName
));
3123 // Null for out-of-memory
3125 if (!entry
->HasNameElement() &&
3126 !entry
->HasIdElementExposedAsHTMLDocumentProperty()) {
3127 ++mExpandoAndGeneration
.generation
;
3129 entry
->AddNameElement(this, aElement
);
3134 nsDocument::RemoveFromNameTable(Element
*aElement
, nsIAtom
* aName
)
3136 // Speed up document teardown
3137 if (mIdentifierMap
.Count() == 0)
3140 nsIdentifierMapEntry
*entry
=
3141 mIdentifierMap
.GetEntry(nsDependentAtomString(aName
));
3142 if (!entry
) // Could be false if the element was anonymous, hence never added
3145 entry
->RemoveNameElement(aElement
);
3146 if (!entry
->HasNameElement() &&
3147 !entry
->HasIdElementExposedAsHTMLDocumentProperty()) {
3148 ++mExpandoAndGeneration
.generation
;
3153 nsDocument::AddToIdTable(Element
*aElement
, nsIAtom
* aId
)
3155 nsIdentifierMapEntry
*entry
=
3156 mIdentifierMap
.PutEntry(nsDependentAtomString(aId
));
3158 if (entry
) { /* True except on OOM */
3159 if (nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(aElement
) &&
3160 !entry
->HasNameElement() &&
3161 !entry
->HasIdElementExposedAsHTMLDocumentProperty()) {
3162 ++mExpandoAndGeneration
.generation
;
3164 entry
->AddIdElement(aElement
);
3169 nsDocument::RemoveFromIdTable(Element
*aElement
, nsIAtom
* aId
)
3171 NS_ASSERTION(aId
, "huhwhatnow?");
3173 // Speed up document teardown
3174 if (mIdentifierMap
.Count() == 0) {
3178 nsIdentifierMapEntry
*entry
=
3179 mIdentifierMap
.GetEntry(nsDependentAtomString(aId
));
3180 if (!entry
) // Can be null for XML elements with changing ids.
3183 entry
->RemoveIdElement(aElement
);
3184 if (nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(aElement
) &&
3185 !entry
->HasNameElement() &&
3186 !entry
->HasIdElementExposedAsHTMLDocumentProperty()) {
3187 ++mExpandoAndGeneration
.generation
;
3189 if (entry
->IsEmpty()) {
3190 mIdentifierMap
.RawRemoveEntry(entry
);
3195 nsDocument::GetPrincipal()
3197 return NodePrincipal();
3200 extern bool sDisablePrefetchHTTPSPref
;
3203 nsDocument::SetPrincipal(nsIPrincipal
*aNewPrincipal
)
3205 if (aNewPrincipal
&& mAllowDNSPrefetch
&& sDisablePrefetchHTTPSPref
) {
3206 nsCOMPtr
<nsIURI
> uri
;
3207 aNewPrincipal
->GetURI(getter_AddRefs(uri
));
3209 if (!uri
|| NS_FAILED(uri
->SchemeIs("https", &isHTTPS
)) ||
3211 mAllowDNSPrefetch
= false;
3214 mNodeInfoManager
->SetDocumentPrincipal(aNewPrincipal
);
3218 nsDocument::GetApplicationCache(nsIApplicationCache
**aApplicationCache
)
3220 NS_IF_ADDREF(*aApplicationCache
= mApplicationCache
);
3226 nsDocument::SetApplicationCache(nsIApplicationCache
*aApplicationCache
)
3228 mApplicationCache
= aApplicationCache
;
3234 nsDocument::GetContentType(nsAString
& aContentType
)
3236 CopyUTF8toUTF16(GetContentTypeInternal(), aContentType
);
3242 nsDocument::SetContentType(const nsAString
& aContentType
)
3244 NS_ASSERTION(GetContentTypeInternal().IsEmpty() ||
3245 GetContentTypeInternal().Equals(NS_ConvertUTF16toUTF8(aContentType
)),
3246 "Do you really want to change the content-type?");
3248 SetContentTypeInternal(NS_ConvertUTF16toUTF8(aContentType
));
3252 nsDocument::GetAllowPlugins(bool * aAllowPlugins
)
3254 // First, we ask our docshell if it allows plugins.
3255 nsCOMPtr
<nsIDocShell
> docShell(mDocumentContainer
);
3258 docShell
->GetAllowPlugins(aAllowPlugins
);
3260 // If the docshell allows plugins, we check whether
3261 // we are sandboxed and plugins should not be allowed.
3263 *aAllowPlugins
= !(mSandboxFlags
& SANDBOXED_PLUGINS
);
3269 already_AddRefed
<UndoManager
>
3270 nsDocument::GetUndoManager()
3272 Element
* rootElement
= GetRootElement();
3277 if (!mUndoManager
) {
3278 mUndoManager
= new UndoManager(rootElement
);
3281 nsRefPtr
<UndoManager
> undoManager
= mUndoManager
;
3282 return undoManager
.forget();
3286 nsDocument::IsWebAnimationsEnabled(JSContext
* /*unused*/, JSObject
* /*unused*/)
3288 MOZ_ASSERT(NS_IsMainThread());
3290 return nsContentUtils::IsCallerChrome() ||
3291 Preferences::GetBool("dom.animations-api.core.enabled");
3295 nsDocument::Timeline()
3297 if (!mAnimationTimeline
) {
3298 mAnimationTimeline
= new AnimationTimeline(this);
3301 return mAnimationTimeline
;
3304 /* Return true if the document is in the focused top-level window, and is an
3305 * ancestor of the focused DOMWindow. */
3307 nsDocument::HasFocus(bool* aResult
)
3310 *aResult
= nsIDocument::HasFocus(rv
);
3311 return rv
.ErrorCode();
3315 nsIDocument::HasFocus(ErrorResult
& rv
) const
3317 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
3319 rv
.Throw(NS_ERROR_NOT_AVAILABLE
);
3323 // Is there a focused DOMWindow?
3324 nsCOMPtr
<nsIDOMWindow
> focusedWindow
;
3325 fm
->GetFocusedWindow(getter_AddRefs(focusedWindow
));
3326 if (!focusedWindow
) {
3330 // Are we an ancestor of the focused DOMWindow?
3331 nsCOMPtr
<nsIDOMDocument
> domDocument
;
3332 focusedWindow
->GetDocument(getter_AddRefs(domDocument
));
3333 nsCOMPtr
<nsIDocument
> document
= do_QueryInterface(domDocument
);
3335 for (nsIDocument
* currentDoc
= document
; currentDoc
;
3336 currentDoc
= currentDoc
->GetParentDocument()) {
3337 if (currentDoc
== this) {
3338 // Yes, we are an ancestor
3347 nsDocument::GetReferrer(nsAString
& aReferrer
)
3349 nsIDocument::GetReferrer(aReferrer
);
3354 nsIDocument::GetReferrer(nsAString
& aReferrer
) const
3356 if (mIsSrcdocDocument
&& mParentDocument
)
3357 mParentDocument
->GetReferrer(aReferrer
);
3359 CopyUTF8toUTF16(mReferrer
, aReferrer
);
3363 nsIDocument::GetSrcdocData(nsAString
&aSrcdocData
)
3365 if (mIsSrcdocDocument
) {
3366 nsCOMPtr
<nsIInputStreamChannel
> inStrmChan
= do_QueryInterface(mChannel
);
3368 return inStrmChan
->GetSrcdocData(aSrcdocData
);
3371 aSrcdocData
= NullString();
3376 nsDocument::GetActiveElement(nsIDOMElement
**aElement
)
3378 nsCOMPtr
<nsIDOMElement
> el(do_QueryInterface(nsIDocument::GetActiveElement()));
3379 el
.forget(aElement
);
3384 nsIDocument::GetActiveElement()
3386 // Get the focused element.
3387 nsCOMPtr
<nsPIDOMWindow
> window
= GetWindow();
3389 nsCOMPtr
<nsPIDOMWindow
> focusedWindow
;
3390 nsIContent
* focusedContent
=
3391 nsFocusManager::GetFocusedDescendant(window
, false,
3392 getter_AddRefs(focusedWindow
));
3393 // be safe and make sure the element is from this document
3394 if (focusedContent
&& focusedContent
->OwnerDoc() == this) {
3395 if (focusedContent
->ChromeOnlyAccess()) {
3396 focusedContent
= focusedContent
->FindFirstNonChromeOnlyAccessContent();
3398 if (focusedContent
) {
3399 return focusedContent
->AsElement();
3404 // No focused element anywhere in this document. Try to get the BODY.
3405 nsRefPtr
<nsHTMLDocument
> htmlDoc
= AsHTMLDocument();
3407 // Because of IE compatibility, return null when html document doesn't have
3409 return htmlDoc
->GetBody();
3412 // If we couldn't get a BODY, return the root element.
3413 return GetDocumentElement();
3417 nsDocument::GetCurrentScript(nsIDOMElement
**aElement
)
3419 nsCOMPtr
<nsIDOMElement
> el(do_QueryInterface(nsIDocument::GetCurrentScript()));
3420 el
.forget(aElement
);
3425 nsIDocument::GetCurrentScript()
3427 nsCOMPtr
<Element
> el(do_QueryInterface(ScriptLoader()->GetCurrentScript()));
3432 nsDocument::ElementFromPoint(float aX
, float aY
, nsIDOMElement
** aReturn
)
3434 Element
* el
= nsIDocument::ElementFromPoint(aX
, aY
);
3435 nsCOMPtr
<nsIDOMElement
> retval
= do_QueryInterface(el
);
3436 retval
.forget(aReturn
);
3441 nsIDocument::ElementFromPoint(float aX
, float aY
)
3443 return ElementFromPointHelper(aX
, aY
, false, true);
3447 nsDocument::ElementFromPointHelper(float aX
, float aY
,
3448 bool aIgnoreRootScrollFrame
,
3451 // As per the the spec, we return null if either coord is negative
3452 if (!aIgnoreRootScrollFrame
&& (aX
< 0 || aY
< 0)) {
3456 nscoord x
= nsPresContext::CSSPixelsToAppUnits(aX
);
3457 nscoord y
= nsPresContext::CSSPixelsToAppUnits(aY
);
3460 // Make sure the layout information we get is up-to-date, and
3461 // ensure we get a root frame (for everything but XUL)
3463 FlushPendingNotifications(Flush_Layout
);
3465 nsIPresShell
*ps
= GetShell();
3469 nsIFrame
*rootFrame
= ps
->GetRootFrame();
3471 // XUL docs, unlike HTML, have no frame tree until everything's done loading
3473 return nullptr; // return null to premature XUL callers as a reminder to wait
3476 nsIFrame
*ptFrame
= nsLayoutUtils::GetFrameForPoint(rootFrame
, pt
,
3477 nsLayoutUtils::IGNORE_PAINT_SUPPRESSION
| nsLayoutUtils::IGNORE_CROSS_DOC
|
3478 (aIgnoreRootScrollFrame
? nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME
: 0));
3483 nsIContent
* elem
= GetContentInThisDocument(ptFrame
);
3484 if (elem
&& !elem
->IsElement()) {
3485 elem
= elem
->GetParent();
3487 return elem
? elem
->AsElement() : nullptr;
3491 nsDocument::NodesFromRectHelper(float aX
, float aY
,
3492 float aTopSize
, float aRightSize
,
3493 float aBottomSize
, float aLeftSize
,
3494 bool aIgnoreRootScrollFrame
,
3496 nsIDOMNodeList
** aReturn
)
3498 NS_ENSURE_ARG_POINTER(aReturn
);
3500 nsSimpleContentList
* elements
= new nsSimpleContentList(this);
3501 NS_ADDREF(elements
);
3502 *aReturn
= elements
;
3504 // Following the same behavior of elementFromPoint,
3505 // we don't return anything if either coord is negative
3506 if (!aIgnoreRootScrollFrame
&& (aX
< 0 || aY
< 0))
3509 nscoord x
= nsPresContext::CSSPixelsToAppUnits(aX
- aLeftSize
);
3510 nscoord y
= nsPresContext::CSSPixelsToAppUnits(aY
- aTopSize
);
3511 nscoord w
= nsPresContext::CSSPixelsToAppUnits(aLeftSize
+ aRightSize
) + 1;
3512 nscoord h
= nsPresContext::CSSPixelsToAppUnits(aTopSize
+ aBottomSize
) + 1;
3514 nsRect
rect(x
, y
, w
, h
);
3516 // Make sure the layout information we get is up-to-date, and
3517 // ensure we get a root frame (for everything but XUL)
3519 FlushPendingNotifications(Flush_Layout
);
3522 nsIPresShell
*ps
= GetShell();
3523 NS_ENSURE_STATE(ps
);
3524 nsIFrame
*rootFrame
= ps
->GetRootFrame();
3526 // XUL docs, unlike HTML, have no frame tree until everything's done loading
3528 return NS_OK
; // return nothing to premature XUL callers as a reminder to wait
3530 nsAutoTArray
<nsIFrame
*,8> outFrames
;
3531 nsLayoutUtils::GetFramesForArea(rootFrame
, rect
, outFrames
,
3532 nsLayoutUtils::IGNORE_PAINT_SUPPRESSION
| nsLayoutUtils::IGNORE_CROSS_DOC
|
3533 (aIgnoreRootScrollFrame
? nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME
: 0));
3535 // Used to filter out repeated elements in sequence.
3536 nsIContent
* lastAdded
= nullptr;
3538 for (uint32_t i
= 0; i
< outFrames
.Length(); i
++) {
3539 nsIContent
* node
= GetContentInThisDocument(outFrames
[i
]);
3541 if (node
&& !node
->IsElement() && !node
->IsNodeOfType(nsINode::eTEXT
)) {
3542 // We have a node that isn't an element or a text node,
3543 // use its parent content instead.
3544 node
= node
->GetParent();
3546 if (node
&& node
!= lastAdded
) {
3547 elements
->AppendElement(node
);
3556 nsDocument::GetElementsByClassName(const nsAString
& aClasses
,
3557 nsIDOMNodeList
** aReturn
)
3559 *aReturn
= nsIDocument::GetElementsByClassName(aClasses
).take();
3563 already_AddRefed
<nsContentList
>
3564 nsIDocument::GetElementsByClassName(const nsAString
& aClasses
)
3566 return nsContentUtils::GetElementsByClassName(this, aClasses
);
3570 nsDocument::ReleaseCapture()
3572 nsIDocument::ReleaseCapture();
3577 nsIDocument::ReleaseCapture() const
3579 // only release the capture if the caller can access it. This prevents a
3580 // page from stopping a scrollbar grab for example.
3581 nsCOMPtr
<nsINode
> node
= nsIPresShell::GetCapturingContent();
3582 if (node
&& nsContentUtils::CanCallerAccess(node
)) {
3583 nsIPresShell::SetCapturingContent(nullptr, 0);
3587 already_AddRefed
<nsIURI
>
3588 nsIDocument::GetBaseURI(bool aTryUseXHRDocBaseURI
) const
3590 nsCOMPtr
<nsIURI
> uri
;
3591 if (aTryUseXHRDocBaseURI
&& mChromeXHRDocBaseURI
) {
3592 uri
= mChromeXHRDocBaseURI
;
3594 uri
= GetDocBaseURI();
3597 return uri
.forget();
3601 nsDocument::SetBaseURI(nsIURI
* aURI
)
3603 if (!aURI
&& !mDocumentBaseURI
) {
3607 // Don't do anything if the URI wasn't actually changed.
3608 if (aURI
&& mDocumentBaseURI
) {
3609 bool equalBases
= false;
3610 mDocumentBaseURI
->Equals(aURI
, &equalBases
);
3616 // Check if CSP allows this base-uri
3617 nsCOMPtr
<nsIContentSecurityPolicy
> csp
;
3618 nsresult rv
= NodePrincipal()->GetCsp(getter_AddRefs(csp
));
3619 NS_ENSURE_SUCCESS(rv
, rv
);
3621 bool permitsBaseURI
= false;
3623 // base-uri is only enforced if explicitly defined in the
3624 // policy - do *not* consult default-src, see:
3625 // http://www.w3.org/TR/CSP2/#directive-default-src
3626 rv
= csp
->Permits(aURI
, nsIContentSecurityPolicy::BASE_URI_DIRECTIVE
,
3627 true, &permitsBaseURI
);
3628 NS_ENSURE_SUCCESS(rv
, rv
);
3629 if (!permitsBaseURI
) {
3635 mDocumentBaseURI
= NS_TryToMakeImmutable(aURI
);
3637 mDocumentBaseURI
= nullptr;
3645 nsDocument::GetBaseTarget(nsAString
&aBaseTarget
)
3647 aBaseTarget
= mBaseTarget
;
3651 nsDocument::SetDocumentCharacterSet(const nsACString
& aCharSetID
)
3653 // XXX it would be a good idea to assert the sanity of the argument,
3654 // but before we figure out what to do about non-Encoding Standard
3655 // encodings in the charset menu and in mailnews, assertions are futile.
3656 if (!mCharacterSet
.Equals(aCharSetID
)) {
3657 if (mMasterDocument
&& !aCharSetID
.EqualsLiteral("UTF-8")) {
3658 // Imports are always UTF-8
3661 mCharacterSet
= aCharSetID
;
3663 int32_t n
= mCharSetObservers
.Length();
3665 for (int32_t i
= 0; i
< n
; i
++) {
3666 nsIObserver
* observer
= mCharSetObservers
.ElementAt(i
);
3668 observer
->Observe(static_cast<nsIDocument
*>(this), "charset",
3669 NS_ConvertASCIItoUTF16(aCharSetID
).get());
3675 nsDocument::AddCharSetObserver(nsIObserver
* aObserver
)
3677 NS_ENSURE_ARG_POINTER(aObserver
);
3679 NS_ENSURE_TRUE(mCharSetObservers
.AppendElement(aObserver
), NS_ERROR_FAILURE
);
3685 nsDocument::RemoveCharSetObserver(nsIObserver
* aObserver
)
3687 mCharSetObservers
.RemoveElement(aObserver
);
3691 nsDocument::GetHeaderData(nsIAtom
* aHeaderField
, nsAString
& aData
) const
3694 const nsDocHeaderData
* data
= mHeaderData
;
3696 if (data
->mField
== aHeaderField
) {
3697 aData
= data
->mData
;
3706 nsDocument::SetHeaderData(nsIAtom
* aHeaderField
, const nsAString
& aData
)
3708 if (!aHeaderField
) {
3709 NS_ERROR("null headerField");
3714 if (!aData
.IsEmpty()) { // don't bother storing empty string
3715 mHeaderData
= new nsDocHeaderData(aHeaderField
, aData
);
3719 nsDocHeaderData
* data
= mHeaderData
;
3720 nsDocHeaderData
** lastPtr
= &mHeaderData
;
3722 do { // look for existing and replace
3723 if (data
->mField
== aHeaderField
) {
3724 if (!aData
.IsEmpty()) {
3725 data
->mData
.Assign(aData
);
3727 else { // don't store empty string
3728 *lastPtr
= data
->mNext
;
3729 data
->mNext
= nullptr;
3736 lastPtr
= &(data
->mNext
);
3740 if (!aData
.IsEmpty() && !found
) {
3741 // didn't find, append
3742 *lastPtr
= new nsDocHeaderData(aHeaderField
, aData
);
3746 if (aHeaderField
== nsGkAtoms::headerContentLanguage
) {
3747 CopyUTF16toUTF8(aData
, mContentLanguage
);
3750 if (aHeaderField
== nsGkAtoms::headerDefaultStyle
) {
3751 // Only mess with our stylesheets if we don't have a lastStyleSheetSet, per
3753 if (DOMStringIsNull(mLastStyleSheetSet
)) {
3754 // Calling EnableStyleSheetsForSetInternal, not SetSelectedStyleSheetSet,
3755 // per spec. The idea here is that we're changing our preferred set and
3756 // that shouldn't change the value of lastStyleSheetSet. Also, we're
3757 // using the Internal version so we can update the CSSLoader and not have
3758 // to worry about null strings.
3759 EnableStyleSheetsForSetInternal(aData
, true);
3763 if (aHeaderField
== nsGkAtoms::refresh
) {
3764 // We get into this code before we have a script global yet, so get to
3765 // our container via mDocumentContainer.
3766 nsCOMPtr
<nsIRefreshURI
> refresher(mDocumentContainer
);
3768 // Note: using mDocumentURI instead of mBaseURI here, for consistency
3769 // (used to just use the current URI of our webnavigation, but that
3770 // should really be the same thing). Note that this code can run
3771 // before the current URI of the webnavigation has been updated, so we
3772 // can't assert equality here.
3773 refresher
->SetupRefreshURIFromHeader(mDocumentURI
, NodePrincipal(),
3774 NS_ConvertUTF16toUTF8(aData
));
3778 if (aHeaderField
== nsGkAtoms::headerDNSPrefetchControl
&&
3779 mAllowDNSPrefetch
) {
3780 // Chromium treats any value other than 'on' (case insensitive) as 'off'.
3781 mAllowDNSPrefetch
= aData
.IsEmpty() || aData
.LowerCaseEqualsLiteral("on");
3784 if (aHeaderField
== nsGkAtoms::viewport
||
3785 aHeaderField
== nsGkAtoms::handheldFriendly
||
3786 aHeaderField
== nsGkAtoms::viewport_minimum_scale
||
3787 aHeaderField
== nsGkAtoms::viewport_maximum_scale
||
3788 aHeaderField
== nsGkAtoms::viewport_initial_scale
||
3789 aHeaderField
== nsGkAtoms::viewport_height
||
3790 aHeaderField
== nsGkAtoms::viewport_width
||
3791 aHeaderField
== nsGkAtoms::viewport_user_scalable
) {
3792 mViewportType
= Unknown
;
3795 // Referrer policy spec says to ignore any empty referrer policies.
3796 // Disabled for now.
3797 if (false && aHeaderField
== nsGkAtoms::referrer
&& !aData
.IsEmpty()) {
3798 ReferrerPolicy policy
= mozilla::net::ReferrerPolicyFromString(aData
);
3800 // Referrer policy spec (section 6.1) says that once the referrer policy
3801 // is set, any future attempts to change it result in No-Referrer.
3802 if (!mReferrerPolicySet
) {
3803 mReferrerPolicy
= policy
;
3804 mReferrerPolicySet
= true;
3805 } else if (mReferrerPolicy
!= policy
) {
3806 mReferrerPolicy
= mozilla::net::RP_No_Referrer
;
3812 nsDocument::TryChannelCharset(nsIChannel
*aChannel
,
3813 int32_t& aCharsetSource
,
3814 nsACString
& aCharset
,
3815 nsHtml5TreeOpExecutor
* aExecutor
)
3818 nsAutoCString charsetVal
;
3819 nsresult rv
= aChannel
->GetContentCharset(charsetVal
);
3820 if (NS_SUCCEEDED(rv
)) {
3821 nsAutoCString preferred
;
3822 if(EncodingUtils::FindEncodingForLabel(charsetVal
, preferred
)) {
3823 aCharset
= preferred
;
3824 aCharsetSource
= kCharsetFromChannel
;
3826 } else if (aExecutor
&& !charsetVal
.IsEmpty()) {
3827 aExecutor
->ComplainAboutBogusProtocolCharset(this);
3833 already_AddRefed
<nsIPresShell
>
3834 nsDocument::CreateShell(nsPresContext
* aContext
, nsViewManager
* aViewManager
,
3835 nsStyleSet
* aStyleSet
)
3837 // Don't add anything here. Add it to |doCreateShell| instead.
3838 // This exists so that subclasses can pass other values for the 4th
3839 // parameter some of the time.
3840 return doCreateShell(aContext
, aViewManager
, aStyleSet
,
3841 eCompatibility_FullStandards
);
3844 already_AddRefed
<nsIPresShell
>
3845 nsDocument::doCreateShell(nsPresContext
* aContext
,
3846 nsViewManager
* aViewManager
, nsStyleSet
* aStyleSet
,
3847 nsCompatibility aCompatMode
)
3849 NS_ASSERTION(!mPresShell
, "We have a presshell already!");
3851 NS_ENSURE_FALSE(GetBFCacheEntry(), nullptr);
3853 FillStyleSet(aStyleSet
);
3855 nsRefPtr
<PresShell
> shell
= new PresShell
;
3856 shell
->Init(this, aContext
, aViewManager
, aStyleSet
, aCompatMode
);
3858 // Note: we don't hold a ref to the shell (it holds a ref to us)
3861 // Make sure to never paint if we belong to an invisible DocShell.
3862 nsCOMPtr
<nsIDocShell
> docShell(mDocumentContainer
);
3863 if (docShell
&& docShell
->IsInvisible())
3864 shell
->SetNeverPainting(true);
3866 mExternalResourceMap
.ShowViewers();
3868 MaybeRescheduleAnimationFrameNotifications();
3870 return shell
.forget();
3874 nsDocument::MaybeRescheduleAnimationFrameNotifications()
3876 if (!mPresShell
|| !IsEventHandlingEnabled()) {
3877 // bail out for now, until one of those conditions changes
3881 nsRefreshDriver
* rd
= mPresShell
->GetPresContext()->RefreshDriver();
3882 if (!mFrameRequestCallbacks
.IsEmpty()) {
3883 rd
->ScheduleFrameRequestCallbacks(this);
3888 nsIDocument::TakeFrameRequestCallbacks(FrameRequestCallbackList
& aCallbacks
)
3890 aCallbacks
.AppendElements(mFrameRequestCallbacks
);
3891 mFrameRequestCallbacks
.Clear();
3894 PLDHashOperator
RequestDiscardEnumerator(imgIRequest
* aKey
,
3898 aKey
->RequestDiscard();
3899 return PL_DHASH_NEXT
;
3903 nsDocument::DeleteShell()
3905 mExternalResourceMap
.HideViewers();
3906 if (IsEventHandlingEnabled()) {
3907 RevokeAnimationFrameNotifications();
3910 // When our shell goes away, request that all our images be immediately
3911 // discarded, so we don't carry around decoded image data for a document we
3912 // no longer intend to paint.
3913 mImageTracker
.EnumerateRead(RequestDiscardEnumerator
, nullptr);
3915 mPresShell
= nullptr;
3919 nsDocument::RevokeAnimationFrameNotifications()
3921 if (!mFrameRequestCallbacks
.IsEmpty()) {
3922 mPresShell
->GetPresContext()->RefreshDriver()->
3923 RevokeFrameRequestCallbacks(this);
3928 SubDocClearEntry(PLDHashTable
*table
, PLDHashEntryHdr
*entry
)
3930 SubDocMapEntry
*e
= static_cast<SubDocMapEntry
*>(entry
);
3932 NS_RELEASE(e
->mKey
);
3933 if (e
->mSubDocument
) {
3934 e
->mSubDocument
->SetParentDocument(nullptr);
3935 NS_RELEASE(e
->mSubDocument
);
3940 SubDocInitEntry(PLDHashTable
*table
, PLDHashEntryHdr
*entry
, const void *key
)
3943 const_cast<SubDocMapEntry
*>
3944 (static_cast<const SubDocMapEntry
*>(entry
));
3946 e
->mKey
= const_cast<Element
*>(static_cast<const Element
*>(key
));
3949 e
->mSubDocument
= nullptr;
3954 nsDocument::SetSubDocumentFor(Element
* aElement
, nsIDocument
* aSubDoc
)
3956 NS_ENSURE_TRUE(aElement
, NS_ERROR_UNEXPECTED
);
3959 // aSubDoc is nullptr, remove the mapping
3961 if (mSubDocuments
) {
3962 SubDocMapEntry
*entry
=
3963 static_cast<SubDocMapEntry
*>
3964 (PL_DHashTableLookup(mSubDocuments
, aElement
));
3966 if (PL_DHASH_ENTRY_IS_BUSY(entry
)) {
3967 PL_DHashTableRawRemove(mSubDocuments
, entry
);
3971 if (!mSubDocuments
) {
3972 // Create a new hashtable
3974 static const PLDHashTableOps hash_table_ops
=
3978 PL_DHashVoidPtrKeyStub
,
3979 PL_DHashMatchEntryStub
,
3980 PL_DHashMoveEntryStub
,
3982 PL_DHashFinalizeStub
,
3986 mSubDocuments
= PL_NewDHashTable(&hash_table_ops
, nullptr,
3987 sizeof(SubDocMapEntry
));
3988 if (!mSubDocuments
) {
3989 return NS_ERROR_OUT_OF_MEMORY
;
3993 // Add a mapping to the hash table
3994 SubDocMapEntry
*entry
=
3995 static_cast<SubDocMapEntry
*>
3996 (PL_DHashTableAdd(mSubDocuments
, aElement
));
3999 return NS_ERROR_OUT_OF_MEMORY
;
4002 if (entry
->mSubDocument
) {
4003 entry
->mSubDocument
->SetParentDocument(nullptr);
4005 // Release the old sub document
4006 NS_RELEASE(entry
->mSubDocument
);
4009 entry
->mSubDocument
= aSubDoc
;
4010 NS_ADDREF(entry
->mSubDocument
);
4012 aSubDoc
->SetParentDocument(this);
4019 nsDocument::GetSubDocumentFor(nsIContent
*aContent
) const
4021 if (mSubDocuments
&& aContent
->IsElement()) {
4022 SubDocMapEntry
*entry
=
4023 static_cast<SubDocMapEntry
*>
4024 (PL_DHashTableLookup(mSubDocuments
, aContent
->AsElement()));
4026 if (PL_DHASH_ENTRY_IS_BUSY(entry
)) {
4027 return entry
->mSubDocument
;
4034 static PLDHashOperator
4035 FindContentEnumerator(PLDHashTable
*table
, PLDHashEntryHdr
*hdr
,
4036 uint32_t number
, void *arg
)
4038 SubDocMapEntry
*entry
= static_cast<SubDocMapEntry
*>(hdr
);
4039 FindContentData
*data
= static_cast<FindContentData
*>(arg
);
4041 if (entry
->mSubDocument
== data
->mSubDocument
) {
4042 data
->mResult
= entry
->mKey
;
4044 return PL_DHASH_STOP
;
4047 return PL_DHASH_NEXT
;
4051 nsDocument::FindContentForSubDocument(nsIDocument
*aDocument
) const
4053 NS_ENSURE_TRUE(aDocument
, nullptr);
4055 if (!mSubDocuments
) {
4059 FindContentData
data(aDocument
);
4060 PL_DHashTableEnumerate(mSubDocuments
, FindContentEnumerator
, &data
);
4062 return data
.mResult
;
4066 nsDocument::IsNodeOfType(uint32_t aFlags
) const
4068 return !(aFlags
& ~eDOCUMENT
);
4072 nsIDocument::GetRootElement() const
4074 return (mCachedRootElement
&& mCachedRootElement
->GetParentNode() == this) ?
4075 mCachedRootElement
: GetRootElementInternal();
4079 nsDocument::GetRootElementInternal() const
4081 // Loop backwards because any non-elements, such as doctypes and PIs
4082 // are likely to appear before the root element.
4084 for (i
= mChildren
.ChildCount(); i
> 0; --i
) {
4085 nsIContent
* child
= mChildren
.ChildAt(i
- 1);
4086 if (child
->IsElement()) {
4087 const_cast<nsDocument
*>(this)->mCachedRootElement
= child
->AsElement();
4088 return child
->AsElement();
4092 const_cast<nsDocument
*>(this)->mCachedRootElement
= nullptr;
4097 nsDocument::GetChildAt(uint32_t aIndex
) const
4099 return mChildren
.GetSafeChildAt(aIndex
);
4103 nsDocument::IndexOf(const nsINode
* aPossibleChild
) const
4105 return mChildren
.IndexOfChild(aPossibleChild
);
4109 nsDocument::GetChildCount() const
4111 return mChildren
.ChildCount();
4114 nsIContent
* const *
4115 nsDocument::GetChildArray(uint32_t* aChildCount
) const
4117 return mChildren
.GetChildArray(aChildCount
);
4122 nsDocument::InsertChildAt(nsIContent
* aKid
, uint32_t aIndex
,
4125 if (aKid
->IsElement() && GetRootElement()) {
4126 NS_WARNING("Inserting root element when we already have one");
4127 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
;
4130 return doInsertChildAt(aKid
, aIndex
, aNotify
, mChildren
);
4134 nsDocument::RemoveChildAt(uint32_t aIndex
, bool aNotify
)
4136 nsCOMPtr
<nsIContent
> oldKid
= GetChildAt(aIndex
);
4141 if (oldKid
->IsElement()) {
4142 // Destroy the link map up front before we mess with the child list.
4143 DestroyElementMaps();
4146 doRemoveChildAt(aIndex
, aNotify
, oldKid
, mChildren
);
4147 mCachedRootElement
= nullptr;
4151 nsDocument::EnsureOnDemandBuiltInUASheet(CSSStyleSheet
* aSheet
)
4153 // Contains() takes nsISupport*, so annoyingly we have to cast here
4154 if (mOnDemandBuiltInUASheets
.Contains(static_cast<nsIStyleSheet
*>(aSheet
))) {
4157 BeginUpdate(UPDATE_STYLE
);
4158 AddOnDemandBuiltInUASheet(aSheet
);
4159 EndUpdate(UPDATE_STYLE
);
4163 nsDocument::AddOnDemandBuiltInUASheet(CSSStyleSheet
* aSheet
)
4165 // Contains() takes nsISupport*, so annoyingly we have to cast here
4166 MOZ_ASSERT(!mOnDemandBuiltInUASheets
.Contains(static_cast<nsIStyleSheet
*>(aSheet
)));
4168 // Prepend here so that we store the sheets in mOnDemandBuiltInUASheets in
4169 // the same order that they should end up in the style set.
4170 mOnDemandBuiltInUASheets
.InsertElementAt(0, aSheet
);
4172 if (aSheet
->IsApplicable()) {
4173 // This is like |AddStyleSheetToStyleSets|, but for an agent sheet.
4174 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
4176 // Note that prepending here is necessary to make sure that html.css etc.
4177 // do not override Firefox OS/Mobile's content.css sheet. Maybe we should
4178 // have an insertion point to match the order of
4179 // nsDocumentViewer::CreateStyleSet though?
4180 shell
->StyleSet()->PrependStyleSheet(nsStyleSet::eAgentSheet
, aSheet
);
4184 NotifyStyleSheetAdded(aSheet
, false);
4188 nsDocument::GetNumberOfStyleSheets() const
4190 return mStyleSheets
.Count();
4194 nsDocument::GetStyleSheetAt(int32_t aIndex
) const
4196 NS_ENSURE_TRUE(0 <= aIndex
&& aIndex
< mStyleSheets
.Count(), nullptr);
4197 return mStyleSheets
[aIndex
];
4201 nsDocument::GetIndexOfStyleSheet(nsIStyleSheet
* aSheet
) const
4203 return mStyleSheets
.IndexOf(aSheet
);
4207 nsDocument::AddStyleSheetToStyleSets(nsIStyleSheet
* aSheet
)
4209 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
4211 shell
->StyleSet()->AddDocStyleSheet(aSheet
, this);
4215 #define DO_STYLESHEET_NOTIFICATION(className, type, memberName, argName) \
4217 nsRefPtr<CSSStyleSheet> cssSheet = do_QueryObject(aSheet); \
4222 className##Init init; \
4223 init.mBubbles = true; \
4224 init.mCancelable = true; \
4225 init.mStylesheet = cssSheet; \
4226 init.memberName = argName; \
4228 nsRefPtr<className> event = \
4229 className::Constructor(this, NS_LITERAL_STRING(type), init); \
4230 event->SetTrusted(true); \
4231 event->SetTarget(this); \
4232 nsRefPtr<AsyncEventDispatcher> asyncDispatcher = \
4233 new AsyncEventDispatcher(this, event); \
4234 asyncDispatcher->mDispatchChromeOnly = true; \
4235 asyncDispatcher->PostDOMEvent(); \
4239 nsDocument::NotifyStyleSheetAdded(nsIStyleSheet
* aSheet
, bool aDocumentSheet
)
4241 NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded
, (this, aSheet
, aDocumentSheet
));
4243 if (StyleSheetChangeEventsEnabled()) {
4244 DO_STYLESHEET_NOTIFICATION(StyleSheetChangeEvent
,
4252 nsDocument::NotifyStyleSheetRemoved(nsIStyleSheet
* aSheet
, bool aDocumentSheet
)
4254 NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetRemoved
, (this, aSheet
, aDocumentSheet
));
4256 if (StyleSheetChangeEventsEnabled()) {
4257 DO_STYLESHEET_NOTIFICATION(StyleSheetChangeEvent
,
4258 "StyleSheetRemoved",
4265 nsDocument::AddStyleSheet(nsIStyleSheet
* aSheet
)
4267 NS_PRECONDITION(aSheet
, "null arg");
4268 mStyleSheets
.AppendObject(aSheet
);
4269 aSheet
->SetOwningDocument(this);
4271 if (aSheet
->IsApplicable()) {
4272 AddStyleSheetToStyleSets(aSheet
);
4275 NotifyStyleSheetAdded(aSheet
, true);
4279 nsDocument::RemoveStyleSheetFromStyleSets(nsIStyleSheet
* aSheet
)
4281 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
4283 shell
->StyleSet()->RemoveDocStyleSheet(aSheet
);
4288 nsDocument::RemoveStyleSheet(nsIStyleSheet
* aSheet
)
4290 NS_PRECONDITION(aSheet
, "null arg");
4291 nsCOMPtr
<nsIStyleSheet
> sheet
= aSheet
; // hold ref so it won't die too soon
4293 if (!mStyleSheets
.RemoveObject(aSheet
)) {
4294 NS_ASSERTION(mInUnlinkOrDeletion
, "stylesheet not found");
4298 if (!mIsGoingAway
) {
4299 if (aSheet
->IsApplicable()) {
4300 RemoveStyleSheetFromStyleSets(aSheet
);
4303 NotifyStyleSheetRemoved(aSheet
, true);
4306 aSheet
->SetOwningDocument(nullptr);
4310 nsDocument::UpdateStyleSheets(nsCOMArray
<nsIStyleSheet
>& aOldSheets
,
4311 nsCOMArray
<nsIStyleSheet
>& aNewSheets
)
4313 BeginUpdate(UPDATE_STYLE
);
4315 // XXX Need to set the sheet on the ownernode, if any
4316 NS_PRECONDITION(aOldSheets
.Count() == aNewSheets
.Count(),
4317 "The lists must be the same length!");
4318 int32_t count
= aOldSheets
.Count();
4320 nsCOMPtr
<nsIStyleSheet
> oldSheet
;
4322 for (i
= 0; i
< count
; ++i
) {
4323 oldSheet
= aOldSheets
[i
];
4325 // First remove the old sheet.
4326 NS_ASSERTION(oldSheet
, "None of the old sheets should be null");
4327 int32_t oldIndex
= mStyleSheets
.IndexOf(oldSheet
);
4328 RemoveStyleSheet(oldSheet
); // This does the right notifications
4330 // Now put the new one in its place. If it's null, just ignore it.
4331 nsIStyleSheet
* newSheet
= aNewSheets
[i
];
4333 mStyleSheets
.InsertObjectAt(newSheet
, oldIndex
);
4334 newSheet
->SetOwningDocument(this);
4335 if (newSheet
->IsApplicable()) {
4336 AddStyleSheetToStyleSets(newSheet
);
4339 NotifyStyleSheetAdded(newSheet
, true);
4343 EndUpdate(UPDATE_STYLE
);
4347 nsDocument::InsertStyleSheetAt(nsIStyleSheet
* aSheet
, int32_t aIndex
)
4349 NS_PRECONDITION(aSheet
, "null ptr");
4350 mStyleSheets
.InsertObjectAt(aSheet
, aIndex
);
4352 aSheet
->SetOwningDocument(this);
4354 if (aSheet
->IsApplicable()) {
4355 AddStyleSheetToStyleSets(aSheet
);
4358 NotifyStyleSheetAdded(aSheet
, true);
4363 nsDocument::SetStyleSheetApplicableState(nsIStyleSheet
* aSheet
,
4366 NS_PRECONDITION(aSheet
, "null arg");
4368 // If we're actually in the document style sheet list
4369 if (-1 != mStyleSheets
.IndexOf(aSheet
)) {
4371 AddStyleSheetToStyleSets(aSheet
);
4373 RemoveStyleSheetFromStyleSets(aSheet
);
4377 // We have to always notify, since this will be called for sheets
4378 // that are children of sheets in our style set, as well as some
4379 // sheets for nsHTMLEditor.
4381 NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetApplicableStateChanged
,
4382 (this, aSheet
, aApplicable
));
4384 if (StyleSheetChangeEventsEnabled()) {
4385 DO_STYLESHEET_NOTIFICATION(StyleSheetApplicableStateChangeEvent
,
4386 "StyleSheetApplicableStateChanged",
4391 if (!mSSApplicableStateNotificationPending
) {
4392 nsRefPtr
<nsIRunnable
> notification
= NS_NewRunnableMethod(this,
4393 &nsDocument::NotifyStyleSheetApplicableStateChanged
);
4394 mSSApplicableStateNotificationPending
=
4395 NS_SUCCEEDED(NS_DispatchToCurrentThread(notification
));
4400 nsDocument::NotifyStyleSheetApplicableStateChanged()
4402 mSSApplicableStateNotificationPending
= false;
4403 nsCOMPtr
<nsIObserverService
> observerService
=
4404 mozilla::services::GetObserverService();
4405 if (observerService
) {
4406 observerService
->NotifyObservers(static_cast<nsIDocument
*>(this),
4407 "style-sheet-applicable-state-changed",
4412 static nsStyleSet::sheetType
4413 ConvertAdditionalSheetType(nsIDocument::additionalSheetType aType
)
4416 case nsIDocument::eAgentSheet
:
4417 return nsStyleSet::eAgentSheet
;
4418 case nsIDocument::eUserSheet
:
4419 return nsStyleSet::eUserSheet
;
4420 case nsIDocument::eAuthorSheet
:
4421 return nsStyleSet::eDocSheet
;
4423 NS_ASSERTION(false, "wrong type");
4424 // we must return something although this should never happen
4425 return nsStyleSet::eSheetTypeCount
;
4430 FindSheet(const nsCOMArray
<nsIStyleSheet
>& aSheets
, nsIURI
* aSheetURI
)
4432 for (int32_t i
= aSheets
.Count() - 1; i
>= 0; i
-- ) {
4434 nsIURI
* uri
= aSheets
[i
]->GetSheetURI();
4436 if (uri
&& NS_SUCCEEDED(uri
->Equals(aSheetURI
, &bEqual
)) && bEqual
)
4444 nsDocument::LoadAdditionalStyleSheet(additionalSheetType aType
, nsIURI
* aSheetURI
)
4446 NS_PRECONDITION(aSheetURI
, "null arg");
4448 // Checking if we have loaded this one already.
4449 if (FindSheet(mAdditionalSheets
[aType
], aSheetURI
) >= 0)
4450 return NS_ERROR_INVALID_ARG
;
4452 // Loading the sheet sync.
4453 nsRefPtr
<mozilla::css::Loader
> loader
= new mozilla::css::Loader();
4455 nsRefPtr
<CSSStyleSheet
> sheet
;
4456 nsresult rv
= loader
->LoadSheetSync(aSheetURI
, aType
== eAgentSheet
,
4457 true, getter_AddRefs(sheet
));
4458 NS_ENSURE_SUCCESS(rv
, rv
);
4460 sheet
->SetOwningDocument(this);
4461 MOZ_ASSERT(sheet
->IsApplicable());
4463 return AddAdditionalStyleSheet(aType
, sheet
);
4467 nsDocument::AddAdditionalStyleSheet(additionalSheetType aType
, nsIStyleSheet
* aSheet
)
4469 if (mAdditionalSheets
[aType
].Contains(aSheet
))
4470 return NS_ERROR_INVALID_ARG
;
4472 if (!aSheet
->IsApplicable())
4473 return NS_ERROR_INVALID_ARG
;
4475 mAdditionalSheets
[aType
].AppendObject(aSheet
);
4477 BeginUpdate(UPDATE_STYLE
);
4478 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
4480 nsStyleSet::sheetType type
= ConvertAdditionalSheetType(aType
);
4481 shell
->StyleSet()->AppendStyleSheet(type
, aSheet
);
4484 // Passing false, so documet.styleSheets.length will not be affected by
4485 // these additional sheets.
4486 NotifyStyleSheetAdded(aSheet
, false);
4487 EndUpdate(UPDATE_STYLE
);
4492 nsDocument::RemoveAdditionalStyleSheet(additionalSheetType aType
, nsIURI
* aSheetURI
)
4494 MOZ_ASSERT(aSheetURI
);
4496 nsCOMArray
<nsIStyleSheet
>& sheets
= mAdditionalSheets
[aType
];
4498 int32_t i
= FindSheet(mAdditionalSheets
[aType
], aSheetURI
);
4500 nsCOMPtr
<nsIStyleSheet
> sheetRef
= sheets
[i
];
4501 sheets
.RemoveObjectAt(i
);
4503 BeginUpdate(UPDATE_STYLE
);
4504 if (!mIsGoingAway
) {
4505 MOZ_ASSERT(sheetRef
->IsApplicable());
4506 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
4508 nsStyleSet::sheetType type
= ConvertAdditionalSheetType(aType
);
4509 shell
->StyleSet()->RemoveStyleSheet(type
, sheetRef
);
4513 // Passing false, so documet.styleSheets.length will not be affected by
4514 // these additional sheets.
4515 NotifyStyleSheetRemoved(sheetRef
, false);
4516 EndUpdate(UPDATE_STYLE
);
4518 sheetRef
->SetOwningDocument(nullptr);
4523 nsDocument::FirstAdditionalAuthorSheet()
4525 return mAdditionalSheets
[eAuthorSheet
].SafeObjectAt(0);
4529 nsDocument::GetScopeObject() const
4531 nsCOMPtr
<nsIGlobalObject
> scope(do_QueryReferent(mScopeObject
));
4536 nsDocument::SetScopeObject(nsIGlobalObject
* aGlobal
)
4538 mScopeObject
= do_GetWeakReference(aGlobal
);
4540 mHasHadScriptHandlingObject
= true;
4546 CheckIfContainsEMEContent(nsISupports
* aSupports
, void* aContainsEME
)
4548 nsCOMPtr
<nsIDOMHTMLMediaElement
> domMediaElem(do_QueryInterface(aSupports
));
4550 nsCOMPtr
<nsIContent
> content(do_QueryInterface(domMediaElem
));
4551 MOZ_ASSERT(content
, "aSupports is not a content");
4552 HTMLMediaElement
* mediaElem
= static_cast<HTMLMediaElement
*>(content
.get());
4553 bool* contains
= static_cast<bool*>(aContainsEME
);
4554 if (mediaElem
->GetMediaKeys()) {
4561 nsDocument::ContainsEMEContent()
4563 bool containsEME
= false;
4564 EnumerateActivityObservers(CheckIfContainsEMEContent
,
4565 static_cast<void*>(&containsEME
));
4571 NotifyActivityChanged(nsISupports
*aSupports
, void *aUnused
)
4573 nsCOMPtr
<nsIDOMHTMLMediaElement
> domMediaElem(do_QueryInterface(aSupports
));
4575 nsCOMPtr
<nsIContent
> content(do_QueryInterface(domMediaElem
));
4576 MOZ_ASSERT(content
, "aSupports is not a content");
4577 HTMLMediaElement
* mediaElem
= static_cast<HTMLMediaElement
*>(content
.get());
4578 mediaElem
->NotifyOwnerDocumentActivityChanged();
4580 nsCOMPtr
<nsIObjectLoadingContent
> objectLoadingContent(do_QueryInterface(aSupports
));
4581 if (objectLoadingContent
) {
4582 nsObjectLoadingContent
* olc
= static_cast<nsObjectLoadingContent
*>(objectLoadingContent
.get());
4583 olc
->NotifyOwnerDocumentActivityChanged();
4585 nsCOMPtr
<nsIDocumentActivity
> objectDocumentActivity(do_QueryInterface(aSupports
));
4586 if (objectDocumentActivity
) {
4587 objectDocumentActivity
->NotifyOwnerDocumentActivityChanged();
4592 nsIDocument::SetContainer(nsDocShell
* aContainer
)
4595 mDocumentContainer
= aContainer
;
4597 mDocumentContainer
= WeakPtr
<nsDocShell
>();
4600 EnumerateActivityObservers(NotifyActivityChanged
, nullptr);
4606 if (aContainer
->ItemType() == nsIDocShellTreeItem::typeContent
) {
4607 // check if same type root
4608 nsCOMPtr
<nsIDocShellTreeItem
> sameTypeRoot
;
4609 aContainer
->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot
));
4610 NS_ASSERTION(sameTypeRoot
, "No document shell root tree item from document shell tree item!");
4612 if (sameTypeRoot
== aContainer
) {
4613 static_cast<nsDocument
*>(this)->SetIsTopLevelContentDocument(true);
4619 nsIDocument::GetContainer() const
4621 return static_cast<nsIDocShell
*>(mDocumentContainer
);
4625 nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject
*aScriptGlobalObject
)
4629 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(aScriptGlobalObject
));
4631 NS_ASSERTION(!win
|| win
->IsInnerWindow(),
4632 "Script global object must be an inner window!");
4635 NS_ABORT_IF_FALSE(aScriptGlobalObject
|| !mAnimationController
||
4636 mAnimationController
->IsPausedByType(
4637 nsSMILTimeContainer::PAUSE_PAGEHIDE
|
4638 nsSMILTimeContainer::PAUSE_BEGIN
),
4639 "Clearing window pointer while animations are unpaused");
4641 if (mScriptGlobalObject
&& !aScriptGlobalObject
) {
4642 // We're detaching from the window. We need to grab a pointer to
4643 // our layout history state now.
4644 mLayoutHistoryState
= GetLayoutHistoryState();
4646 if (mPresShell
&& !EventHandlingSuppressed()) {
4647 RevokeAnimationFrameNotifications();
4650 // Also make sure to remove our onload blocker now if we haven't done it yet
4651 if (mOnloadBlockCount
!= 0) {
4652 nsCOMPtr
<nsILoadGroup
> loadGroup
= GetDocumentLoadGroup();
4654 loadGroup
->RemoveRequest(mOnloadBlocker
, nullptr, NS_OK
);
4659 mScriptGlobalObject
= aScriptGlobalObject
;
4661 if (aScriptGlobalObject
) {
4662 mHasHadScriptHandlingObject
= true;
4663 mHasHadDefaultView
= true;
4664 // Go back to using the docshell for the layout history state
4665 mLayoutHistoryState
= nullptr;
4666 mScopeObject
= do_GetWeakReference(aScriptGlobalObject
);
4668 if (!mWillReparent
) {
4669 // We really shouldn't have a wrapper here but if we do we need to make sure
4670 // it has the correct parent.
4671 JSObject
*obj
= GetWrapperPreserveColor();
4673 JSObject
*newScope
= aScriptGlobalObject
->GetGlobalJSObject();
4674 NS_ASSERTION(js::GetGlobalForObjectCrossCompartment(obj
) == newScope
,
4675 "Wrong scope, this is really bad!");
4680 if (mAllowDNSPrefetch
) {
4681 nsCOMPtr
<nsIDocShell
> docShell(mDocumentContainer
);
4684 nsCOMPtr
<nsIWebNavigation
> webNav
=
4685 do_GetInterface(aScriptGlobalObject
);
4686 NS_ASSERTION(SameCOMIdentity(webNav
, docShell
),
4687 "Unexpected container or script global?");
4689 bool allowDNSPrefetch
;
4690 docShell
->GetAllowDNSPrefetch(&allowDNSPrefetch
);
4691 mAllowDNSPrefetch
= allowDNSPrefetch
;
4695 MaybeRescheduleAnimationFrameNotifications();
4696 mRegistry
= new Registry();
4699 // Remember the pointer to our window (or lack there of), to avoid
4700 // having to QI every time it's asked for.
4701 nsCOMPtr
<nsPIDOMWindow
> window
= do_QueryInterface(mScriptGlobalObject
);
4704 // Now that we know what our window is, we can flush the CSP errors to the
4705 // Web Console. We are flushing all messages that occured and were stored
4706 // in the queue prior to this point.
4707 FlushCSPWebConsoleErrorQueue();
4708 nsCOMPtr
<nsIHttpChannelInternal
> internalChannel
=
4709 do_QueryInterface(GetChannel());
4710 if (internalChannel
) {
4711 nsCOMArray
<nsISecurityConsoleMessage
> messages
;
4712 internalChannel
->TakeAllSecurityMessages(messages
);
4713 SendToConsole(messages
);
4716 // Set our visibility state, but do not fire the event. This is correct
4717 // because either we're coming out of bfcache (in which case IsVisible() will
4718 // still test false at this point and no state change will happen) or we're
4719 // doing the initial document load and don't want to fire the event for this
4721 dom::VisibilityState oldState
= mVisibilityState
;
4722 mVisibilityState
= GetVisibilityState();
4723 // When the visibility is changed, notify it to observers.
4724 // Some observers need the notification, for example HTMLMediaElement uses
4725 // it to update internal media resource allocation.
4726 // When video is loaded via VideoDocument, HTMLMediaElement and MediaDecoder
4727 // creation are already done before nsDocument::SetScriptGlobalObject() call.
4728 // MediaDecoder decides whether starting decoding is decided based on
4729 // document's visibility. When the MediaDecoder is created,
4730 // nsDocument::SetScriptGlobalObject() is not yet called and document is
4731 // hidden state. Therefore the MediaDecoder decides that decoding is
4732 // not yet necessary. But soon after nsDocument::SetScriptGlobalObject()
4733 // call, the document becomes not hidden. At the time, MediaDecoder needs
4734 // to know it and needs to start updating decoding.
4735 if (oldState
!= mVisibilityState
) {
4736 EnumerateActivityObservers(NotifyActivityChanged
, nullptr);
4739 // The global in the template contents owner document should be the same.
4740 if (mTemplateContentsOwner
&& mTemplateContentsOwner
!= this) {
4741 mTemplateContentsOwner
->SetScriptGlobalObject(aScriptGlobalObject
);
4744 nsCOMPtr
<nsIChannel
> channel
= GetChannel();
4745 if (!mMaybeServiceWorkerControlled
&& channel
) {
4746 nsLoadFlags loadFlags
= 0;
4747 channel
->GetLoadFlags(&loadFlags
);
4748 // If we are shift-reloaded, don't associate with a ServiceWorker.
4749 // FIXME(nsm): Bug 1041339.
4750 if (loadFlags
& nsIRequest::LOAD_BYPASS_CACHE
) {
4751 NS_WARNING("Page was shift reloaded, skipping ServiceWorker control");
4755 nsCOMPtr
<nsIServiceWorkerManager
> swm
= mozilla::services::GetServiceWorkerManager();
4757 swm
->MaybeStartControlling(this);
4758 mMaybeServiceWorkerControlled
= true;
4763 nsIScriptGlobalObject
*
4764 nsDocument::GetScriptHandlingObjectInternal() const
4766 MOZ_ASSERT(!mScriptGlobalObject
,
4767 "Do not call this when mScriptGlobalObject is set!");
4768 if (mHasHadDefaultView
) {
4772 nsCOMPtr
<nsIScriptGlobalObject
> scriptHandlingObject
=
4773 do_QueryReferent(mScopeObject
);
4774 nsCOMPtr
<nsPIDOMWindow
> win
= do_QueryInterface(scriptHandlingObject
);
4776 NS_ASSERTION(win
->IsInnerWindow(), "Should have inner window here!");
4777 nsPIDOMWindow
* outer
= win
->GetOuterWindow();
4778 if (!outer
|| outer
->GetCurrentInnerWindow() != win
) {
4779 NS_WARNING("Wrong inner/outer window combination!");
4783 return scriptHandlingObject
;
4786 nsDocument::SetScriptHandlingObject(nsIScriptGlobalObject
* aScriptObject
)
4788 NS_ASSERTION(!mScriptGlobalObject
||
4789 mScriptGlobalObject
== aScriptObject
,
4790 "Wrong script object!");
4791 nsCOMPtr
<nsPIDOMWindow
> win
= do_QueryInterface(aScriptObject
);
4792 NS_ASSERTION(!win
|| win
->IsInnerWindow(), "Should have inner window here!");
4793 if (aScriptObject
) {
4794 mScopeObject
= do_GetWeakReference(aScriptObject
);
4795 mHasHadScriptHandlingObject
= true;
4796 mHasHadDefaultView
= false;
4801 nsDocument::IsTopLevelContentDocument()
4803 return mIsTopLevelContentDocument
;
4807 nsDocument::SetIsTopLevelContentDocument(bool aIsTopLevelContentDocument
)
4809 mIsTopLevelContentDocument
= aIsTopLevelContentDocument
;
4813 nsDocument::GetWindowInternal() const
4815 MOZ_ASSERT(!mWindow
, "This should not be called when mWindow is not null!");
4816 // Let's use mScriptGlobalObject. Even if the document is already removed from
4817 // the docshell, the outer window might be still obtainable from the it.
4818 nsCOMPtr
<nsPIDOMWindow
> win
;
4819 if (mRemovedFromDocShell
) {
4820 // The docshell returns the outer window we are done.
4821 nsCOMPtr
<nsIDocShell
> kungfuDeathGrip(mDocumentContainer
);
4822 if (mDocumentContainer
) {
4823 win
= mDocumentContainer
->GetWindow();
4826 win
= do_QueryInterface(mScriptGlobalObject
);
4828 // mScriptGlobalObject is always the inner window, let's get the outer.
4829 win
= win
->GetOuterWindow();
4837 nsDocument::ScriptLoader()
4839 return mScriptLoader
;
4843 nsDocument::InternalAllowXULXBL()
4845 if (nsContentUtils::AllowXULXBLForPrincipal(NodePrincipal())) {
4846 mAllowXULXBL
= eTriTrue
;
4850 mAllowXULXBL
= eTriFalse
;
4854 // Note: We don't hold a reference to the document observer; we assume
4855 // that it has a live reference to the document.
4857 nsDocument::AddObserver(nsIDocumentObserver
* aObserver
)
4859 NS_ASSERTION(mObservers
.IndexOf(aObserver
) == nsTArray
<int>::NoIndex
,
4860 "Observer already in the list");
4861 mObservers
.AppendElement(aObserver
);
4862 AddMutationObserver(aObserver
);
4866 nsDocument::RemoveObserver(nsIDocumentObserver
* aObserver
)
4868 // If we're in the process of destroying the document (and we're
4869 // informing the observers of the destruction), don't remove the
4870 // observers from the list. This is not a big deal, since we
4871 // don't hold a live reference to the observers.
4872 if (!mInDestructor
) {
4873 RemoveMutationObserver(aObserver
);
4874 return mObservers
.RemoveElement(aObserver
);
4877 return mObservers
.Contains(aObserver
);
4881 nsDocument::MaybeEndOutermostXBLUpdate()
4883 // Only call BindingManager()->EndOutermostUpdate() when
4884 // we're not in an update and it is safe to run scripts.
4885 if (mUpdateNestLevel
== 0 && mInXBLUpdate
) {
4886 if (nsContentUtils::IsSafeToRunScript()) {
4887 mInXBLUpdate
= false;
4888 BindingManager()->EndOutermostUpdate();
4889 } else if (!mInDestructor
) {
4890 nsContentUtils::AddScriptRunner(
4891 NS_NewRunnableMethod(this, &nsDocument::MaybeEndOutermostXBLUpdate
));
4897 nsDocument::BeginUpdate(nsUpdateType aUpdateType
)
4899 if (mUpdateNestLevel
== 0 && !mInXBLUpdate
) {
4900 mInXBLUpdate
= true;
4901 BindingManager()->BeginOutermostUpdate();
4905 nsContentUtils::AddScriptBlocker();
4906 NS_DOCUMENT_NOTIFY_OBSERVERS(BeginUpdate
, (this, aUpdateType
));
4910 nsDocument::EndUpdate(nsUpdateType aUpdateType
)
4912 NS_DOCUMENT_NOTIFY_OBSERVERS(EndUpdate
, (this, aUpdateType
));
4914 nsContentUtils::RemoveScriptBlocker();
4918 // This set of updates may have created XBL bindings. Let the
4919 // binding manager know we're done.
4920 MaybeEndOutermostXBLUpdate();
4922 MaybeInitializeFinalizeFrameLoaders();
4926 nsDocument::BeginLoad()
4928 // Block onload here to prevent having to deal with blocking and
4929 // unblocking it while we know the document is loading.
4931 mDidFireDOMContentLoaded
= false;
4932 BlockDOMContentLoaded();
4934 if (mScriptLoader
) {
4935 mScriptLoader
->BeginDeferringScripts();
4938 NS_DOCUMENT_NOTIFY_OBSERVERS(BeginLoad
, (this));
4942 nsDocument::ReportEmptyGetElementByIdArg()
4944 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag
,
4945 NS_LITERAL_CSTRING("DOM"), this,
4946 nsContentUtils::eDOM_PROPERTIES
,
4947 "EmptyGetElementByIdParam");
4951 nsDocument::GetElementById(const nsAString
& aElementId
)
4953 if (!CheckGetElementByIdArg(aElementId
)) {
4957 nsIdentifierMapEntry
*entry
= mIdentifierMap
.GetEntry(aElementId
);
4958 return entry
? entry
->GetIdElement() : nullptr;
4961 const nsSmallVoidArray
*
4962 nsDocument::GetAllElementsForId(const nsAString
& aElementId
) const
4964 if (aElementId
.IsEmpty()) {
4968 nsIdentifierMapEntry
*entry
= mIdentifierMap
.GetEntry(aElementId
);
4969 return entry
? entry
->GetIdElements() : nullptr;
4973 nsDocument::GetElementById(const nsAString
& aId
, nsIDOMElement
** aReturn
)
4975 Element
*content
= GetElementById(aId
);
4977 return CallQueryInterface(content
, aReturn
);
4986 nsDocument::AddIDTargetObserver(nsIAtom
* aID
, IDTargetObserver aObserver
,
4987 void* aData
, bool aForImage
)
4989 nsDependentAtomString
id(aID
);
4991 if (!CheckGetElementByIdArg(id
))
4994 nsIdentifierMapEntry
*entry
= mIdentifierMap
.PutEntry(id
);
4995 NS_ENSURE_TRUE(entry
, nullptr);
4997 entry
->AddContentChangeCallback(aObserver
, aData
, aForImage
);
4998 return aForImage
? entry
->GetImageIdElement() : entry
->GetIdElement();
5002 nsDocument::RemoveIDTargetObserver(nsIAtom
* aID
, IDTargetObserver aObserver
,
5003 void* aData
, bool aForImage
)
5005 nsDependentAtomString
id(aID
);
5007 if (!CheckGetElementByIdArg(id
))
5010 nsIdentifierMapEntry
*entry
= mIdentifierMap
.GetEntry(id
);
5015 entry
->RemoveContentChangeCallback(aObserver
, aData
, aForImage
);
5019 nsDocument::MozSetImageElement(const nsAString
& aImageElementId
,
5020 nsIDOMElement
* aImageElement
)
5022 nsCOMPtr
<Element
> el
= do_QueryInterface(aImageElement
);
5023 MozSetImageElement(aImageElementId
, el
);
5028 nsDocument::MozSetImageElement(const nsAString
& aImageElementId
,
5031 if (aImageElementId
.IsEmpty())
5034 // Hold a script blocker while calling SetImageElement since that can call
5035 // out to id-observers
5036 nsAutoScriptBlocker scriptBlocker
;
5038 nsIdentifierMapEntry
*entry
= mIdentifierMap
.PutEntry(aImageElementId
);
5040 entry
->SetImageElement(aElement
);
5041 if (entry
->IsEmpty()) {
5042 mIdentifierMap
.RemoveEntry(aImageElementId
);
5048 nsDocument::LookupImageElement(const nsAString
& aId
)
5053 nsIdentifierMapEntry
*entry
= mIdentifierMap
.GetEntry(aId
);
5054 return entry
? entry
->GetImageIdElement() : nullptr;
5058 nsDocument::DispatchContentLoadedEvents()
5060 // If you add early returns from this method, make sure you're
5061 // calling UnblockOnload properly.
5063 // Unpin references to preloaded images
5064 mPreloadingImages
.Clear();
5067 mTiming
->NotifyDOMContentLoadedStart(nsIDocument::GetDocumentURI());
5070 // Dispatch observer notification to notify observers document is interactive.
5071 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
5072 nsIPrincipal
*principal
= GetPrincipal();
5073 os
->NotifyObservers(static_cast<nsIDocument
*>(this),
5074 nsContentUtils::IsSystemPrincipal(principal
) ?
5075 "chrome-document-interactive" :
5076 "content-document-interactive",
5079 // Fire a DOM event notifying listeners that this document has been
5080 // loaded (excluding images and other loads initiated by this
5082 nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument
*>(this),
5083 NS_LITERAL_STRING("DOMContentLoaded"),
5087 mTiming
->NotifyDOMContentLoadedEnd(nsIDocument::GetDocumentURI());
5090 // If this document is a [i]frame, fire a DOMFrameContentLoaded
5091 // event on all parent documents notifying that the HTML (excluding
5092 // other external files such as images and stylesheets) in a frame
5093 // has finished loading.
5095 // target_frame is the [i]frame element that will be used as the
5096 // target for the event. It's the [i]frame whose content is done
5098 nsCOMPtr
<EventTarget
> target_frame
;
5100 if (mParentDocument
) {
5101 target_frame
= mParentDocument
->FindContentForSubDocument(this);
5105 nsCOMPtr
<nsIDocument
> parent
= mParentDocument
;
5107 nsCOMPtr
<nsIDOMDocument
> domDoc
= do_QueryInterface(parent
);
5109 nsCOMPtr
<nsIDOMEvent
> event
;
5111 domDoc
->CreateEvent(NS_LITERAL_STRING("Events"),
5112 getter_AddRefs(event
));
5117 event
->InitEvent(NS_LITERAL_STRING("DOMFrameContentLoaded"), true,
5120 event
->SetTarget(target_frame
);
5121 event
->SetTrusted(true);
5123 // To dispatch this event we must manually call
5124 // EventDispatcher::Dispatch() on the ancestor document since the
5125 // target is not in the same document, so the event would never reach
5126 // the ancestor document if we used the normal event
5127 // dispatching code.
5129 WidgetEvent
* innerEvent
= event
->GetInternalNSEvent();
5131 nsEventStatus status
= nsEventStatus_eIgnore
;
5133 nsIPresShell
*shell
= parent
->GetShell();
5135 nsRefPtr
<nsPresContext
> context
= shell
->GetPresContext();
5138 EventDispatcher::Dispatch(parent
, context
, innerEvent
, event
,
5145 parent
= parent
->GetParentDocument();
5149 // If the document has a manifest attribute, fire a MozApplicationManifest
5151 Element
* root
= GetRootElement();
5152 if (root
&& root
->HasAttr(kNameSpaceID_None
, nsGkAtoms::manifest
)) {
5153 nsContentUtils::DispatchChromeEvent(this, static_cast<nsIDocument
*>(this),
5154 NS_LITERAL_STRING("MozApplicationManifest"),
5158 UnblockOnload(true);
5162 nsDocument::EndLoad()
5164 // Drop the ref to our parser, if any, but keep hold of the sink so that we
5165 // can flush it from FlushPendingNotifications as needed. We might have to
5166 // do that to get a StartLayout() to happen.
5168 mWeakSink
= do_GetWeakReference(mParser
->GetContentSink());
5172 NS_DOCUMENT_NOTIFY_OBSERVERS(EndLoad
, (this));
5174 UnblockDOMContentLoaded();
5178 nsDocument::UnblockDOMContentLoaded()
5180 MOZ_ASSERT(mBlockDOMContentLoaded
);
5181 if (--mBlockDOMContentLoaded
!= 0 || mDidFireDOMContentLoaded
) {
5184 mDidFireDOMContentLoaded
= true;
5186 MOZ_ASSERT(mReadyState
== READYSTATE_INTERACTIVE
);
5187 if (!mSynchronousDOMContentLoaded
) {
5188 nsRefPtr
<nsIRunnable
> ev
=
5189 NS_NewRunnableMethod(this, &nsDocument::DispatchContentLoadedEvents
);
5190 NS_DispatchToCurrentThread(ev
);
5192 DispatchContentLoadedEvents();
5197 nsDocument::ContentStateChanged(nsIContent
* aContent
, EventStates aStateMask
)
5199 NS_PRECONDITION(!nsContentUtils::IsSafeToRunScript(),
5200 "Someone forgot a scriptblocker");
5201 NS_DOCUMENT_NOTIFY_OBSERVERS(ContentStateChanged
,
5202 (this, aContent
, aStateMask
));
5206 nsDocument::DocumentStatesChanged(EventStates aStateMask
)
5208 // Invalidate our cached state.
5209 mGotDocumentState
&= ~aStateMask
;
5210 mDocumentState
&= ~aStateMask
;
5212 NS_DOCUMENT_NOTIFY_OBSERVERS(DocumentStatesChanged
, (this, aStateMask
));
5216 nsDocument::StyleRuleChanged(nsIStyleSheet
* aSheet
,
5217 nsIStyleRule
* aOldStyleRule
,
5218 nsIStyleRule
* aNewStyleRule
)
5220 NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleChanged
,
5222 aOldStyleRule
, aNewStyleRule
));
5224 if (StyleSheetChangeEventsEnabled()) {
5225 nsCOMPtr
<css::Rule
> rule
= do_QueryInterface(aNewStyleRule
);
5226 DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent
,
5229 rule
? rule
->GetDOMRule() : nullptr);
5234 nsDocument::StyleRuleAdded(nsIStyleSheet
* aSheet
,
5235 nsIStyleRule
* aStyleRule
)
5237 NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleAdded
,
5238 (this, aSheet
, aStyleRule
));
5240 if (StyleSheetChangeEventsEnabled()) {
5241 nsCOMPtr
<css::Rule
> rule
= do_QueryInterface(aStyleRule
);
5242 DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent
,
5245 rule
? rule
->GetDOMRule() : nullptr);
5250 nsDocument::StyleRuleRemoved(nsIStyleSheet
* aSheet
,
5251 nsIStyleRule
* aStyleRule
)
5253 NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleRemoved
,
5254 (this, aSheet
, aStyleRule
));
5256 if (StyleSheetChangeEventsEnabled()) {
5257 nsCOMPtr
<css::Rule
> rule
= do_QueryInterface(aStyleRule
);
5258 DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent
,
5261 rule
? rule
->GetDOMRule() : nullptr);
5265 #undef DO_STYLESHEET_NOTIFICATION
5267 already_AddRefed
<AnonymousContent
>
5268 nsIDocument::InsertAnonymousContent(Element
& aElement
, ErrorResult
& aRv
)
5270 nsIPresShell
* shell
= GetShell();
5271 if (!shell
|| !shell
->GetCanvasFrame()) {
5272 aRv
.Throw(NS_ERROR_UNEXPECTED
);
5276 nsCOMPtr
<Element
> container
= shell
->GetCanvasFrame()
5277 ->GetCustomContentContainer();
5279 aRv
.Throw(NS_ERROR_UNEXPECTED
);
5283 // Clone the node to avoid returning a direct reference
5284 nsCOMPtr
<nsINode
> clonedElement
= aElement
.CloneNode(true, aRv
);
5289 // Insert the element into the container
5291 rv
= container
->AppendChildTo(clonedElement
->AsContent(), true);
5292 if (NS_FAILED(rv
)) {
5296 nsRefPtr
<AnonymousContent
> anonymousContent
=
5297 new AnonymousContent(clonedElement
->AsElement());
5298 mAnonymousContents
.AppendElement(anonymousContent
);
5300 return anonymousContent
.forget();
5304 nsIDocument::RemoveAnonymousContent(AnonymousContent
& aContent
,
5307 nsIPresShell
* shell
= GetShell();
5308 if (!shell
|| !shell
->GetCanvasFrame()) {
5309 aRv
.Throw(NS_ERROR_UNEXPECTED
);
5313 nsCOMPtr
<Element
> container
= shell
->GetCanvasFrame()
5314 ->GetCustomContentContainer();
5316 aRv
.Throw(NS_ERROR_UNEXPECTED
);
5320 // Iterate over know customContents to get and remove the right one
5321 for (int32_t i
= mAnonymousContents
.Length() - 1; i
>= 0; --i
) {
5322 if (mAnonymousContents
[i
] == &aContent
) {
5323 // Get the node from the customContent
5324 nsCOMPtr
<Element
> node
= aContent
.GetContentNode();
5326 // Remove the entry in mAnonymousContents
5327 mAnonymousContents
.RemoveElementAt(i
);
5329 // Remove the node from its container
5330 container
->RemoveChild(*node
, aRv
);
5341 // nsIDOMDocument interface
5344 nsIDocument::GetDoctype() const
5346 for (nsIContent
* child
= GetFirstChild();
5348 child
= child
->GetNextSibling()) {
5349 if (child
->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE
) {
5350 return static_cast<DocumentType
*>(child
);
5357 nsDocument::GetDoctype(nsIDOMDocumentType
** aDoctype
)
5359 MOZ_ASSERT(aDoctype
);
5360 nsCOMPtr
<nsIDOMDocumentType
> doctype
= nsIDocument::GetDoctype();
5361 doctype
.forget(aDoctype
);
5366 nsDocument::GetImplementation(nsIDOMDOMImplementation
** aImplementation
)
5369 *aImplementation
= GetImplementation(rv
);
5371 MOZ_ASSERT(!*aImplementation
);
5372 return rv
.ErrorCode();
5374 NS_ADDREF(*aImplementation
);
5379 nsDocument::GetImplementation(ErrorResult
& rv
)
5381 if (!mDOMImplementation
) {
5382 nsCOMPtr
<nsIURI
> uri
;
5383 NS_NewURI(getter_AddRefs(uri
), "about:blank");
5385 rv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
5388 bool hasHadScriptObject
= true;
5389 nsIScriptGlobalObject
* scriptObject
=
5390 GetScriptHandlingObject(hasHadScriptObject
);
5391 if (!scriptObject
&& hasHadScriptObject
) {
5392 rv
.Throw(NS_ERROR_UNEXPECTED
);
5395 mDOMImplementation
= new DOMImplementation(this,
5396 scriptObject
? scriptObject
: GetScopeObject(), uri
, uri
);
5399 return mDOMImplementation
;
5403 nsDocument::GetDocumentElement(nsIDOMElement
** aDocumentElement
)
5405 NS_ENSURE_ARG_POINTER(aDocumentElement
);
5407 Element
* root
= GetRootElement();
5409 return CallQueryInterface(root
, aDocumentElement
);
5412 *aDocumentElement
= nullptr;
5418 nsDocument::CreateElement(const nsAString
& aTagName
,
5419 nsIDOMElement
** aReturn
)
5423 nsCOMPtr
<Element
> element
= nsIDocument::CreateElement(aTagName
, rv
);
5424 NS_ENSURE_FALSE(rv
.Failed(), rv
.ErrorCode());
5425 return CallQueryInterface(element
, aReturn
);
5428 bool IsLowercaseASCII(const nsAString
& aValue
)
5430 int32_t len
= aValue
.Length();
5431 for (int32_t i
= 0; i
< len
; ++i
) {
5432 char16_t c
= aValue
[i
];
5433 if (!(0x0061 <= (c
) && ((c
) <= 0x007a))) {
5440 already_AddRefed
<Element
>
5441 nsIDocument::CreateElement(const nsAString
& aTagName
, ErrorResult
& rv
)
5443 rv
= nsContentUtils::CheckQName(aTagName
, false);
5448 bool needsLowercase
= IsHTML() && !IsLowercaseASCII(aTagName
);
5449 nsAutoString lcTagName
;
5450 if (needsLowercase
) {
5451 nsContentUtils::ASCIIToLower(aTagName
, lcTagName
);
5454 nsCOMPtr
<nsIContent
> content
;
5455 rv
= CreateElem(needsLowercase
? lcTagName
: aTagName
,
5456 nullptr, mDefaultElementType
, getter_AddRefs(content
));
5460 return dont_AddRef(content
.forget().take()->AsElement());
5464 nsDocument::SetupCustomElement(Element
* aElement
,
5465 uint32_t aNamespaceID
,
5466 const nsAString
* aTypeExtension
)
5472 nsCOMPtr
<nsIAtom
> tagAtom
= aElement
->Tag();
5473 nsCOMPtr
<nsIAtom
> typeAtom
= aTypeExtension
?
5474 do_GetAtom(*aTypeExtension
) : tagAtom
;
5476 if (aTypeExtension
&& !aElement
->HasAttr(kNameSpaceID_None
, nsGkAtoms::is
)) {
5477 // Custom element setup in the parser happens after the "is"
5478 // attribute is added.
5479 aElement
->SetAttr(kNameSpaceID_None
, nsGkAtoms::is
, *aTypeExtension
, true);
5482 CustomElementDefinition
* data
;
5483 CustomElementHashKey
key(aNamespaceID
, typeAtom
);
5484 if (!mRegistry
->mCustomDefinitions
.Get(&key
, &data
)) {
5485 // The type extension doesn't exist in the registry,
5486 // thus we don't need to enqueue callback or adjust
5487 // the "is" attribute, but it is possibly an upgrade candidate.
5488 RegisterUnresolvedElement(aElement
, typeAtom
);
5492 if (data
->mLocalName
!= tagAtom
) {
5493 // The element doesn't match the local name for the
5494 // definition, thus the element isn't a custom element
5495 // and we don't need to do anything more.
5499 // Enqueuing the created callback will set the CustomElementData on the
5500 // element, causing prototype swizzling to occur in Element::WrapObject.
5501 EnqueueLifecycleCallback(nsIDocument::eCreated
, aElement
, nullptr, data
);
5504 already_AddRefed
<Element
>
5505 nsDocument::CreateElement(const nsAString
& aTagName
,
5506 const nsAString
& aTypeExtension
,
5509 nsRefPtr
<Element
> elem
= nsIDocument::CreateElement(aTagName
, rv
);
5514 if (!aTagName
.Equals(aTypeExtension
)) {
5515 // Custom element type can not extend itself.
5516 SetupCustomElement(elem
, GetDefaultNamespaceID(), &aTypeExtension
);
5519 return elem
.forget();
5523 nsDocument::CreateElementNS(const nsAString
& aNamespaceURI
,
5524 const nsAString
& aQualifiedName
,
5525 nsIDOMElement
** aReturn
)
5529 nsCOMPtr
<Element
> element
=
5530 nsIDocument::CreateElementNS(aNamespaceURI
, aQualifiedName
, rv
);
5531 NS_ENSURE_FALSE(rv
.Failed(), rv
.ErrorCode());
5532 return CallQueryInterface(element
, aReturn
);
5535 already_AddRefed
<Element
>
5536 nsIDocument::CreateElementNS(const nsAString
& aNamespaceURI
,
5537 const nsAString
& aQualifiedName
,
5540 nsRefPtr
<mozilla::dom::NodeInfo
> nodeInfo
;
5541 rv
= nsContentUtils::GetNodeInfoFromQName(aNamespaceURI
,
5544 nsIDOMNode::ELEMENT_NODE
,
5545 getter_AddRefs(nodeInfo
));
5550 nsCOMPtr
<Element
> element
;
5551 rv
= NS_NewElement(getter_AddRefs(element
), nodeInfo
.forget(),
5556 return element
.forget();
5559 already_AddRefed
<Element
>
5560 nsDocument::CreateElementNS(const nsAString
& aNamespaceURI
,
5561 const nsAString
& aQualifiedName
,
5562 const nsAString
& aTypeExtension
,
5565 nsRefPtr
<Element
> elem
= nsIDocument::CreateElementNS(aNamespaceURI
,
5572 int32_t nameSpaceId
= kNameSpaceID_Wildcard
;
5573 if (!aNamespaceURI
.EqualsLiteral("*")) {
5574 rv
= nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI
,
5581 if (!aQualifiedName
.Equals(aTypeExtension
)) {
5582 // A custom element type can not extend itself.
5583 SetupCustomElement(elem
, nameSpaceId
, &aTypeExtension
);
5586 return elem
.forget();
5590 nsDocument::CreateTextNode(const nsAString
& aData
, nsIDOMText
** aReturn
)
5592 *aReturn
= nsIDocument::CreateTextNode(aData
).take();
5596 already_AddRefed
<nsTextNode
>
5597 nsIDocument::CreateTextNode(const nsAString
& aData
) const
5599 nsRefPtr
<nsTextNode
> text
= new nsTextNode(mNodeInfoManager
);
5600 // Don't notify; this node is still being created.
5601 text
->SetText(aData
, false);
5602 return text
.forget();
5606 nsDocument::CreateDocumentFragment(nsIDOMDocumentFragment
** aReturn
)
5608 *aReturn
= nsIDocument::CreateDocumentFragment().take();
5612 already_AddRefed
<DocumentFragment
>
5613 nsIDocument::CreateDocumentFragment() const
5615 nsRefPtr
<DocumentFragment
> frag
= new DocumentFragment(mNodeInfoManager
);
5616 return frag
.forget();
5620 nsDocument::CreateComment(const nsAString
& aData
, nsIDOMComment
** aReturn
)
5622 *aReturn
= nsIDocument::CreateComment(aData
).take();
5626 // Unfortunately, bareword "Comment" is ambiguous with some Mac system headers.
5627 already_AddRefed
<dom::Comment
>
5628 nsIDocument::CreateComment(const nsAString
& aData
) const
5630 nsRefPtr
<dom::Comment
> comment
= new dom::Comment(mNodeInfoManager
);
5632 // Don't notify; this node is still being created.
5633 comment
->SetText(aData
, false);
5634 return comment
.forget();
5638 nsDocument::CreateCDATASection(const nsAString
& aData
,
5639 nsIDOMCDATASection
** aReturn
)
5641 NS_ENSURE_ARG_POINTER(aReturn
);
5643 *aReturn
= nsIDocument::CreateCDATASection(aData
, rv
).take();
5644 return rv
.ErrorCode();
5647 already_AddRefed
<CDATASection
>
5648 nsIDocument::CreateCDATASection(const nsAString
& aData
,
5652 rv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
5656 if (FindInReadable(NS_LITERAL_STRING("]]>"), aData
)) {
5657 rv
.Throw(NS_ERROR_DOM_INVALID_CHARACTER_ERR
);
5661 nsRefPtr
<CDATASection
> cdata
= new CDATASection(mNodeInfoManager
);
5663 // Don't notify; this node is still being created.
5664 cdata
->SetText(aData
, false);
5666 return cdata
.forget();
5670 nsDocument::CreateProcessingInstruction(const nsAString
& aTarget
,
5671 const nsAString
& aData
,
5672 nsIDOMProcessingInstruction
** aReturn
)
5676 nsIDocument::CreateProcessingInstruction(aTarget
, aData
, rv
).take();
5677 return rv
.ErrorCode();
5680 already_AddRefed
<ProcessingInstruction
>
5681 nsIDocument::CreateProcessingInstruction(const nsAString
& aTarget
,
5682 const nsAString
& aData
,
5683 ErrorResult
& rv
) const
5685 nsresult res
= nsContentUtils::CheckQName(aTarget
, false);
5686 if (NS_FAILED(res
)) {
5691 if (FindInReadable(NS_LITERAL_STRING("?>"), aData
)) {
5692 rv
.Throw(NS_ERROR_DOM_INVALID_CHARACTER_ERR
);
5696 nsRefPtr
<ProcessingInstruction
> pi
=
5697 NS_NewXMLProcessingInstruction(mNodeInfoManager
, aTarget
, aData
);
5703 nsDocument::CreateAttribute(const nsAString
& aName
,
5704 nsIDOMAttr
** aReturn
)
5707 *aReturn
= nsIDocument::CreateAttribute(aName
, rv
).take();
5708 return rv
.ErrorCode();
5711 already_AddRefed
<Attr
>
5712 nsIDocument::CreateAttribute(const nsAString
& aName
, ErrorResult
& rv
)
5714 WarnOnceAbout(eCreateAttribute
);
5716 if (!mNodeInfoManager
) {
5717 rv
.Throw(NS_ERROR_NOT_INITIALIZED
);
5721 nsresult res
= nsContentUtils::CheckQName(aName
, false);
5722 if (NS_FAILED(res
)) {
5727 nsRefPtr
<mozilla::dom::NodeInfo
> nodeInfo
;
5728 res
= mNodeInfoManager
->GetNodeInfo(aName
, nullptr, kNameSpaceID_None
,
5729 nsIDOMNode::ATTRIBUTE_NODE
,
5730 getter_AddRefs(nodeInfo
));
5731 if (NS_FAILED(res
)) {
5736 nsRefPtr
<Attr
> attribute
= new Attr(nullptr, nodeInfo
.forget(),
5737 EmptyString(), false);
5738 return attribute
.forget();
5742 nsDocument::CreateAttributeNS(const nsAString
& aNamespaceURI
,
5743 const nsAString
& aQualifiedName
,
5744 nsIDOMAttr
**aResult
)
5748 nsIDocument::CreateAttributeNS(aNamespaceURI
, aQualifiedName
, rv
).take();
5749 return rv
.ErrorCode();
5752 already_AddRefed
<Attr
>
5753 nsIDocument::CreateAttributeNS(const nsAString
& aNamespaceURI
,
5754 const nsAString
& aQualifiedName
,
5757 WarnOnceAbout(eCreateAttributeNS
);
5759 nsRefPtr
<mozilla::dom::NodeInfo
> nodeInfo
;
5760 rv
= nsContentUtils::GetNodeInfoFromQName(aNamespaceURI
,
5763 nsIDOMNode::ATTRIBUTE_NODE
,
5764 getter_AddRefs(nodeInfo
));
5769 nsRefPtr
<Attr
> attribute
= new Attr(nullptr, nodeInfo
.forget(),
5770 EmptyString(), true);
5771 return attribute
.forget();
5775 nsDocument::CustomElementConstructor(JSContext
* aCx
, unsigned aArgc
, JS::Value
* aVp
)
5777 JS::CallArgs args
= JS::CallArgsFromVp(aArgc
, aVp
);
5779 JS::Rooted
<JSObject
*> global(aCx
,
5780 JS_GetGlobalForObject(aCx
, &args
.callee()));
5781 nsCOMPtr
<nsPIDOMWindow
> window
= do_QueryWrapper(aCx
, global
);
5782 MOZ_ASSERT(window
, "Should have a non-null window");
5784 nsDocument
* document
= static_cast<nsDocument
*>(window
->GetDoc());
5786 // Function name is the type of the custom element.
5787 JSString
* jsFunName
=
5788 JS_GetFunctionId(JS_ValueToFunction(aCx
, args
.calleev()));
5789 nsAutoJSString elemName
;
5790 if (!elemName
.init(aCx
, jsFunName
)) {
5794 nsCOMPtr
<nsIAtom
> typeAtom(do_GetAtom(elemName
));
5795 CustomElementHashKey
key(kNameSpaceID_Unknown
, typeAtom
);
5796 CustomElementDefinition
* definition
;
5797 if (!document
->mRegistry
||
5798 !document
->mRegistry
->mCustomDefinitions
.Get(&key
, &definition
)) {
5802 nsDependentAtomString
localName(definition
->mLocalName
);
5804 nsCOMPtr
<nsIContent
> newElement
;
5805 nsresult rv
= document
->CreateElem(localName
, nullptr,
5806 definition
->mNamespaceID
,
5807 getter_AddRefs(newElement
));
5808 NS_ENSURE_SUCCESS(rv
, true);
5810 nsCOMPtr
<Element
> element
= do_QueryInterface(newElement
);
5811 if (definition
->mLocalName
!= typeAtom
) {
5812 // This element is a custom element by extension, thus we need to
5813 // do some special setup. For non-extended custom elements, this happens
5814 // when the element is created.
5815 document
->SetupCustomElement(element
, definition
->mNamespaceID
, &elemName
);
5818 rv
= nsContentUtils::WrapNative(aCx
, newElement
, newElement
, args
.rval());
5819 NS_ENSURE_SUCCESS(rv
, true);
5825 nsDocument::IsWebComponentsEnabled(JSContext
* aCx
, JSObject
* aObject
)
5827 JS::Rooted
<JSObject
*> obj(aCx
, aObject
);
5828 return Preferences::GetBool("dom.webcomponents.enabled") ||
5829 IsInCertifiedApp(aCx
, obj
);
5833 nsDocument::RegisterUnresolvedElement(Element
* aElement
, nsIAtom
* aTypeName
)
5839 mozilla::dom::NodeInfo
* info
= aElement
->NodeInfo();
5841 // Candidate may be a custom element through extension,
5842 // in which case the custom element type name will not
5843 // match the element tag name. e.g. <button is="x-button">.
5844 nsCOMPtr
<nsIAtom
> typeName
= aTypeName
;
5846 typeName
= info
->NameAtom();
5849 CustomElementHashKey
key(info
->NamespaceID(), typeName
);
5850 if (mRegistry
->mCustomDefinitions
.Get(&key
)) {
5854 nsTArray
<nsRefPtr
<Element
>>* unresolved
;
5855 mRegistry
->mCandidatesMap
.Get(&key
, &unresolved
);
5857 unresolved
= new nsTArray
<nsRefPtr
<Element
>>();
5858 // Ownership of unresolved is taken by mCandidatesMap.
5859 mRegistry
->mCandidatesMap
.Put(&key
, unresolved
);
5862 nsRefPtr
<Element
>* elem
= unresolved
->AppendElement();
5870 class ProcessStackRunner MOZ_FINAL
: public nsIRunnable
5872 ~ProcessStackRunner() {}
5874 explicit ProcessStackRunner(bool aIsBaseQueue
= false)
5875 : mIsBaseQueue(aIsBaseQueue
)
5879 NS_IMETHOD
Run() MOZ_OVERRIDE
5881 nsDocument::ProcessTopElementQueue(mIsBaseQueue
);
5887 NS_IMPL_ISUPPORTS(ProcessStackRunner
, nsIRunnable
);
5889 } // anonymous namespace
5892 nsDocument::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType
,
5893 Element
* aCustomElement
,
5894 LifecycleCallbackArgs
* aArgs
,
5895 CustomElementDefinition
* aDefinition
)
5898 // The element might not belong to a document that
5899 // has a browsing context, and thus no registry.
5903 CustomElementData
* elementData
= aCustomElement
->GetCustomElementData();
5905 // Let DEFINITION be ELEMENT's definition
5906 CustomElementDefinition
* definition
= aDefinition
;
5908 mozilla::dom::NodeInfo
* info
= aCustomElement
->NodeInfo();
5910 // Make sure we get the correct definition in case the element
5911 // is a extended custom element e.g. <button is="x-button">.
5912 nsCOMPtr
<nsIAtom
> typeAtom
= elementData
?
5913 elementData
->mType
.get() : info
->NameAtom();
5915 CustomElementHashKey
key(info
->NamespaceID(), typeAtom
);
5916 if (!mRegistry
->mCustomDefinitions
.Get(&key
, &definition
) ||
5917 definition
->mLocalName
!= info
->NameAtom()) {
5918 // Trying to enqueue a callback for an element that is not
5919 // a custom element. We are done, nothing to do.
5925 // Create the custom element data the first time
5926 // that we try to enqueue a callback.
5927 elementData
= new CustomElementData(definition
->mType
);
5928 // aCustomElement takes ownership of elementData
5929 aCustomElement
->SetCustomElementData(elementData
);
5930 MOZ_ASSERT(aType
== nsIDocument::eCreated
,
5931 "First callback should be the created callback");
5934 // Let CALLBACK be the callback associated with the key NAME in CALLBACKS.
5935 CallbackFunction
* func
= nullptr;
5937 case nsIDocument::eCreated
:
5938 if (definition
->mCallbacks
->mCreatedCallback
.WasPassed()) {
5939 func
= definition
->mCallbacks
->mCreatedCallback
.Value();
5943 case nsIDocument::eAttached
:
5944 if (definition
->mCallbacks
->mAttachedCallback
.WasPassed()) {
5945 func
= definition
->mCallbacks
->mAttachedCallback
.Value();
5949 case nsIDocument::eDetached
:
5950 if (definition
->mCallbacks
->mDetachedCallback
.WasPassed()) {
5951 func
= definition
->mCallbacks
->mDetachedCallback
.Value();
5955 case nsIDocument::eAttributeChanged
:
5956 if (definition
->mCallbacks
->mAttributeChangedCallback
.WasPassed()) {
5957 func
= definition
->mCallbacks
->mAttributeChangedCallback
.Value();
5962 // If there is no such callback, stop.
5967 if (aType
== nsIDocument::eCreated
) {
5968 elementData
->mCreatedCallbackInvoked
= false;
5969 } else if (!elementData
->mCreatedCallbackInvoked
) {
5970 // Callbacks other than created callback must not be enqueued
5971 // until after the created callback has been invoked.
5975 // Add CALLBACK to ELEMENT's callback queue.
5976 CustomElementCallback
* callback
= new CustomElementCallback(aCustomElement
,
5980 // Ownership of callback is taken by mCallbackQueue.
5981 elementData
->mCallbackQueue
.AppendElement(callback
);
5983 callback
->SetArgs(*aArgs
);
5986 if (!elementData
->mElementIsBeingCreated
) {
5987 CustomElementData
* lastData
=
5988 sProcessingStack
->SafeLastElement(nullptr);
5990 // A new element queue needs to be pushed if the queue at the
5991 // top of the stack is associated with another microtask level.
5992 // Don't push a queue for the level 0 microtask (base element queue)
5993 // because we don't want to process the queue until the
5994 // microtask checkpoint.
5995 bool shouldPushElementQueue
= nsContentUtils::MicroTaskLevel() > 0 &&
5996 (!lastData
|| lastData
->mAssociatedMicroTask
<
5997 static_cast<int32_t>(nsContentUtils::MicroTaskLevel()));
5999 // Push a new element queue onto the processing stack when appropriate
6000 // (when we enter a new microtask).
6001 if (shouldPushElementQueue
) {
6002 // Push a sentinel value on the processing stack to mark the
6003 // boundary between the element queues.
6004 sProcessingStack
->AppendElement((CustomElementData
*) nullptr);
6007 sProcessingStack
->AppendElement(elementData
);
6008 elementData
->mAssociatedMicroTask
=
6009 static_cast<int32_t>(nsContentUtils::MicroTaskLevel());
6011 // Add a script runner to pop and process the element queue at
6012 // the top of the processing stack.
6013 if (shouldPushElementQueue
) {
6014 // Lifecycle callbacks enqueued by user agent implementation
6015 // should be invoked prior to returning control back to script.
6016 // Create a script runner to process the top of the processing
6017 // stack as soon as it is safe to run script.
6018 nsContentUtils::AddScriptRunner(new ProcessStackRunner());
6025 nsDocument::ProcessBaseElementQueue()
6027 // Prevent re-entrance. Also, if a microtask checkpoint is reached
6028 // and there is no processing stack to process, then we are done.
6029 if (sProcessingBaseElementQueue
|| !sProcessingStack
) {
6033 MOZ_ASSERT(nsContentUtils::MicroTaskLevel() == 0);
6034 sProcessingBaseElementQueue
= true;
6035 nsContentUtils::AddScriptRunner(new ProcessStackRunner(true));
6040 nsDocument::ProcessTopElementQueue(bool aIsBaseQueue
)
6042 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
6044 nsTArray
<nsRefPtr
<CustomElementData
>>& stack
= *sProcessingStack
;
6045 uint32_t firstQueue
= stack
.LastIndexOf((CustomElementData
*) nullptr);
6047 if (aIsBaseQueue
&& firstQueue
!= 0) {
6051 for (uint32_t i
= firstQueue
+ 1; i
< stack
.Length(); ++i
) {
6052 // Callback queue may have already been processed in an earlier
6053 // element queue or in an element queue that was popped
6054 // off more recently.
6055 if (stack
[i
]->mAssociatedMicroTask
!= -1) {
6056 stack
[i
]->RunCallbackQueue();
6057 stack
[i
]->mAssociatedMicroTask
= -1;
6061 // If this was actually the base element queue, don't bother trying to pop
6062 // the first "queue" marker (sentinel).
6063 if (firstQueue
!= 0) {
6064 stack
.SetLength(firstQueue
);
6066 // Don't pop sentinel for base element queue.
6068 sProcessingBaseElementQueue
= false;
6073 nsDocument::RegisterEnabled()
6075 static bool sPrefValue
=
6076 Preferences::GetBool("dom.webcomponents.enabled", false);
6081 Maybe
<nsTArray
<nsRefPtr
<mozilla::dom::CustomElementData
>>>
6082 nsDocument::sProcessingStack
;
6086 nsDocument::sProcessingBaseElementQueue
;
6089 nsDocument::RegisterElement(JSContext
* aCx
, const nsAString
& aType
,
6090 const ElementRegistrationOptions
& aOptions
,
6091 JS::MutableHandle
<JSObject
*> aRetval
,
6095 rv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
6099 Registry::DefinitionMap
& definitions
= mRegistry
->mCustomDefinitions
;
6101 // Unconditionally convert TYPE to lowercase.
6102 nsAutoString lcType
;
6103 nsContentUtils::ASCIIToLower(aType
, lcType
);
6105 // Only convert NAME to lowercase in HTML documents. Note that NAME is
6107 nsAutoString lcName
;
6109 nsContentUtils::ASCIIToLower(aOptions
.mExtends
, lcName
);
6111 lcName
.Assign(aOptions
.mExtends
);
6114 nsCOMPtr
<nsIAtom
> typeAtom(do_GetAtom(lcType
));
6115 if (!nsContentUtils::IsCustomElementName(typeAtom
)) {
6116 rv
.Throw(NS_ERROR_DOM_SYNTAX_ERR
);
6120 // If there already exists a definition with the same TYPE, set ERROR to
6121 // DuplicateDefinition and stop.
6122 // Note that we need to find existing custom elements from either namespace.
6123 CustomElementHashKey
duplicateFinder(kNameSpaceID_Unknown
, typeAtom
);
6124 if (definitions
.Get(&duplicateFinder
)) {
6125 rv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
6129 nsIGlobalObject
* sgo
= GetScopeObject();
6131 rv
.Throw(NS_ERROR_UNEXPECTED
);
6135 JS::Rooted
<JSObject
*> global(aCx
, sgo
->GetGlobalJSObject());
6136 nsCOMPtr
<nsIAtom
> nameAtom
;
6137 int32_t namespaceID
= kNameSpaceID_XHTML
;
6138 JS::Rooted
<JSObject
*> protoObject(aCx
);
6140 JSAutoCompartment
ac(aCx
, global
);
6142 JS::Handle
<JSObject
*> htmlProto(
6143 HTMLElementBinding::GetProtoObjectHandle(aCx
, global
));
6145 rv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
6149 if (!aOptions
.mPrototype
) {
6150 protoObject
= JS_NewObject(aCx
, nullptr, htmlProto
, JS::NullPtr());
6152 rv
.Throw(NS_ERROR_UNEXPECTED
);
6156 protoObject
= aOptions
.mPrototype
;
6158 // We are already operating on the document's (/global's) compartment. Let's
6159 // get a view of the passed in proto from this compartment.
6160 if (!JS_WrapObject(aCx
, &protoObject
)) {
6161 rv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
6165 // We also need an unwrapped version of it for various checks.
6166 JS::Rooted
<JSObject
*> protoObjectUnwrapped(aCx
,
6167 js::CheckedUnwrap(protoObject
));
6168 if (!protoObjectUnwrapped
) {
6169 // If the documents compartment does not have same origin access
6170 // to the compartment of the proto we should just throw.
6171 rv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
6175 // If PROTOTYPE is already an interface prototype object for any interface
6176 // object or PROTOTYPE has a non-configurable property named constructor,
6177 // throw a NotSupportedError and stop.
6178 const js::Class
* clasp
= js::GetObjectClass(protoObjectUnwrapped
);
6179 if (IsDOMIfaceAndProtoClass(clasp
)) {
6180 rv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
6184 JS::Rooted
<JSPropertyDescriptor
> descRoot(aCx
);
6185 JS::MutableHandle
<JSPropertyDescriptor
> desc(&descRoot
);
6186 // This check will go through a wrapper, but as we checked above
6187 // it should be transparent or an xray. This should be fine for now,
6188 // until the spec is sorted out.
6189 if (!JS_GetPropertyDescriptor(aCx
, protoObject
, "constructor", desc
)) {
6190 rv
.Throw(NS_ERROR_UNEXPECTED
);
6194 // Check if non-configurable
6195 if (desc
.isPermanent()) {
6196 rv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
6200 JS::Handle
<JSObject
*> svgProto(
6201 SVGElementBinding::GetProtoObjectHandle(aCx
, global
));
6203 rv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
6207 JS::Rooted
<JSObject
*> protoProto(aCx
, protoObject
);
6209 // If PROTOTYPE's interface inherits from SVGElement, set NAMESPACE to SVG
6211 while (protoProto
) {
6212 if (protoProto
== htmlProto
) {
6216 if (protoProto
== svgProto
) {
6217 namespaceID
= kNameSpaceID_SVG
;
6221 if (!JS_GetPrototype(aCx
, protoProto
, &protoProto
)) {
6222 rv
.Throw(NS_ERROR_UNEXPECTED
);
6228 // If name was provided and not null...
6229 if (!lcName
.IsEmpty()) {
6230 // Let BASE be the element interface for NAME and NAMESPACE.
6232 nameAtom
= do_GetAtom(lcName
);
6233 if (namespaceID
== kNameSpaceID_XHTML
) {
6234 nsIParserService
* ps
= nsContentUtils::GetParserService();
6236 rv
.Throw(NS_ERROR_UNEXPECTED
);
6241 ps
->HTMLCaseSensitiveAtomTagToId(nameAtom
) != eHTMLTag_userdefined
;
6243 known
= SVGElementFactory::Exists(nameAtom
);
6246 // If BASE does not exist or is an interface for a custom element, set ERROR
6247 // to InvalidName and stop.
6248 // If BASE exists, then it cannot be an interface for a custom element.
6250 rv
.Throw(NS_ERROR_DOM_SYNTAX_ERR
);
6254 // If NAMESPACE is SVG Namespace, set ERROR to InvalidName and stop.
6255 if (namespaceID
== kNameSpaceID_SVG
) {
6256 rv
.Throw(NS_ERROR_UNEXPECTED
);
6260 nameAtom
= typeAtom
;
6262 } // Leaving the document's compartment for the LifecycleCallbacks init
6264 // Note: We call the init from the caller compartment here
6265 nsAutoPtr
<LifecycleCallbacks
> callbacksHolder(new LifecycleCallbacks());
6266 JS::RootedValue
rootedv(aCx
, JS::ObjectValue(*protoObject
));
6267 if (!JS_WrapValue(aCx
, &rootedv
) || !callbacksHolder
->Init(aCx
, rootedv
)) {
6268 rv
.Throw(NS_ERROR_FAILURE
);
6272 // Entering the global's compartment again
6273 JSAutoCompartment
ac(aCx
, global
);
6275 // Associate the definition with the custom element.
6276 CustomElementHashKey
key(namespaceID
, typeAtom
);
6277 LifecycleCallbacks
* callbacks
= callbacksHolder
.forget();
6278 CustomElementDefinition
* definition
=
6279 new CustomElementDefinition(protoObject
,
6284 0 /* TODO dependent on HTML imports. Bug 877072 */);
6285 definitions
.Put(&key
, definition
);
6287 // Do element upgrade.
6288 nsAutoPtr
<nsTArray
<nsRefPtr
<Element
>>> candidates
;
6289 mRegistry
->mCandidatesMap
.RemoveAndForget(&key
, candidates
);
6291 for (size_t i
= 0; i
< candidates
->Length(); ++i
) {
6292 Element
*elem
= candidates
->ElementAt(i
);
6294 // Make sure that the element name matches the name in the definition.
6295 // (e.g. a definition for x-button extending button should match
6296 // <button is="x-button"> but not <x-button>.
6297 if (elem
->NodeInfo()->NameAtom() != nameAtom
) {
6298 // Skip over this element because definition does not apply.
6302 nsWrapperCache
* cache
;
6303 CallQueryInterface(elem
, &cache
);
6304 MOZ_ASSERT(cache
, "Element doesn't support wrapper cache?");
6306 JS::RootedObject
wrapper(aCx
);
6307 if ((wrapper
= cache
->GetWrapper())) {
6308 if (!JS_SetPrototype(aCx
, wrapper
, protoObject
)) {
6313 EnqueueLifecycleCallback(nsIDocument::eCreated
, elem
, nullptr, definition
);
6317 // Create constructor to return. Store the name of the custom element as the
6318 // name of the function.
6319 JSFunction
* constructor
= JS_NewFunction(aCx
, nsDocument::CustomElementConstructor
, 0,
6320 JSFUN_CONSTRUCTOR
, JS::NullPtr(),
6321 NS_ConvertUTF16toUTF8(lcType
).get());
6323 rv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
6327 JS::Rooted
<JSObject
*> constructorObj(aCx
, JS_GetFunctionObject(constructor
));
6328 if (!JS_LinkConstructorAndPrototype(aCx
, constructorObj
, protoObject
)) {
6329 rv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
6333 aRetval
.set(constructorObj
);
6337 nsDocument::UseRegistryFromDocument(nsIDocument
* aDocument
)
6339 nsDocument
* doc
= static_cast<nsDocument
*>(aDocument
);
6340 MOZ_ASSERT(!mRegistry
, "There should be no existing registry.");
6341 mRegistry
= doc
->mRegistry
;
6345 nsDocument::GetElementsByTagName(const nsAString
& aTagname
,
6346 nsIDOMNodeList
** aReturn
)
6348 nsRefPtr
<nsContentList
> list
= GetElementsByTagName(aTagname
);
6349 NS_ENSURE_TRUE(list
, NS_ERROR_OUT_OF_MEMORY
);
6351 // transfer ref to aReturn
6352 list
.forget(aReturn
);
6357 nsDocument::BlockedTrackingNodeCount() const
6359 return mBlockedTrackingNodes
.Length();
6362 already_AddRefed
<nsSimpleContentList
>
6363 nsDocument::BlockedTrackingNodes() const
6365 nsRefPtr
<nsSimpleContentList
> list
= new nsSimpleContentList(nullptr);
6367 nsTArray
<nsWeakPtr
> blockedTrackingNodes
;
6368 blockedTrackingNodes
= mBlockedTrackingNodes
;
6370 for (unsigned long i
= 0; i
< blockedTrackingNodes
.Length(); i
++) {
6371 nsWeakPtr weakNode
= blockedTrackingNodes
[i
];
6372 nsCOMPtr
<nsIContent
> node
= do_QueryReferent(weakNode
);
6373 // Consider only nodes to which we have managed to get strong references.
6374 // Coping with nullptrs since it's expected for nodes to disappear when
6375 // nobody else is referring to them.
6377 list
->AppendElement(node
);
6381 return list
.forget();
6384 already_AddRefed
<nsContentList
>
6385 nsIDocument::GetElementsByTagNameNS(const nsAString
& aNamespaceURI
,
6386 const nsAString
& aLocalName
,
6387 ErrorResult
& aResult
)
6389 int32_t nameSpaceId
= kNameSpaceID_Wildcard
;
6391 if (!aNamespaceURI
.EqualsLiteral("*")) {
6393 nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI
,
6395 if (aResult
.Failed()) {
6400 NS_ASSERTION(nameSpaceId
!= kNameSpaceID_Unknown
, "Unexpected namespace ID!");
6402 return NS_GetContentList(this, nameSpaceId
, aLocalName
);
6406 nsDocument::GetElementsByTagNameNS(const nsAString
& aNamespaceURI
,
6407 const nsAString
& aLocalName
,
6408 nsIDOMNodeList
** aReturn
)
6411 nsRefPtr
<nsContentList
> list
=
6412 nsIDocument::GetElementsByTagNameNS(aNamespaceURI
, aLocalName
, rv
);
6414 return rv
.ErrorCode();
6417 // transfer ref to aReturn
6418 list
.forget(aReturn
);
6423 nsDocument::GetAsync(bool *aAsync
)
6425 NS_ERROR("nsDocument::GetAsync() should be overriden by subclass!");
6427 return NS_ERROR_NOT_IMPLEMENTED
;
6431 nsDocument::SetAsync(bool aAsync
)
6433 NS_ERROR("nsDocument::SetAsync() should be overriden by subclass!");
6435 return NS_ERROR_NOT_IMPLEMENTED
;
6439 nsDocument::Load(const nsAString
& aUrl
, bool *aReturn
)
6441 NS_ERROR("nsDocument::Load() should be overriden by subclass!");
6443 return NS_ERROR_NOT_IMPLEMENTED
;
6447 nsDocument::GetStyleSheets(nsIDOMStyleSheetList
** aStyleSheets
)
6449 NS_ADDREF(*aStyleSheets
= StyleSheets());
6454 nsDocument::StyleSheets()
6456 if (!mDOMStyleSheets
) {
6457 mDOMStyleSheets
= new nsDOMStyleSheetList(this);
6459 return mDOMStyleSheets
;
6463 nsDocument::GetMozSelectedStyleSheetSet(nsAString
& aSheetSet
)
6465 nsIDocument::GetSelectedStyleSheetSet(aSheetSet
);
6470 nsIDocument::GetSelectedStyleSheetSet(nsAString
& aSheetSet
)
6472 aSheetSet
.Truncate();
6474 // Look through our sheets, find the selected set title
6475 int32_t count
= GetNumberOfStyleSheets();
6477 for (int32_t index
= 0; index
< count
; index
++) {
6478 nsIStyleSheet
* sheet
= GetStyleSheetAt(index
);
6479 NS_ASSERTION(sheet
, "Null sheet in sheet list!");
6481 nsCOMPtr
<nsIDOMStyleSheet
> domSheet
= do_QueryInterface(sheet
);
6482 NS_ASSERTION(domSheet
, "Sheet must QI to nsIDOMStyleSheet");
6484 domSheet
->GetDisabled(&disabled
);
6486 // Disabled sheets don't affect the currently selected set
6490 sheet
->GetTitle(title
);
6492 if (aSheetSet
.IsEmpty()) {
6494 } else if (!title
.IsEmpty() && !aSheetSet
.Equals(title
)) {
6495 // Sheets from multiple sets enabled; return null string, per spec.
6496 SetDOMStringToNull(aSheetSet
);
6503 nsDocument::SetMozSelectedStyleSheetSet(const nsAString
& aSheetSet
)
6505 SetSelectedStyleSheetSet(aSheetSet
);
6510 nsDocument::SetSelectedStyleSheetSet(const nsAString
& aSheetSet
)
6512 if (DOMStringIsNull(aSheetSet
)) {
6516 // Must update mLastStyleSheetSet before doing anything else with stylesheets
6518 mLastStyleSheetSet
= aSheetSet
;
6519 EnableStyleSheetsForSetInternal(aSheetSet
, true);
6523 nsDocument::GetLastStyleSheetSet(nsAString
& aSheetSet
)
6526 GetLastStyleSheetSet(sheetSet
);
6527 aSheetSet
= sheetSet
;
6532 nsDocument::GetLastStyleSheetSet(nsString
& aSheetSet
)
6534 aSheetSet
= mLastStyleSheetSet
;
6538 nsDocument::GetPreferredStyleSheetSet(nsAString
& aSheetSet
)
6540 nsIDocument::GetPreferredStyleSheetSet(aSheetSet
);
6545 nsIDocument::GetPreferredStyleSheetSet(nsAString
& aSheetSet
)
6547 GetHeaderData(nsGkAtoms::headerDefaultStyle
, aSheetSet
);
6551 nsDocument::GetStyleSheetSets(nsISupports
** aList
)
6553 NS_ADDREF(*aList
= StyleSheetSets());
6558 nsDocument::StyleSheetSets()
6560 if (!mStyleSheetSetList
) {
6561 mStyleSheetSetList
= new nsDOMStyleSheetSetList(this);
6563 return mStyleSheetSetList
;
6567 nsDocument::MozEnableStyleSheetsForSet(const nsAString
& aSheetSet
)
6569 EnableStyleSheetsForSet(aSheetSet
);
6574 nsDocument::EnableStyleSheetsForSet(const nsAString
& aSheetSet
)
6576 // Per spec, passing in null is a no-op.
6577 if (!DOMStringIsNull(aSheetSet
)) {
6578 // Note: must make sure to not change the CSSLoader's preferred sheet --
6579 // that value should be equal to either our lastStyleSheetSet (if that's
6580 // non-null) or to our preferredStyleSheetSet. And this method doesn't
6581 // change either of those.
6582 EnableStyleSheetsForSetInternal(aSheetSet
, false);
6587 nsDocument::EnableStyleSheetsForSetInternal(const nsAString
& aSheetSet
,
6588 bool aUpdateCSSLoader
)
6590 BeginUpdate(UPDATE_STYLE
);
6591 int32_t count
= GetNumberOfStyleSheets();
6593 for (int32_t index
= 0; index
< count
; index
++) {
6594 nsIStyleSheet
* sheet
= GetStyleSheetAt(index
);
6595 NS_ASSERTION(sheet
, "Null sheet in sheet list!");
6596 sheet
->GetTitle(title
);
6597 if (!title
.IsEmpty()) {
6598 sheet
->SetEnabled(title
.Equals(aSheetSet
));
6601 if (aUpdateCSSLoader
) {
6602 CSSLoader()->SetPreferredSheet(aSheetSet
);
6604 EndUpdate(UPDATE_STYLE
);
6608 nsDocument::GetCharacterSet(nsAString
& aCharacterSet
)
6610 nsIDocument::GetCharacterSet(aCharacterSet
);
6615 nsIDocument::GetCharacterSet(nsAString
& aCharacterSet
) const
6617 CopyASCIItoUTF16(GetDocumentCharacterSet(), aCharacterSet
);
6621 nsDocument::ImportNode(nsIDOMNode
* aImportedNode
,
6624 nsIDOMNode
** aResult
)
6632 nsCOMPtr
<nsINode
> imported
= do_QueryInterface(aImportedNode
);
6633 NS_ENSURE_TRUE(imported
, NS_ERROR_UNEXPECTED
);
6636 nsCOMPtr
<nsINode
> result
= nsIDocument::ImportNode(*imported
, aDeep
, rv
);
6638 return rv
.ErrorCode();
6641 NS_ADDREF(*aResult
= result
->AsDOMNode());
6645 already_AddRefed
<nsINode
>
6646 nsIDocument::ImportNode(nsINode
& aNode
, bool aDeep
, ErrorResult
& rv
) const
6648 nsINode
* imported
= &aNode
;
6650 switch (imported
->NodeType()) {
6651 case nsIDOMNode::ATTRIBUTE_NODE
:
6652 case nsIDOMNode::DOCUMENT_FRAGMENT_NODE
:
6653 case nsIDOMNode::ELEMENT_NODE
:
6654 case nsIDOMNode::PROCESSING_INSTRUCTION_NODE
:
6655 case nsIDOMNode::TEXT_NODE
:
6656 case nsIDOMNode::CDATA_SECTION_NODE
:
6657 case nsIDOMNode::COMMENT_NODE
:
6658 case nsIDOMNode::DOCUMENT_TYPE_NODE
:
6660 nsCOMPtr
<nsINode
> newNode
;
6661 nsCOMArray
<nsINode
> nodesWithProperties
;
6662 rv
= nsNodeUtils::Clone(imported
, aDeep
, mNodeInfoManager
,
6663 nodesWithProperties
, getter_AddRefs(newNode
));
6667 return newNode
.forget();
6671 NS_WARNING("Don't know how to clone this nodetype for importNode.");
6673 rv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
6681 nsDocument::LoadBindingDocument(const nsAString
& aURI
)
6684 nsIDocument::LoadBindingDocument(aURI
, rv
);
6685 return rv
.ErrorCode();
6689 nsIDocument::LoadBindingDocument(const nsAString
& aURI
, ErrorResult
& rv
)
6691 nsCOMPtr
<nsIURI
> uri
;
6692 rv
= NS_NewURI(getter_AddRefs(uri
), aURI
,
6693 mCharacterSet
.get(),
6699 // Note - This computation of subjectPrincipal isn't necessarily sensical.
6700 // It's just designed to preserve the old semantics during a mass-conversion
6702 nsCOMPtr
<nsIPrincipal
> subjectPrincipal
=
6703 nsContentUtils::GetCurrentJSContext() ? nsContentUtils::SubjectPrincipal()
6705 BindingManager()->LoadBindingDocument(this, uri
, subjectPrincipal
);
6709 nsDocument::GetBindingParent(nsIDOMNode
* aNode
, nsIDOMElement
** aResult
)
6711 nsCOMPtr
<nsINode
> node
= do_QueryInterface(aNode
);
6712 NS_ENSURE_ARG_POINTER(node
);
6714 Element
* bindingParent
= nsIDocument::GetBindingParent(*node
);
6715 nsCOMPtr
<nsIDOMElement
> retval
= do_QueryInterface(bindingParent
);
6716 retval
.forget(aResult
);
6721 nsIDocument::GetBindingParent(nsINode
& aNode
)
6723 nsCOMPtr
<nsIContent
> content(do_QueryInterface(&aNode
));
6727 nsIContent
* bindingParent
= content
->GetBindingParent();
6728 return bindingParent
? bindingParent
->AsElement() : nullptr;
6732 GetElementByAttribute(nsIContent
* aContent
, nsIAtom
* aAttrName
,
6733 const nsAString
& aAttrValue
, bool aUniversalMatch
)
6735 if (aUniversalMatch
? aContent
->HasAttr(kNameSpaceID_None
, aAttrName
) :
6736 aContent
->AttrValueIs(kNameSpaceID_None
, aAttrName
,
6737 aAttrValue
, eCaseMatters
)) {
6738 return aContent
->AsElement();
6741 for (nsIContent
* child
= aContent
->GetFirstChild();
6743 child
= child
->GetNextSibling()) {
6745 Element
* matchedElement
=
6746 GetElementByAttribute(child
, aAttrName
, aAttrValue
, aUniversalMatch
);
6748 return matchedElement
;
6755 nsDocument::GetAnonymousElementByAttribute(nsIContent
* aElement
,
6757 const nsAString
& aAttrValue
) const
6759 nsINodeList
* nodeList
= BindingManager()->GetAnonymousNodesFor(aElement
);
6763 uint32_t length
= 0;
6764 nodeList
->GetLength(&length
);
6766 bool universalMatch
= aAttrValue
.EqualsLiteral("*");
6768 for (uint32_t i
= 0; i
< length
; ++i
) {
6769 nsIContent
* current
= nodeList
->Item(i
);
6770 Element
* matchedElm
=
6771 GetElementByAttribute(current
, aAttrName
, aAttrValue
, universalMatch
);
6780 nsDocument::GetAnonymousElementByAttribute(nsIDOMElement
* aElement
,
6781 const nsAString
& aAttrName
,
6782 const nsAString
& aAttrValue
,
6783 nsIDOMElement
** aResult
)
6785 nsCOMPtr
<Element
> element
= do_QueryInterface(aElement
);
6786 NS_ENSURE_ARG_POINTER(element
);
6789 nsIDocument::GetAnonymousElementByAttribute(*element
, aAttrName
,
6791 nsCOMPtr
<nsIDOMElement
> retval
= do_QueryInterface(anonEl
);
6792 retval
.forget(aResult
);
6797 nsIDocument::GetAnonymousElementByAttribute(Element
& aElement
,
6798 const nsAString
& aAttrName
,
6799 const nsAString
& aAttrValue
)
6801 nsCOMPtr
<nsIAtom
> attribute
= do_GetAtom(aAttrName
);
6803 return GetAnonymousElementByAttribute(&aElement
, attribute
, aAttrValue
);
6808 nsDocument::GetAnonymousNodes(nsIDOMElement
* aElement
,
6809 nsIDOMNodeList
** aResult
)
6813 nsCOMPtr
<nsIContent
> content(do_QueryInterface(aElement
));
6814 return BindingManager()->GetAnonymousNodesFor(content
, aResult
);
6818 nsIDocument::GetAnonymousNodes(Element
& aElement
)
6820 return BindingManager()->GetAnonymousNodesFor(&aElement
);
6824 nsDocument::CreateRange(nsIDOMRange
** aReturn
)
6827 *aReturn
= nsIDocument::CreateRange(rv
).take();
6828 return rv
.ErrorCode();
6831 already_AddRefed
<nsRange
>
6832 nsIDocument::CreateRange(ErrorResult
& rv
)
6834 nsRefPtr
<nsRange
> range
= new nsRange(this);
6835 nsresult res
= range
->Set(this, 0, this, 0);
6836 if (NS_FAILED(res
)) {
6841 return range
.forget();
6845 nsDocument::CreateNodeIterator(nsIDOMNode
*aRoot
,
6846 uint32_t aWhatToShow
,
6847 nsIDOMNodeFilter
*aFilter
,
6848 uint8_t aOptionalArgc
,
6849 nsIDOMNodeIterator
**_retval
)
6853 if (!aOptionalArgc
) {
6854 aWhatToShow
= nsIDOMNodeFilter::SHOW_ALL
;
6858 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
6861 nsCOMPtr
<nsINode
> root
= do_QueryInterface(aRoot
);
6862 NS_ENSURE_TRUE(root
, NS_ERROR_UNEXPECTED
);
6865 NodeFilterHolder
holder(aFilter
);
6866 *_retval
= nsIDocument::CreateNodeIterator(*root
, aWhatToShow
, holder
,
6868 return rv
.ErrorCode();
6871 already_AddRefed
<NodeIterator
>
6872 nsIDocument::CreateNodeIterator(nsINode
& aRoot
, uint32_t aWhatToShow
,
6873 NodeFilter
* aFilter
,
6874 ErrorResult
& rv
) const
6876 NodeFilterHolder
holder(aFilter
);
6877 return CreateNodeIterator(aRoot
, aWhatToShow
, holder
, rv
);
6880 already_AddRefed
<NodeIterator
>
6881 nsIDocument::CreateNodeIterator(nsINode
& aRoot
, uint32_t aWhatToShow
,
6882 const NodeFilterHolder
& aFilter
,
6883 ErrorResult
& rv
) const
6885 nsINode
* root
= &aRoot
;
6886 nsRefPtr
<NodeIterator
> iterator
= new NodeIterator(root
, aWhatToShow
,
6888 return iterator
.forget();
6892 nsDocument::CreateTreeWalker(nsIDOMNode
*aRoot
,
6893 uint32_t aWhatToShow
,
6894 nsIDOMNodeFilter
*aFilter
,
6895 uint8_t aOptionalArgc
,
6896 nsIDOMTreeWalker
**_retval
)
6900 if (!aOptionalArgc
) {
6901 aWhatToShow
= nsIDOMNodeFilter::SHOW_ALL
;
6904 nsCOMPtr
<nsINode
> root
= do_QueryInterface(aRoot
);
6905 NS_ENSURE_TRUE(root
, NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
6908 NodeFilterHolder
holder(aFilter
);
6909 *_retval
= nsIDocument::CreateTreeWalker(*root
, aWhatToShow
, holder
,
6911 return rv
.ErrorCode();
6914 already_AddRefed
<TreeWalker
>
6915 nsIDocument::CreateTreeWalker(nsINode
& aRoot
, uint32_t aWhatToShow
,
6916 NodeFilter
* aFilter
,
6917 ErrorResult
& rv
) const
6919 NodeFilterHolder
holder(aFilter
);
6920 return CreateTreeWalker(aRoot
, aWhatToShow
, holder
, rv
);
6923 already_AddRefed
<TreeWalker
>
6924 nsIDocument::CreateTreeWalker(nsINode
& aRoot
, uint32_t aWhatToShow
,
6925 const NodeFilterHolder
& aFilter
,
6926 ErrorResult
& rv
) const
6928 nsINode
* root
= &aRoot
;
6929 nsRefPtr
<TreeWalker
> walker
= new TreeWalker(root
, aWhatToShow
, aFilter
);
6930 return walker
.forget();
6935 nsDocument::GetDefaultView(nsIDOMWindow
** aDefaultView
)
6937 *aDefaultView
= nullptr;
6938 nsCOMPtr
<nsPIDOMWindow
> win
= GetWindow();
6939 win
.forget(aDefaultView
);
6944 nsDocument::GetLocation(nsIDOMLocation
**_retval
)
6946 *_retval
= nsIDocument::GetLocation().take();
6950 already_AddRefed
<nsLocation
>
6951 nsIDocument::GetLocation() const
6953 nsCOMPtr
<nsIDOMWindow
> w
= do_QueryInterface(mScriptGlobalObject
);
6959 nsCOMPtr
<nsIDOMLocation
> loc
;
6960 w
->GetLocation(getter_AddRefs(loc
));
6961 return loc
.forget().downcast
<nsLocation
>();
6965 nsIDocument::GetHtmlElement() const
6967 Element
* rootElement
= GetRootElement();
6968 if (rootElement
&& rootElement
->IsHTML(nsGkAtoms::html
))
6974 nsIDocument::GetHtmlChildElement(nsIAtom
* aTag
)
6976 Element
* html
= GetHtmlElement();
6980 // Look for the element with aTag inside html. This needs to run
6981 // forwards to find the first such element.
6982 for (nsIContent
* child
= html
->GetFirstChild();
6984 child
= child
->GetNextSibling()) {
6985 if (child
->IsHTML(aTag
))
6986 return child
->AsElement();
6992 nsDocument::GetTitleContent(uint32_t aNamespace
)
6994 // mMayHaveTitleElement will have been set to true if any HTML or SVG
6995 // <title> element has been bound to this document. So if it's false,
6996 // we know there is nothing to do here. This avoids us having to search
6997 // the whole DOM if someone calls document.title on a large document
6999 if (!mMayHaveTitleElement
)
7002 nsRefPtr
<nsContentList
> list
=
7003 NS_GetContentList(this, aNamespace
, NS_LITERAL_STRING("title"));
7005 return list
->Item(0, false);
7009 nsDocument::GetTitleFromElement(uint32_t aNamespace
, nsAString
& aTitle
)
7011 nsIContent
* title
= GetTitleContent(aNamespace
);
7014 if(!nsContentUtils::GetNodeTextContent(title
, false, aTitle
))
7015 NS_RUNTIMEABORT("OOM");
7019 nsDocument::GetTitle(nsAString
& aTitle
)
7028 nsDocument::GetTitle(nsString
& aTitle
)
7032 nsIContent
*rootElement
= GetRootElement();
7038 switch (rootElement
->GetNameSpaceID()) {
7040 case kNameSpaceID_XUL
:
7041 rootElement
->GetAttr(kNameSpaceID_None
, nsGkAtoms::title
, tmp
);
7044 case kNameSpaceID_SVG
:
7045 if (rootElement
->Tag() == nsGkAtoms::svg
) {
7046 GetTitleFromElement(kNameSpaceID_SVG
, tmp
);
7048 } // else fall through
7050 GetTitleFromElement(kNameSpaceID_XHTML
, tmp
);
7054 tmp
.CompressWhitespace();
7059 nsDocument::SetTitle(const nsAString
& aTitle
)
7061 Element
*rootElement
= GetRootElement();
7065 switch (rootElement
->GetNameSpaceID()) {
7066 case kNameSpaceID_SVG
:
7067 return NS_OK
; // SVG doesn't support setting a title
7069 case kNameSpaceID_XUL
:
7070 return rootElement
->SetAttr(kNameSpaceID_None
, nsGkAtoms::title
,
7075 // Batch updates so that mutation events don't change "the title
7076 // element" under us
7077 mozAutoDocUpdate
updateBatch(this, UPDATE_CONTENT_MODEL
, true);
7079 nsIContent
* title
= GetTitleContent(kNameSpaceID_XHTML
);
7081 Element
*head
= GetHeadElement();
7086 nsRefPtr
<mozilla::dom::NodeInfo
> titleInfo
;
7087 titleInfo
= mNodeInfoManager
->GetNodeInfo(nsGkAtoms::title
, nullptr,
7089 nsIDOMNode::ELEMENT_NODE
);
7090 title
= NS_NewHTMLTitleElement(titleInfo
.forget());
7095 head
->AppendChildTo(title
, true);
7098 return nsContentUtils::SetNodeTextContent(title
, aTitle
, false);
7102 nsDocument::SetTitle(const nsAString
& aTitle
, ErrorResult
& rv
)
7104 rv
= SetTitle(aTitle
);
7108 nsDocument::NotifyPossibleTitleChange(bool aBoundTitleElement
)
7110 NS_ASSERTION(!mInUnlinkOrDeletion
|| !aBoundTitleElement
,
7111 "Setting a title while unlinking or destroying the element?");
7112 if (mInUnlinkOrDeletion
) {
7116 if (aBoundTitleElement
) {
7117 mMayHaveTitleElement
= true;
7119 if (mPendingTitleChangeEvent
.IsPending())
7122 nsRefPtr
<nsRunnableMethod
<nsDocument
, void, false> > event
=
7123 NS_NewNonOwningRunnableMethod(this,
7124 &nsDocument::DoNotifyPossibleTitleChange
);
7125 nsresult rv
= NS_DispatchToCurrentThread(event
);
7126 if (NS_SUCCEEDED(rv
)) {
7127 mPendingTitleChangeEvent
= event
;
7132 nsDocument::DoNotifyPossibleTitleChange()
7134 mPendingTitleChangeEvent
.Forget();
7135 mHaveFiredTitleChange
= true;
7140 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
7142 nsCOMPtr
<nsISupports
> container
=
7143 shell
->GetPresContext()->GetContainerWeak();
7145 nsCOMPtr
<nsIBaseWindow
> docShellWin
= do_QueryInterface(container
);
7147 docShellWin
->SetTitle(title
.get());
7152 // Fire a DOM event for the title change.
7153 nsContentUtils::DispatchChromeEvent(this, static_cast<nsIDocument
*>(this),
7154 NS_LITERAL_STRING("DOMTitleChanged"),
7158 already_AddRefed
<BoxObject
>
7159 nsDocument::GetBoxObjectFor(Element
* aElement
, ErrorResult
& aRv
)
7162 aRv
.Throw(NS_ERROR_UNEXPECTED
);
7166 nsIDocument
* doc
= aElement
->OwnerDoc();
7168 aRv
.Throw(NS_ERROR_DOM_WRONG_DOCUMENT_ERR
);
7172 if (!mHasWarnedAboutBoxObjects
&& !aElement
->IsXUL()) {
7173 mHasWarnedAboutBoxObjects
= true;
7174 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag
,
7175 NS_LITERAL_CSTRING("BoxObjects"), this,
7176 nsContentUtils::eDOM_PROPERTIES
,
7177 "UseOfGetBoxObjectForWarning");
7180 if (!mBoxObjectTable
) {
7181 mBoxObjectTable
= new nsInterfaceHashtable
<nsPtrHashKey
<nsIContent
>, nsPIBoxObject
>(6);
7183 nsCOMPtr
<nsPIBoxObject
> boxObject
= mBoxObjectTable
->Get(aElement
);
7185 return boxObject
.forget().downcast
<BoxObject
>();
7189 int32_t namespaceID
;
7190 nsCOMPtr
<nsIAtom
> tag
= BindingManager()->ResolveTag(aElement
, &namespaceID
);
7192 nsAutoCString
contractID("@mozilla.org/layout/xul-boxobject");
7193 if (namespaceID
== kNameSpaceID_XUL
) {
7194 if (tag
== nsGkAtoms::browser
||
7195 tag
== nsGkAtoms::editor
||
7196 tag
== nsGkAtoms::iframe
)
7197 contractID
+= "-container";
7198 else if (tag
== nsGkAtoms::menu
)
7199 contractID
+= "-menu";
7200 else if (tag
== nsGkAtoms::popup
||
7201 tag
== nsGkAtoms::menupopup
||
7202 tag
== nsGkAtoms::panel
||
7203 tag
== nsGkAtoms::tooltip
)
7204 contractID
+= "-popup";
7205 else if (tag
== nsGkAtoms::tree
)
7206 contractID
+= "-tree";
7207 else if (tag
== nsGkAtoms::listbox
)
7208 contractID
+= "-listbox";
7209 else if (tag
== nsGkAtoms::scrollbox
)
7210 contractID
+= "-scrollbox";
7214 nsCOMPtr
<nsPIBoxObject
> boxObject(do_CreateInstance(contractID
.get()));
7216 aRv
.Throw(NS_ERROR_FAILURE
);
7220 boxObject
->Init(aElement
);
7222 if (mBoxObjectTable
) {
7223 mBoxObjectTable
->Put(aElement
, boxObject
.get());
7226 return boxObject
.forget().downcast
<BoxObject
>();
7230 nsDocument::ClearBoxObjectFor(nsIContent
* aContent
)
7232 if (mBoxObjectTable
) {
7233 nsPIBoxObject
*boxObject
= mBoxObjectTable
->GetWeak(aContent
);
7236 mBoxObjectTable
->Remove(aContent
);
7241 already_AddRefed
<MediaQueryList
>
7242 nsIDocument::MatchMedia(const nsAString
& aMediaQueryList
)
7244 nsRefPtr
<MediaQueryList
> result
= new MediaQueryList(this, aMediaQueryList
);
7246 // Insert the new item at the end of the linked list.
7247 PR_INSERT_BEFORE(result
, &mDOMMediaQueryLists
);
7249 return result
.forget();
7253 nsDocument::FlushSkinBindings()
7255 BindingManager()->FlushSkinBindings();
7259 nsDocument::InitializeFrameLoader(nsFrameLoader
* aLoader
)
7261 mInitializableFrameLoaders
.RemoveElement(aLoader
);
7262 // Don't even try to initialize.
7263 if (mInDestructor
) {
7264 NS_WARNING("Trying to initialize a frame loader while"
7265 "document is being deleted");
7266 return NS_ERROR_FAILURE
;
7269 mInitializableFrameLoaders
.AppendElement(aLoader
);
7270 if (!mFrameLoaderRunner
) {
7271 mFrameLoaderRunner
=
7272 NS_NewRunnableMethod(this, &nsDocument::MaybeInitializeFinalizeFrameLoaders
);
7273 NS_ENSURE_TRUE(mFrameLoaderRunner
, NS_ERROR_OUT_OF_MEMORY
);
7274 nsContentUtils::AddScriptRunner(mFrameLoaderRunner
);
7280 nsDocument::FinalizeFrameLoader(nsFrameLoader
* aLoader
)
7282 mInitializableFrameLoaders
.RemoveElement(aLoader
);
7283 if (mInDestructor
) {
7284 return NS_ERROR_FAILURE
;
7287 mFinalizableFrameLoaders
.AppendElement(aLoader
);
7288 if (!mFrameLoaderRunner
) {
7289 mFrameLoaderRunner
=
7290 NS_NewRunnableMethod(this, &nsDocument::MaybeInitializeFinalizeFrameLoaders
);
7291 NS_ENSURE_TRUE(mFrameLoaderRunner
, NS_ERROR_OUT_OF_MEMORY
);
7292 nsContentUtils::AddScriptRunner(mFrameLoaderRunner
);
7298 nsDocument::MaybeInitializeFinalizeFrameLoaders()
7300 if (mDelayFrameLoaderInitialization
|| mUpdateNestLevel
!= 0) {
7301 // This method will be recalled when mUpdateNestLevel drops to 0,
7302 // or when !mDelayFrameLoaderInitialization.
7303 mFrameLoaderRunner
= nullptr;
7307 // We're not in an update, but it is not safe to run scripts, so
7308 // postpone frameloader initialization and finalization.
7309 if (!nsContentUtils::IsSafeToRunScript()) {
7310 if (!mInDestructor
&& !mFrameLoaderRunner
&&
7311 (mInitializableFrameLoaders
.Length() ||
7312 mFinalizableFrameLoaders
.Length())) {
7313 mFrameLoaderRunner
=
7314 NS_NewRunnableMethod(this, &nsDocument::MaybeInitializeFinalizeFrameLoaders
);
7315 nsContentUtils::AddScriptRunner(mFrameLoaderRunner
);
7319 mFrameLoaderRunner
= nullptr;
7321 // Don't use a temporary array for mInitializableFrameLoaders, because
7322 // loading a frame may cause some other frameloader to be removed from the
7323 // array. But be careful to keep the loader alive when starting the load!
7324 while (mInitializableFrameLoaders
.Length()) {
7325 nsRefPtr
<nsFrameLoader
> loader
= mInitializableFrameLoaders
[0];
7326 mInitializableFrameLoaders
.RemoveElementAt(0);
7327 NS_ASSERTION(loader
, "null frameloader in the array?");
7328 loader
->ReallyStartLoading();
7331 uint32_t length
= mFinalizableFrameLoaders
.Length();
7333 nsTArray
<nsRefPtr
<nsFrameLoader
> > loaders
;
7334 mFinalizableFrameLoaders
.SwapElements(loaders
);
7335 for (uint32_t i
= 0; i
< length
; ++i
) {
7336 loaders
[i
]->Finalize();
7342 nsDocument::TryCancelFrameLoaderInitialization(nsIDocShell
* aShell
)
7344 uint32_t length
= mInitializableFrameLoaders
.Length();
7345 for (uint32_t i
= 0; i
< length
; ++i
) {
7346 if (mInitializableFrameLoaders
[i
]->GetExistingDocShell() == aShell
) {
7347 mInitializableFrameLoaders
.RemoveElementAt(i
);
7354 nsDocument::FrameLoaderScheduledToBeFinalized(nsIDocShell
* aShell
)
7357 uint32_t length
= mFinalizableFrameLoaders
.Length();
7358 for (uint32_t i
= 0; i
< length
; ++i
) {
7359 if (mFinalizableFrameLoaders
[i
]->GetExistingDocShell() == aShell
) {
7368 nsDocument::RequestExternalResource(nsIURI
* aURI
,
7369 nsINode
* aRequestingNode
,
7370 ExternalResourceLoad
** aPendingLoad
)
7372 NS_PRECONDITION(aURI
, "Must have a URI");
7373 NS_PRECONDITION(aRequestingNode
, "Must have a node");
7374 if (mDisplayDocument
) {
7375 return mDisplayDocument
->RequestExternalResource(aURI
,
7380 return mExternalResourceMap
.RequestResource(aURI
, aRequestingNode
,
7381 this, aPendingLoad
);
7385 nsDocument::EnumerateExternalResources(nsSubDocEnumFunc aCallback
, void* aData
)
7387 mExternalResourceMap
.EnumerateResources(aCallback
, aData
);
7390 nsSMILAnimationController
*
7391 nsDocument::GetAnimationController()
7393 // We create the animation controller lazily because most documents won't want
7394 // one and only SVG documents and the like will call this
7395 if (mAnimationController
)
7396 return mAnimationController
;
7397 // Refuse to create an Animation Controller for data documents.
7398 if (mLoadedAsData
|| mLoadedAsInteractiveData
)
7401 mAnimationController
= new nsSMILAnimationController(this);
7403 // If there's a presContext then check the animation mode and pause if
7405 nsIPresShell
*shell
= GetShell();
7406 if (mAnimationController
&& shell
) {
7407 nsPresContext
*context
= shell
->GetPresContext();
7409 context
->ImageAnimationMode() == imgIContainer::kDontAnimMode
) {
7410 mAnimationController
->Pause(nsSMILTimeContainer::PAUSE_USERPREF
);
7414 // If we're hidden (or being hidden), notify the newly-created animation
7415 // controller. (Skip this check for SVG-as-an-image documents, though,
7416 // because they don't get OnPageShow / OnPageHide calls).
7417 if (!mIsShowing
&& !mIsBeingUsedAsImage
) {
7418 mAnimationController
->OnPageHide();
7421 return mAnimationController
;
7424 PendingPlayerTracker
*
7425 nsDocument::GetOrCreatePendingPlayerTracker()
7427 if (!mPendingPlayerTracker
) {
7428 mPendingPlayerTracker
= new PendingPlayerTracker(this);
7431 return mPendingPlayerTracker
;
7435 * Retrieve the "direction" property of the document.
7440 nsDocument::GetDir(nsAString
& aDirection
)
7442 nsIDocument::GetDir(aDirection
);
7447 nsIDocument::GetDir(nsAString
& aDirection
) const
7449 aDirection
.Truncate();
7450 Element
* rootElement
= GetHtmlElement();
7452 static_cast<nsGenericHTMLElement
*>(rootElement
)->GetDir(aDirection
);
7457 * Set the "direction" property of the document.
7462 nsDocument::SetDir(const nsAString
& aDirection
)
7464 nsIDocument::SetDir(aDirection
);
7469 nsIDocument::SetDir(const nsAString
& aDirection
)
7471 Element
* rootElement
= GetHtmlElement();
7473 rootElement
->SetAttr(kNameSpaceID_None
, nsGkAtoms::dir
,
7479 nsDocument::GetInputEncoding(nsAString
& aInputEncoding
)
7481 nsIDocument::GetInputEncoding(aInputEncoding
);
7486 nsIDocument::GetInputEncoding(nsAString
& aInputEncoding
)
7488 // Not const function, because WarnOnceAbout is not a const method
7489 WarnOnceAbout(eInputEncoding
);
7490 if (mHaveInputEncoding
) {
7491 return GetCharacterSet(aInputEncoding
);
7494 SetDOMStringToNull(aInputEncoding
);
7498 nsDocument::GetMozSyntheticDocument(bool *aSyntheticDocument
)
7500 *aSyntheticDocument
= mIsSyntheticDocument
;
7505 nsDocument::GetDocumentURI(nsAString
& aDocumentURI
)
7508 nsIDocument::GetDocumentURI(temp
);
7509 aDocumentURI
= temp
;
7514 nsIDocument::GetDocumentURI(nsString
& aDocumentURI
) const
7518 mDocumentURI
->GetSpec(uri
);
7519 CopyUTF8toUTF16(uri
, aDocumentURI
);
7521 aDocumentURI
.Truncate();
7527 nsDocument::GetURL(nsAString
& aURL
)
7529 return GetDocumentURI(aURL
);
7533 nsIDocument::GetURL(nsString
& aURL
) const
7535 return GetDocumentURI(aURL
);
7539 nsIDocument::GetDocumentURIFromJS(nsString
& aDocumentURI
) const
7541 if (!mChromeXHRDocURI
|| !nsContentUtils::IsCallerChrome()) {
7542 return GetDocumentURI(aDocumentURI
);
7546 mChromeXHRDocURI
->GetSpec(uri
);
7547 CopyUTF8toUTF16(uri
, aDocumentURI
);
7551 nsIDocument::GetDocumentURIObject() const
7553 if (!mChromeXHRDocURI
) {
7554 return GetDocumentURI();
7557 return mChromeXHRDocURI
;
7561 // readonly attribute DOMString compatMode;
7562 // Returns "BackCompat" if we are in quirks mode, "CSS1Compat" if we are
7563 // in almost standards or full standards mode. See bug 105640. This was
7564 // implemented to match MSIE's compatMode property.
7566 nsDocument::GetCompatMode(nsAString
& aCompatMode
)
7569 nsIDocument::GetCompatMode(temp
);
7575 nsIDocument::GetCompatMode(nsString
& aCompatMode
) const
7577 NS_ASSERTION(mCompatMode
== eCompatibility_NavQuirks
||
7578 mCompatMode
== eCompatibility_AlmostStandards
||
7579 mCompatMode
== eCompatibility_FullStandards
,
7580 "mCompatMode is neither quirks nor strict for this document");
7582 if (mCompatMode
== eCompatibility_NavQuirks
) {
7583 aCompatMode
.AssignLiteral("BackCompat");
7585 aCompatMode
.AssignLiteral("CSS1Compat");
7589 static void BlastSubtreeToPieces(nsINode
*aNode
);
7592 BlastFunc(nsAttrHashKey::KeyType aKey
, Attr
*aData
, void* aUserArg
)
7594 nsCOMPtr
<nsIAttribute
> *attr
=
7595 static_cast<nsCOMPtr
<nsIAttribute
>*>(aUserArg
);
7599 NS_ASSERTION(attr
->get(),
7600 "non-nsIAttribute somehow made it into the hashmap?!");
7602 return PL_DHASH_STOP
;
7606 BlastSubtreeToPieces(nsINode
*aNode
)
7608 if (aNode
->IsElement()) {
7609 Element
*element
= aNode
->AsElement();
7610 const nsDOMAttributeMap
*map
= element
->GetAttributeMap();
7612 nsCOMPtr
<nsIAttribute
> attr
;
7613 while (map
->Enumerate(BlastFunc
, &attr
) > 0) {
7614 BlastSubtreeToPieces(attr
);
7619 element
->UnsetAttr(attr
->NodeInfo()->NamespaceID(),
7620 attr
->NodeInfo()->NameAtom(),
7623 // XXX Should we abort here?
7624 NS_ASSERTION(NS_SUCCEEDED(rv
), "Uhoh, UnsetAttr shouldn't fail!");
7629 uint32_t count
= aNode
->GetChildCount();
7630 for (uint32_t i
= 0; i
< count
; ++i
) {
7631 BlastSubtreeToPieces(aNode
->GetFirstChild());
7632 aNode
->RemoveChildAt(0, false);
7637 nsDocument::AdoptNode(nsIDOMNode
*aAdoptedNode
, nsIDOMNode
**aResult
)
7641 nsCOMPtr
<nsINode
> adoptedNode
= do_QueryInterface(aAdoptedNode
);
7642 NS_ENSURE_TRUE(adoptedNode
, NS_ERROR_UNEXPECTED
);
7645 nsINode
* result
= nsIDocument::AdoptNode(*adoptedNode
, rv
);
7647 return rv
.ErrorCode();
7650 NS_ADDREF(*aResult
= result
->AsDOMNode());
7655 nsIDocument::AdoptNode(nsINode
& aAdoptedNode
, ErrorResult
& rv
)
7657 nsINode
* adoptedNode
= &aAdoptedNode
;
7659 // Scope firing mutation events so that we don't carry any state that
7662 nsINode
* parent
= adoptedNode
->GetParentNode();
7664 nsContentUtils::MaybeFireNodeRemoved(adoptedNode
, parent
,
7665 adoptedNode
->OwnerDoc());
7669 nsAutoScriptBlocker scriptBlocker
;
7671 switch (adoptedNode
->NodeType()) {
7672 case nsIDOMNode::ATTRIBUTE_NODE
:
7674 // Remove from ownerElement.
7675 nsRefPtr
<Attr
> adoptedAttr
= static_cast<Attr
*>(adoptedNode
);
7677 nsCOMPtr
<Element
> ownerElement
= adoptedAttr
->GetOwnerElement(rv
);
7683 nsRefPtr
<Attr
> newAttr
=
7684 ownerElement
->RemoveAttributeNode(*adoptedAttr
, rv
);
7689 newAttr
.swap(adoptedAttr
);
7694 case nsIDOMNode::DOCUMENT_FRAGMENT_NODE
:
7695 case nsIDOMNode::ELEMENT_NODE
:
7696 case nsIDOMNode::PROCESSING_INSTRUCTION_NODE
:
7697 case nsIDOMNode::TEXT_NODE
:
7698 case nsIDOMNode::CDATA_SECTION_NODE
:
7699 case nsIDOMNode::COMMENT_NODE
:
7700 case nsIDOMNode::DOCUMENT_TYPE_NODE
:
7702 // Don't allow adopting a node's anonymous subtree out from under it.
7703 if (adoptedNode
->AsContent()->IsRootOfAnonymousSubtree()) {
7704 rv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
7708 // We don't want to adopt an element into its own contentDocument or into
7709 // a descendant contentDocument, so we check if the frameElement of this
7710 // document or any of its parents is the adopted node or one of its
7712 nsIDocument
*doc
= this;
7714 nsPIDOMWindow
*win
= doc
->GetWindow();
7716 nsCOMPtr
<nsINode
> node
= win
->GetFrameElementInternal();
7718 nsContentUtils::ContentIsDescendantOf(node
, adoptedNode
)) {
7719 rv
.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
);
7723 } while ((doc
= doc
->GetParentDocument()));
7725 // Remove from parent.
7726 nsCOMPtr
<nsINode
> parent
= adoptedNode
->GetParentNode();
7728 int32_t idx
= parent
->IndexOf(adoptedNode
);
7729 MOZ_ASSERT(idx
>= 0);
7730 parent
->RemoveChildAt(idx
, true);
7732 MOZ_ASSERT(!adoptedNode
->IsInDoc());
7734 // If we're adopting a node that's not in a document, it might still
7735 // have a binding applied. Remove the binding from the element now
7736 // that it's getting adopted into a new document.
7737 // TODO Fully tear down the binding.
7738 adoptedNode
->AsContent()->SetXBLBinding(nullptr);
7743 case nsIDOMNode::DOCUMENT_NODE
:
7745 rv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
7750 NS_WARNING("Don't know how to adopt this nodetype for adoptNode.");
7752 rv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
7757 nsCOMPtr
<nsIDocument
> oldDocument
= adoptedNode
->OwnerDoc();
7758 bool sameDocument
= oldDocument
== this;
7761 JS::Rooted
<JSObject
*> newScope(cx
, nullptr);
7762 if (!sameDocument
) {
7763 newScope
= GetWrapper();
7764 if (!newScope
&& GetScopeObject() && GetScopeObject()->GetGlobalJSObject()) {
7765 // Make sure cx is in a semi-sane compartment before we call WrapNative.
7766 // It's kind of irrelevant, given that we're passing aAllowWrapping =
7767 // false, and documents should always insist on being wrapped in an
7768 // canonical scope. But we try to pass something sane anyway.
7769 JSAutoCompartment
ac(cx
, GetScopeObject()->GetGlobalJSObject());
7770 JS::Rooted
<JS::Value
> v(cx
);
7771 rv
= nsContentUtils::WrapNative(cx
, this, this, &v
,
7772 /* aAllowWrapping = */ false);
7775 newScope
= &v
.toObject();
7779 nsCOMArray
<nsINode
> nodesWithProperties
;
7780 rv
= nsNodeUtils::Adopt(adoptedNode
, sameDocument
? nullptr : mNodeInfoManager
,
7781 newScope
, nodesWithProperties
);
7783 // Disconnect all nodes from their parents, since some have the old document
7784 // as their ownerDocument and some have this as their ownerDocument.
7785 BlastSubtreeToPieces(adoptedNode
);
7787 if (!sameDocument
&& oldDocument
) {
7788 uint32_t count
= nodesWithProperties
.Count();
7789 for (uint32_t j
= 0; j
< oldDocument
->GetPropertyTableCount(); ++j
) {
7790 for (uint32_t i
= 0; i
< count
; ++i
) {
7791 // Remove all properties.
7792 oldDocument
->PropertyTable(j
)->
7793 DeleteAllPropertiesFor(nodesWithProperties
[i
]);
7801 uint32_t count
= nodesWithProperties
.Count();
7802 if (!sameDocument
&& oldDocument
) {
7803 for (uint32_t j
= 0; j
< oldDocument
->GetPropertyTableCount(); ++j
) {
7804 nsPropertyTable
*oldTable
= oldDocument
->PropertyTable(j
);
7805 nsPropertyTable
*newTable
= PropertyTable(j
);
7806 for (uint32_t i
= 0; i
< count
; ++i
) {
7807 rv
= oldTable
->TransferOrDeleteAllPropertiesFor(nodesWithProperties
[i
],
7813 // Disconnect all nodes from their parents.
7814 BlastSubtreeToPieces(adoptedNode
);
7820 NS_ASSERTION(adoptedNode
->OwnerDoc() == this,
7821 "Should still be in the document we just got adopted into");
7827 nsDocument::GetViewportInfo(const ScreenIntSize
& aDisplaySize
)
7829 // Compute the CSS-to-LayoutDevice pixel scale as the product of the
7830 // widget scale and the full zoom.
7831 nsPresContext
* context
= mPresShell
->GetPresContext();
7832 float fullZoom
= context
? context
->GetFullZoom() : 1.0;
7833 fullZoom
= (fullZoom
== 0.0) ? 1.0 : fullZoom
;
7834 nsIWidget
*widget
= nsContentUtils::WidgetForDocument(this);
7835 float widgetScale
= widget
? widget
->GetDefaultScale().scale
: 1.0f
;
7836 CSSToLayoutDeviceScale
layoutDeviceScale(widgetScale
* fullZoom
);
7838 CSSToScreenScale defaultScale
= layoutDeviceScale
7839 * LayoutDeviceToScreenScale(1.0);
7841 if (!Preferences::GetBool("dom.meta-viewport.enabled", false)) {
7842 return nsViewportInfo(aDisplaySize
,
7844 /*allowZoom*/ false,
7845 /*allowDoubleTapZoom*/ true);
7848 // In cases where the width of the CSS viewport is less than or equal to the width
7849 // of the display (i.e. width <= device-width) then we disable double-tap-to-zoom
7850 // behaviour. See bug 941995 for details.
7852 switch (mViewportType
) {
7853 case DisplayWidthHeight
:
7854 return nsViewportInfo(aDisplaySize
,
7857 /*allowDoubleTapZoom*/ true);
7858 case DisplayWidthHeightNoZoom
:
7859 return nsViewportInfo(aDisplaySize
,
7861 /*allowZoom*/ false,
7862 /*allowDoubleTapZoom*/ false);
7865 nsAutoString viewport
;
7866 GetHeaderData(nsGkAtoms::viewport
, viewport
);
7867 if (viewport
.IsEmpty()) {
7868 // If the docType specifies that we are on a site optimized for mobile,
7869 // then we want to return specially crafted defaults for the viewport info.
7870 nsCOMPtr
<nsIDOMDocumentType
> docType
;
7871 nsresult rv
= GetDoctype(getter_AddRefs(docType
));
7872 if (NS_SUCCEEDED(rv
) && docType
) {
7874 rv
= docType
->GetPublicId(docId
);
7875 if (NS_SUCCEEDED(rv
)) {
7876 if ((docId
.Find("WAP") != -1) ||
7877 (docId
.Find("Mobile") != -1) ||
7878 (docId
.Find("WML") != -1))
7880 // We're making an assumption that the docType can't change here
7881 mViewportType
= DisplayWidthHeight
;
7882 return nsViewportInfo(aDisplaySize
,
7885 /*allowDoubleTapZoom*/false);
7890 nsAutoString handheldFriendly
;
7891 GetHeaderData(nsGkAtoms::handheldFriendly
, handheldFriendly
);
7892 if (handheldFriendly
.EqualsLiteral("true")) {
7893 mViewportType
= DisplayWidthHeight
;
7894 return nsViewportInfo(aDisplaySize
,
7897 /*allowDoubleTapZoom*/false);
7901 nsAutoString minScaleStr
;
7902 GetHeaderData(nsGkAtoms::viewport_minimum_scale
, minScaleStr
);
7905 mScaleMinFloat
= LayoutDeviceToScreenScale(minScaleStr
.ToFloat(&errorCode
));
7907 if (NS_FAILED(errorCode
)) {
7908 mScaleMinFloat
= kViewportMinScale
;
7911 mScaleMinFloat
= mozilla::clamped(
7912 mScaleMinFloat
, kViewportMinScale
, kViewportMaxScale
);
7914 nsAutoString maxScaleStr
;
7915 GetHeaderData(nsGkAtoms::viewport_maximum_scale
, maxScaleStr
);
7917 // We define a special error code variable for the scale and max scale,
7918 // because they are used later (see the width calculations).
7919 nsresult scaleMaxErrorCode
;
7920 mScaleMaxFloat
= LayoutDeviceToScreenScale(maxScaleStr
.ToFloat(&scaleMaxErrorCode
));
7922 if (NS_FAILED(scaleMaxErrorCode
)) {
7923 mScaleMaxFloat
= kViewportMaxScale
;
7926 mScaleMaxFloat
= mozilla::clamped(
7927 mScaleMaxFloat
, kViewportMinScale
, kViewportMaxScale
);
7929 nsAutoString scaleStr
;
7930 GetHeaderData(nsGkAtoms::viewport_initial_scale
, scaleStr
);
7932 nsresult scaleErrorCode
;
7933 mScaleFloat
= LayoutDeviceToScreenScale(scaleStr
.ToFloat(&scaleErrorCode
));
7935 nsAutoString widthStr
, heightStr
;
7937 GetHeaderData(nsGkAtoms::viewport_height
, heightStr
);
7938 GetHeaderData(nsGkAtoms::viewport_width
, widthStr
);
7942 if (widthStr
.EqualsLiteral("device-width")) {
7946 if (widthStr
.IsEmpty() &&
7947 (heightStr
.EqualsLiteral("device-height") ||
7948 (mScaleFloat
.scale
== 1.0)))
7953 nsresult widthErrorCode
, heightErrorCode
;
7954 mViewportSize
.width
= widthStr
.ToInteger(&widthErrorCode
);
7955 mViewportSize
.height
= heightStr
.ToInteger(&heightErrorCode
);
7957 // If width or height has not been set to a valid number by this point,
7958 // fall back to a default value.
7959 mValidWidth
= (!widthStr
.IsEmpty() && NS_SUCCEEDED(widthErrorCode
) && mViewportSize
.width
> 0);
7960 mValidHeight
= (!heightStr
.IsEmpty() && NS_SUCCEEDED(heightErrorCode
) && mViewportSize
.height
> 0);
7963 nsAutoString userScalable
;
7964 GetHeaderData(nsGkAtoms::viewport_user_scalable
, userScalable
);
7966 if ((userScalable
.EqualsLiteral("0")) ||
7967 (userScalable
.EqualsLiteral("no")) ||
7968 (userScalable
.EqualsLiteral("false"))) {
7971 mAllowDoubleTapZoom
= mAllowZoom
;
7973 mScaleStrEmpty
= scaleStr
.IsEmpty();
7974 mWidthStrEmpty
= widthStr
.IsEmpty();
7975 mValidScaleFloat
= !scaleStr
.IsEmpty() && NS_SUCCEEDED(scaleErrorCode
);
7976 mValidMaxScale
= !maxScaleStr
.IsEmpty() && NS_SUCCEEDED(scaleMaxErrorCode
);
7978 mViewportType
= Specified
;
7982 CSSSize size
= mViewportSize
;
7985 if (mValidHeight
&& !aDisplaySize
.IsEmpty()) {
7986 size
.width
= size
.height
* aDisplaySize
.width
/ aDisplaySize
.height
;
7988 // Stretch CSS pixel size of viewport to keep device pixel size
7989 // unchanged after full zoom applied.
7991 size
.width
= Preferences::GetInt("browser.viewport.desktopWidth",
7992 kViewportDefaultScreenWidth
) / fullZoom
;
7996 if (!mValidHeight
) {
7997 if (!aDisplaySize
.IsEmpty()) {
7998 size
.height
= size
.width
* aDisplaySize
.height
/ aDisplaySize
.width
;
8000 size
.height
= size
.width
;
8004 CSSToScreenScale scaleFloat
= mScaleFloat
* layoutDeviceScale
;
8005 CSSToScreenScale scaleMinFloat
= mScaleMinFloat
* layoutDeviceScale
;
8006 CSSToScreenScale scaleMaxFloat
= mScaleMaxFloat
* layoutDeviceScale
;
8009 // aDisplaySize is in screen pixels; convert them to CSS pixels for the viewport size.
8010 CSSToScreenScale defaultPixelScale
= layoutDeviceScale
* LayoutDeviceToScreenScale(1.0f
);
8011 size
= ScreenSize(aDisplaySize
) / defaultPixelScale
;
8014 size
.width
= clamped(size
.width
, float(kViewportMinSize
.width
), float(kViewportMaxSize
.width
));
8016 // Also recalculate the default zoom, if it wasn't specified in the metadata,
8017 // and the width is specified.
8018 if (mScaleStrEmpty
&& !mWidthStrEmpty
) {
8019 CSSToScreenScale
defaultScale(float(aDisplaySize
.width
) / size
.width
);
8020 scaleFloat
= (scaleFloat
> defaultScale
) ? scaleFloat
: defaultScale
;
8023 size
.height
= clamped(size
.height
, float(kViewportMinSize
.height
), float(kViewportMaxSize
.height
));
8025 // We need to perform a conversion, but only if the initial or maximum
8026 // scale were set explicitly by the user.
8027 if (mValidScaleFloat
) {
8028 CSSSize displaySize
= ScreenSize(aDisplaySize
) / scaleFloat
;
8029 size
.width
= std::max(size
.width
, displaySize
.width
);
8030 size
.height
= std::max(size
.height
, displaySize
.height
);
8031 } else if (mValidMaxScale
) {
8032 CSSSize displaySize
= ScreenSize(aDisplaySize
) / scaleMaxFloat
;
8033 size
.width
= std::max(size
.width
, displaySize
.width
);
8034 size
.height
= std::max(size
.height
, displaySize
.height
);
8037 return nsViewportInfo(scaleFloat
, scaleMinFloat
, scaleMaxFloat
, size
,
8038 mAutoSize
, mAllowZoom
, mAllowDoubleTapZoom
);
8042 EventListenerManager
*
8043 nsDocument::GetOrCreateListenerManager()
8045 if (!mListenerManager
) {
8047 new EventListenerManager(static_cast<EventTarget
*>(this));
8048 SetFlags(NODE_HAS_LISTENERMANAGER
);
8051 return mListenerManager
;
8054 EventListenerManager
*
8055 nsDocument::GetExistingListenerManager() const
8057 return mListenerManager
;
8061 nsDocument::PreHandleEvent(EventChainPreVisitor
& aVisitor
)
8063 aVisitor
.mCanHandle
= true;
8064 // FIXME! This is a hack to make middle mouse paste working also in Editor.
8066 aVisitor
.mForceContentDispatch
= true;
8068 // Load events must not propagate to |window| object, see bug 335251.
8069 if (aVisitor
.mEvent
->message
!= NS_LOAD
) {
8070 nsGlobalWindow
* window
= static_cast<nsGlobalWindow
*>(GetWindow());
8071 aVisitor
.mParentTarget
=
8072 window
? window
->GetTargetForEventTargetChain() : nullptr;
8078 nsDocument::CreateEvent(const nsAString
& aEventType
, nsIDOMEvent
** aReturn
)
8080 NS_ENSURE_ARG_POINTER(aReturn
);
8082 *aReturn
= nsIDocument::CreateEvent(aEventType
, rv
).take();
8083 return rv
.ErrorCode();
8086 already_AddRefed
<Event
>
8087 nsIDocument::CreateEvent(const nsAString
& aEventType
, ErrorResult
& rv
) const
8089 nsIPresShell
*shell
= GetShell();
8091 nsPresContext
*presContext
= nullptr;
8094 // Retrieve the context
8095 presContext
= shell
->GetPresContext();
8098 // Create event even without presContext.
8099 nsCOMPtr
<nsIDOMEvent
> ev
;
8100 rv
= EventDispatcher::CreateEvent(const_cast<nsIDocument
*>(this),
8101 presContext
, nullptr, aEventType
,
8102 getter_AddRefs(ev
));
8106 WidgetEvent
* e
= ev
->GetInternalNSEvent();
8107 e
->mFlags
.mBubbles
= false;
8108 e
->mFlags
.mCancelable
= false;
8109 return dont_AddRef(ev
.forget().take()->InternalDOMEvent());
8113 nsDocument::FlushPendingNotifications(mozFlushType aType
)
8115 nsDocumentOnStack
dos(this);
8117 // We need to flush the sink for non-HTML documents (because the XML
8118 // parser still does insertion with deferred notifications). We
8119 // also need to flush the sink if this is a layout-related flush, to
8120 // make sure that layout is started as needed. But we can skip that
8121 // part if we have no presshell or if it's already done an initial
8124 (aType
> Flush_ContentAndNotify
&& mPresShell
&&
8125 !mPresShell
->DidInitialize())) &&
8126 (mParser
|| mWeakSink
)) {
8127 nsCOMPtr
<nsIContentSink
> sink
;
8129 sink
= mParser
->GetContentSink();
8131 sink
= do_QueryReferent(mWeakSink
);
8133 mWeakSink
= nullptr;
8136 // Determine if it is safe to flush the sink notifications
8137 // by determining if it safe to flush all the presshells.
8138 if (sink
&& (aType
== Flush_Content
|| IsSafeToFlush())) {
8139 sink
->FlushPendingNotifications(aType
);
8143 // Should we be flushing pending binding constructors in here?
8145 if (aType
<= Flush_ContentAndNotify
) {
8146 // Nothing to do here
8150 // If we have a parent we must flush the parent too to ensure that our
8151 // container is reflowed if its size was changed. But if it's not safe to
8152 // flush ourselves, then don't flush the parent, since that can cause things
8153 // like resizes of our frame's widget, which we can't handle while flushing
8155 // Since media queries mean that a size change of our container can
8156 // affect style, we need to promote a style flush on ourself to a
8157 // layout flush on our parent, since we need our container to be the
8158 // correct size to determine the correct style.
8159 if (mParentDocument
&& IsSafeToFlush()) {
8160 mozFlushType parentType
= aType
;
8161 if (aType
>= Flush_Style
)
8162 parentType
= std::max(Flush_Layout
, aType
);
8163 mParentDocument
->FlushPendingNotifications(parentType
);
8166 // We can optimize away getting our presshell and calling
8167 // FlushPendingNotifications on it if we don't need a flush of the sort we're
8168 // looking at. The one exception is if mInFlush is true, because in that
8169 // case we might have set mNeedStyleFlush and mNeedLayoutFlush to false
8170 // already but the presshell hasn't actually done the corresponding work yet.
8171 // So if mInFlush and reentering this code, we need to flush the presshell.
8172 if (mNeedStyleFlush
||
8173 (mNeedLayoutFlush
&& aType
>= Flush_InterruptibleLayout
) ||
8174 aType
>= Flush_Display
||
8176 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
8178 mNeedStyleFlush
= false;
8179 mNeedLayoutFlush
= mNeedLayoutFlush
&& (aType
< Flush_InterruptibleLayout
);
8180 // mInFlush is a bitfield, so can't us AutoRestore here. But we
8181 // need to keep track of multi-level reentry correctly, so need
8182 // to restore the old mInFlush value.
8183 bool oldInFlush
= mInFlush
;
8185 shell
->FlushPendingNotifications(aType
);
8186 mInFlush
= oldInFlush
;
8192 Copy(nsIDocument
* aDocument
, void* aData
)
8194 nsTArray
<nsCOMPtr
<nsIDocument
> >* resources
=
8195 static_cast<nsTArray
<nsCOMPtr
<nsIDocument
> >* >(aData
);
8196 resources
->AppendElement(aDocument
);
8201 nsDocument::FlushExternalResources(mozFlushType aType
)
8203 NS_ASSERTION(aType
>= Flush_Style
,
8204 "should only need to flush for style or higher in external resources");
8205 if (GetDisplayDocument()) {
8208 nsTArray
<nsCOMPtr
<nsIDocument
> > resources
;
8209 EnumerateExternalResources(Copy
, &resources
);
8211 for (uint32_t i
= 0; i
< resources
.Length(); i
++) {
8212 resources
[i
]->FlushPendingNotifications(aType
);
8217 nsDocument::SetXMLDeclaration(const char16_t
*aVersion
,
8218 const char16_t
*aEncoding
,
8219 const int32_t aStandalone
)
8221 if (!aVersion
|| *aVersion
== '\0') {
8222 mXMLDeclarationBits
= 0;
8226 mXMLDeclarationBits
= XML_DECLARATION_BITS_DECLARATION_EXISTS
;
8228 if (aEncoding
&& *aEncoding
!= '\0') {
8229 mXMLDeclarationBits
|= XML_DECLARATION_BITS_ENCODING_EXISTS
;
8232 if (aStandalone
== 1) {
8233 mXMLDeclarationBits
|= XML_DECLARATION_BITS_STANDALONE_EXISTS
|
8234 XML_DECLARATION_BITS_STANDALONE_YES
;
8236 else if (aStandalone
== 0) {
8237 mXMLDeclarationBits
|= XML_DECLARATION_BITS_STANDALONE_EXISTS
;
8242 nsDocument::GetXMLDeclaration(nsAString
& aVersion
, nsAString
& aEncoding
,
8243 nsAString
& aStandalone
)
8245 aVersion
.Truncate();
8246 aEncoding
.Truncate();
8247 aStandalone
.Truncate();
8249 if (!(mXMLDeclarationBits
& XML_DECLARATION_BITS_DECLARATION_EXISTS
)) {
8253 // always until we start supporting 1.1 etc.
8254 aVersion
.AssignLiteral("1.0");
8256 if (mXMLDeclarationBits
& XML_DECLARATION_BITS_ENCODING_EXISTS
) {
8257 // This is what we have stored, not necessarily what was written
8259 GetCharacterSet(aEncoding
);
8262 if (mXMLDeclarationBits
& XML_DECLARATION_BITS_STANDALONE_EXISTS
) {
8263 if (mXMLDeclarationBits
& XML_DECLARATION_BITS_STANDALONE_YES
) {
8264 aStandalone
.AssignLiteral("yes");
8266 aStandalone
.AssignLiteral("no");
8272 nsDocument::IsScriptEnabled()
8274 // If this document is sandboxed without 'allow-scripts'
8275 // script is not enabled
8276 if (mSandboxFlags
& SANDBOXED_SCRIPTS
) {
8280 nsCOMPtr
<nsIScriptSecurityManager
> sm(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
));
8281 NS_ENSURE_TRUE(sm
, false);
8283 nsCOMPtr
<nsIScriptGlobalObject
> globalObject
= do_QueryInterface(GetInnerWindow());
8284 if (!globalObject
&& mMasterDocument
) {
8285 globalObject
= do_QueryInterface(mMasterDocument
->GetInnerWindow());
8287 NS_ENSURE_TRUE(globalObject
&& globalObject
->GetGlobalJSObject(), false);
8289 return sm
->ScriptAllowed(globalObject
->GetGlobalJSObject());
8293 nsDocument::GetRadioGroupInternal(const nsAString
& aName
) const
8297 nsAutoString lcName
;
8298 ToLowerCase(aName
, lcName
);
8299 MOZ_ASSERT(aName
== lcName
);
8303 nsRadioGroupStruct
* radioGroup
;
8304 if (!mRadioGroups
.Get(aName
, &radioGroup
)) {
8312 nsDocument::GetRadioGroup(const nsAString
& aName
) const
8314 nsAutoString
tmKey(aName
);
8316 ToLowerCase(tmKey
); //should case-insensitive.
8319 return GetRadioGroupInternal(tmKey
);
8323 nsDocument::GetOrCreateRadioGroup(const nsAString
& aName
)
8325 nsAutoString
tmKey(aName
);
8327 ToLowerCase(tmKey
); //should case-insensitive.
8330 if (nsRadioGroupStruct
* radioGroup
= GetRadioGroupInternal(tmKey
)) {
8334 nsAutoPtr
<nsRadioGroupStruct
> newRadioGroup(new nsRadioGroupStruct());
8335 mRadioGroups
.Put(tmKey
, newRadioGroup
);
8337 return newRadioGroup
.forget();
8341 nsDocument::SetCurrentRadioButton(const nsAString
& aName
,
8342 HTMLInputElement
* aRadio
)
8344 nsRadioGroupStruct
* radioGroup
= GetOrCreateRadioGroup(aName
);
8345 radioGroup
->mSelectedRadioButton
= aRadio
;
8349 nsDocument::GetCurrentRadioButton(const nsAString
& aName
)
8351 return GetOrCreateRadioGroup(aName
)->mSelectedRadioButton
;
8355 nsDocument::GetNextRadioButton(const nsAString
& aName
,
8356 const bool aPrevious
,
8357 HTMLInputElement
* aFocusedRadio
,
8358 HTMLInputElement
** aRadioOut
)
8360 // XXX Can we combine the HTML radio button method impls of
8361 // nsDocument and nsHTMLFormControl?
8362 // XXX Why is HTML radio button stuff in nsDocument, as
8363 // opposed to nsHTMLDocument?
8364 *aRadioOut
= nullptr;
8366 nsRadioGroupStruct
* radioGroup
= GetOrCreateRadioGroup(aName
);
8368 // Return the radio button relative to the focused radio button.
8369 // If no radio is focused, get the radio relative to the selected one.
8370 nsRefPtr
<HTMLInputElement
> currentRadio
;
8371 if (aFocusedRadio
) {
8372 currentRadio
= aFocusedRadio
;
8375 currentRadio
= radioGroup
->mSelectedRadioButton
;
8376 if (!currentRadio
) {
8377 return NS_ERROR_FAILURE
;
8380 int32_t index
= radioGroup
->mRadioButtons
.IndexOf(currentRadio
);
8382 return NS_ERROR_FAILURE
;
8385 int32_t numRadios
= radioGroup
->mRadioButtons
.Count();
8386 nsRefPtr
<HTMLInputElement
> radio
;
8390 index
= numRadios
-1;
8393 else if (++index
>= numRadios
) {
8396 NS_ASSERTION(static_cast<nsGenericHTMLFormElement
*>(radioGroup
->mRadioButtons
[index
])->IsHTML(nsGkAtoms::input
),
8397 "mRadioButtons holding a non-radio button");
8398 radio
= static_cast<HTMLInputElement
*>(radioGroup
->mRadioButtons
[index
]);
8399 } while (radio
->Disabled() && radio
!= currentRadio
);
8401 radio
.forget(aRadioOut
);
8406 nsDocument::AddToRadioGroup(const nsAString
& aName
,
8407 nsIFormControl
* aRadio
)
8409 nsRadioGroupStruct
* radioGroup
= GetOrCreateRadioGroup(aName
);
8410 radioGroup
->mRadioButtons
.AppendObject(aRadio
);
8412 nsCOMPtr
<nsIContent
> element
= do_QueryInterface(aRadio
);
8413 NS_ASSERTION(element
, "radio controls have to be content elements");
8414 if (element
->HasAttr(kNameSpaceID_None
, nsGkAtoms::required
)) {
8415 radioGroup
->mRequiredRadioCount
++;
8420 nsDocument::RemoveFromRadioGroup(const nsAString
& aName
,
8421 nsIFormControl
* aRadio
)
8423 nsRadioGroupStruct
* radioGroup
= GetOrCreateRadioGroup(aName
);
8424 radioGroup
->mRadioButtons
.RemoveObject(aRadio
);
8426 nsCOMPtr
<nsIContent
> element
= do_QueryInterface(aRadio
);
8427 NS_ASSERTION(element
, "radio controls have to be content elements");
8428 if (element
->HasAttr(kNameSpaceID_None
, nsGkAtoms::required
)) {
8429 NS_ASSERTION(radioGroup
->mRequiredRadioCount
!= 0,
8430 "mRequiredRadioCount about to wrap below 0!");
8431 radioGroup
->mRequiredRadioCount
--;
8436 nsDocument::WalkRadioGroup(const nsAString
& aName
,
8437 nsIRadioVisitor
* aVisitor
,
8440 nsRadioGroupStruct
* radioGroup
= GetOrCreateRadioGroup(aName
);
8442 for (int i
= 0; i
< radioGroup
->mRadioButtons
.Count(); i
++) {
8443 if (!aVisitor
->Visit(radioGroup
->mRadioButtons
[i
])) {
8452 nsDocument::GetRequiredRadioCount(const nsAString
& aName
) const
8454 nsRadioGroupStruct
* radioGroup
= GetRadioGroup(aName
);
8455 return radioGroup
? radioGroup
->mRequiredRadioCount
: 0;
8459 nsDocument::RadioRequiredWillChange(const nsAString
& aName
, bool aRequiredAdded
)
8461 nsRadioGroupStruct
* radioGroup
= GetOrCreateRadioGroup(aName
);
8463 if (aRequiredAdded
) {
8464 radioGroup
->mRequiredRadioCount
++;
8466 NS_ASSERTION(radioGroup
->mRequiredRadioCount
!= 0,
8467 "mRequiredRadioCount about to wrap below 0!");
8468 radioGroup
->mRequiredRadioCount
--;
8473 nsDocument::GetValueMissingState(const nsAString
& aName
) const
8475 nsRadioGroupStruct
* radioGroup
= GetRadioGroup(aName
);
8476 return radioGroup
&& radioGroup
->mGroupSuffersFromValueMissing
;
8480 nsDocument::SetValueMissingState(const nsAString
& aName
, bool aValue
)
8482 nsRadioGroupStruct
* radioGroup
= GetOrCreateRadioGroup(aName
);
8483 radioGroup
->mGroupSuffersFromValueMissing
= aValue
;
8487 nsDocument::RetrieveRelevantHeaders(nsIChannel
*aChannel
)
8489 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(aChannel
);
8495 rv
= httpChannel
->GetResponseHeader(NS_LITERAL_CSTRING("last-modified"),
8498 if (NS_SUCCEEDED(rv
)) {
8500 PRStatus st
= PR_ParseTimeString(tmp
.get(), true, &time
);
8501 if (st
== PR_SUCCESS
) {
8506 // The misspelled key 'referer' is as per the HTTP spec
8507 rv
= httpChannel
->GetRequestHeader(NS_LITERAL_CSTRING("referer"),
8509 if (NS_FAILED(rv
)) {
8510 mReferrer
.Truncate();
8513 static const char *const headers
[] = {
8515 "content-style-type",
8517 "content-disposition",
8519 "x-dns-prefetch-control",
8521 // add more http headers if you need
8522 // XXXbz don't add content-location support without reading bug
8523 // 238654 and its dependencies/dups first.
8527 nsAutoCString headerVal
;
8528 const char *const *name
= headers
;
8531 httpChannel
->GetResponseHeader(nsDependentCString(*name
), headerVal
);
8532 if (NS_SUCCEEDED(rv
) && !headerVal
.IsEmpty()) {
8533 nsCOMPtr
<nsIAtom
> key
= do_GetAtom(*name
);
8534 SetHeaderData(key
, NS_ConvertASCIItoUTF16(headerVal
));
8539 nsCOMPtr
<nsIFileChannel
> fileChannel
= do_QueryInterface(aChannel
);
8541 nsCOMPtr
<nsIFile
> file
;
8542 fileChannel
->GetFile(getter_AddRefs(file
));
8545 rv
= file
->GetLastModifiedTime(&msecs
);
8547 if (NS_SUCCEEDED(rv
)) {
8548 modDate
= msecs
* int64_t(PR_USEC_PER_MSEC
);
8552 nsAutoCString contentDisp
;
8553 rv
= aChannel
->GetContentDispositionHeader(contentDisp
);
8554 if (NS_SUCCEEDED(rv
)) {
8555 SetHeaderData(nsGkAtoms::headerContentDisposition
,
8556 NS_ConvertASCIItoUTF16(contentDisp
));
8562 // We got nothing from our attempt to ask nsIFileChannel and
8563 // nsIHttpChannel for the last modified time. Return the current
8568 mLastModified
.Truncate();
8570 PRExplodedTime prtime
;
8571 PR_ExplodeTime(modDate
, PR_LocalTimeParameters
, &prtime
);
8572 // "MM/DD/YYYY hh:mm:ss"
8573 char formatedTime
[24];
8574 if (PR_snprintf(formatedTime
, sizeof(formatedTime
),
8575 "%02ld/%02ld/%04hd %02ld:%02ld:%02ld",
8576 prtime
.tm_month
+ 1, prtime
.tm_mday
, prtime
.tm_year
,
8577 prtime
.tm_hour
, prtime
.tm_min
, prtime
.tm_sec
)) {
8578 CopyASCIItoUTF16(nsDependentCString(formatedTime
), mLastModified
);
8584 nsDocument::CreateElem(const nsAString
& aName
, nsIAtom
*aPrefix
, int32_t aNamespaceID
,
8585 nsIContent
**aResult
)
8590 aPrefix
->ToString(qName
);
8593 qName
.Append(aName
);
8595 // Note: "a:b:c" is a valid name in non-namespaces XML, and
8596 // nsDocument::CreateElement can call us with such a name and no prefix,
8597 // which would cause an error if we just used true here.
8598 bool nsAware
= aPrefix
!= nullptr || aNamespaceID
!= GetDefaultNamespaceID();
8599 NS_ASSERTION(NS_SUCCEEDED(nsContentUtils::CheckQName(qName
, nsAware
)),
8600 "Don't pass invalid prefixes to nsDocument::CreateElem, "
8606 nsRefPtr
<mozilla::dom::NodeInfo
> nodeInfo
;
8607 mNodeInfoManager
->GetNodeInfo(aName
, aPrefix
, aNamespaceID
,
8608 nsIDOMNode::ELEMENT_NODE
,
8609 getter_AddRefs(nodeInfo
));
8610 NS_ENSURE_TRUE(nodeInfo
, NS_ERROR_OUT_OF_MEMORY
);
8612 nsCOMPtr
<Element
> element
;
8613 nsresult rv
= NS_NewElement(getter_AddRefs(element
), nodeInfo
.forget(),
8615 element
.forget(aResult
);
8620 nsDocument::IsSafeToFlush() const
8622 nsIPresShell
* shell
= GetShell();
8626 return shell
->IsSafeToFlush();
8630 nsDocument::Sanitize()
8632 // Sanitize the document by resetting all password fields and any form
8633 // fields with autocomplete=off to their default values. We do this now,
8634 // instead of when the presentation is restored, to offer some protection
8635 // in case there is ever an exploit that allows a cached document to be
8636 // accessed from a different document.
8638 // First locate all input elements, regardless of whether they are
8639 // in a form, and reset the password and autocomplete=off elements.
8641 nsRefPtr
<nsContentList
> nodes
= GetElementsByTagName(NS_LITERAL_STRING("input"));
8643 nsCOMPtr
<nsIContent
> item
;
8646 uint32_t length
= nodes
->Length(true);
8647 for (uint32_t i
= 0; i
< length
; ++i
) {
8648 NS_ASSERTION(nodes
->Item(i
), "null item in node list!");
8650 nsRefPtr
<HTMLInputElement
> input
= HTMLInputElement::FromContentOrNull(nodes
->Item(i
));
8654 bool resetValue
= false;
8656 input
->GetAttribute(NS_LITERAL_STRING("autocomplete"), value
);
8657 if (value
.LowerCaseEqualsLiteral("off")) {
8660 input
->GetType(value
);
8661 if (value
.LowerCaseEqualsLiteral("password"))
8670 // Now locate all _form_ elements that have autocomplete=off and reset them
8671 nodes
= GetElementsByTagName(NS_LITERAL_STRING("form"));
8673 length
= nodes
->Length(true);
8674 for (uint32_t i
= 0; i
< length
; ++i
) {
8675 NS_ASSERTION(nodes
->Item(i
), "null item in nodelist");
8677 nsCOMPtr
<nsIDOMHTMLFormElement
> form
= do_QueryInterface(nodes
->Item(i
));
8681 nodes
->Item(i
)->AsElement()->GetAttr(kNameSpaceID_None
,
8682 nsGkAtoms::autocomplete
, value
);
8683 if (value
.LowerCaseEqualsLiteral("off"))
8688 struct SubDocEnumArgs
8690 nsIDocument::nsSubDocEnumFunc callback
;
8694 static PLDHashOperator
8695 SubDocHashEnum(PLDHashTable
*table
, PLDHashEntryHdr
*hdr
,
8696 uint32_t number
, void *arg
)
8698 SubDocMapEntry
*entry
= static_cast<SubDocMapEntry
*>(hdr
);
8699 SubDocEnumArgs
*args
= static_cast<SubDocEnumArgs
*>(arg
);
8701 nsIDocument
*subdoc
= entry
->mSubDocument
;
8702 bool next
= subdoc
? args
->callback(subdoc
, args
->data
) : true;
8704 return next
? PL_DHASH_NEXT
: PL_DHASH_STOP
;
8708 nsDocument::EnumerateSubDocuments(nsSubDocEnumFunc aCallback
, void *aData
)
8710 if (mSubDocuments
) {
8711 SubDocEnumArgs args
= { aCallback
, aData
};
8712 PL_DHashTableEnumerate(mSubDocuments
, SubDocHashEnum
, &args
);
8716 static PLDHashOperator
8717 CanCacheSubDocument(PLDHashTable
*table
, PLDHashEntryHdr
*hdr
,
8718 uint32_t number
, void *arg
)
8720 SubDocMapEntry
*entry
= static_cast<SubDocMapEntry
*>(hdr
);
8721 bool *canCacheArg
= static_cast<bool*>(arg
);
8723 nsIDocument
*subdoc
= entry
->mSubDocument
;
8725 // The aIgnoreRequest we were passed is only for us, so don't pass it on.
8726 bool canCache
= subdoc
? subdoc
->CanSavePresentation(nullptr) : false;
8728 *canCacheArg
= false;
8729 return PL_DHASH_STOP
;
8732 return PL_DHASH_NEXT
;
8736 #define DEBUG_PAGE_CACHE
8740 nsDocument::CanSavePresentation(nsIRequest
*aNewRequest
)
8742 if (EventHandlingSuppressed()) {
8746 nsPIDOMWindow
* win
= GetInnerWindow();
8747 if (win
&& win
->TimeoutSuspendCount()) {
8751 // Check our event listener manager for unload/beforeunload listeners.
8752 nsCOMPtr
<EventTarget
> piTarget
= do_QueryInterface(mScriptGlobalObject
);
8754 EventListenerManager
* manager
= piTarget
->GetExistingListenerManager();
8755 if (manager
&& manager
->HasUnloadListeners()) {
8760 // Check if we have pending network requests
8761 nsCOMPtr
<nsILoadGroup
> loadGroup
= GetDocumentLoadGroup();
8763 nsCOMPtr
<nsISimpleEnumerator
> requests
;
8764 loadGroup
->GetRequests(getter_AddRefs(requests
));
8766 bool hasMore
= false;
8768 // We want to bail out if we have any requests other than aNewRequest (or
8769 // in the case when aNewRequest is a part of a multipart response the base
8770 // channel the multipart response is coming in on).
8771 nsCOMPtr
<nsIChannel
> baseChannel
;
8772 nsCOMPtr
<nsIMultiPartChannel
> part(do_QueryInterface(aNewRequest
));
8774 part
->GetBaseChannel(getter_AddRefs(baseChannel
));
8777 while (NS_SUCCEEDED(requests
->HasMoreElements(&hasMore
)) && hasMore
) {
8778 nsCOMPtr
<nsISupports
> elem
;
8779 requests
->GetNext(getter_AddRefs(elem
));
8781 nsCOMPtr
<nsIRequest
> request
= do_QueryInterface(elem
);
8782 if (request
&& request
!= aNewRequest
&& request
!= baseChannel
) {
8783 #ifdef DEBUG_PAGE_CACHE
8784 nsAutoCString requestName
, docSpec
;
8785 request
->GetName(requestName
);
8787 mDocumentURI
->GetSpec(docSpec
);
8789 printf("document %s has request %s\n",
8790 docSpec
.get(), requestName
.get());
8797 #ifdef MOZ_MEDIA_NAVIGATOR
8798 // Check if we have active GetUserMedia use
8799 if (MediaManager::Exists() && win
&&
8800 MediaManager::Get()->IsWindowStillActive(win
->WindowID())) {
8803 #endif // MOZ_MEDIA_NAVIGATOR
8806 // Check if we have active PeerConnections
8807 nsCOMPtr
<IPeerConnectionManager
> pcManager
=
8808 do_GetService(IPEERCONNECTION_MANAGER_CONTRACTID
);
8810 if (pcManager
&& win
) {
8812 pcManager
->HasActivePeerConnection(win
->WindowID(), &active
);
8817 #endif // MOZ_WEBRTC
8820 // Don't save presentations for documents containing EME content, so that
8821 // CDMs reliably shutdown upon user navigation.
8822 if (ContainsEMEContent()) {
8827 bool canCache
= true;
8829 PL_DHashTableEnumerate(mSubDocuments
, CanCacheSubDocument
, &canCache
);
8835 nsDocument::Destroy()
8837 // The ContentViewer wants to release the document now. So, tell our content
8838 // to drop any references to the document so that it can be destroyed.
8842 mIsGoingAway
= true;
8844 RemovedFromDocShell();
8846 bool oldVal
= mInUnlinkOrDeletion
;
8847 mInUnlinkOrDeletion
= true;
8848 uint32_t i
, count
= mChildren
.ChildCount();
8849 for (i
= 0; i
< count
; ++i
) {
8850 mChildren
.ChildAt(i
)->DestroyContent();
8852 mInUnlinkOrDeletion
= oldVal
;
8854 mLayoutHistoryState
= nullptr;
8856 // Shut down our external resource map. We might not need this for
8857 // leak-fixing if we fix nsDocumentViewer to do cycle-collection, but
8858 // tearing down all those frame trees right now is the right thing to do.
8859 mExternalResourceMap
.Shutdown();
8861 mRegistry
= nullptr;
8863 nsCOMPtr
<nsIServiceWorkerManager
> swm
= mozilla::services::GetServiceWorkerManager();
8865 swm
->MaybeStopControlling(this);
8868 // XXX We really should let cycle collection do this, but that currently still
8869 // leaks (see https://bugzilla.mozilla.org/show_bug.cgi?id=406684).
8870 ReleaseWrapper(static_cast<nsINode
*>(this));
8874 nsDocument::RemovedFromDocShell()
8876 if (mRemovedFromDocShell
)
8879 mRemovedFromDocShell
= true;
8880 EnumerateActivityObservers(NotifyActivityChanged
, nullptr);
8882 uint32_t i
, count
= mChildren
.ChildCount();
8883 for (i
= 0; i
< count
; ++i
) {
8884 mChildren
.ChildAt(i
)->SaveSubtreeState();
8888 already_AddRefed
<nsILayoutHistoryState
>
8889 nsDocument::GetLayoutHistoryState() const
8891 nsCOMPtr
<nsILayoutHistoryState
> state
;
8892 if (!mScriptGlobalObject
) {
8893 state
= mLayoutHistoryState
;
8895 nsCOMPtr
<nsIDocShell
> docShell(mDocumentContainer
);
8897 docShell
->GetLayoutHistoryState(getter_AddRefs(state
));
8901 return state
.forget();
8905 nsDocument::EnsureOnloadBlocker()
8907 // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
8908 // -- it's not ours.
8909 if (mOnloadBlockCount
!= 0 && mScriptGlobalObject
) {
8910 nsCOMPtr
<nsILoadGroup
> loadGroup
= GetDocumentLoadGroup();
8912 // Check first to see if mOnloadBlocker is in the loadgroup.
8913 nsCOMPtr
<nsISimpleEnumerator
> requests
;
8914 loadGroup
->GetRequests(getter_AddRefs(requests
));
8916 bool hasMore
= false;
8917 while (NS_SUCCEEDED(requests
->HasMoreElements(&hasMore
)) && hasMore
) {
8918 nsCOMPtr
<nsISupports
> elem
;
8919 requests
->GetNext(getter_AddRefs(elem
));
8920 nsCOMPtr
<nsIRequest
> request
= do_QueryInterface(elem
);
8921 if (request
&& request
== mOnloadBlocker
) {
8926 // Not in the loadgroup, so add it.
8927 loadGroup
->AddRequest(mOnloadBlocker
, nullptr);
8933 nsDocument::AsyncBlockOnload()
8935 while (mAsyncOnloadBlockCount
) {
8936 --mAsyncOnloadBlockCount
;
8942 nsDocument::BlockOnload()
8944 if (mDisplayDocument
) {
8945 mDisplayDocument
->BlockOnload();
8949 // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
8950 // -- it's not ours.
8951 if (mOnloadBlockCount
== 0 && mScriptGlobalObject
) {
8952 if (!nsContentUtils::IsSafeToRunScript()) {
8953 // Because AddRequest may lead to OnStateChange calls in chrome,
8954 // block onload only when there are no script blockers.
8955 ++mAsyncOnloadBlockCount
;
8956 if (mAsyncOnloadBlockCount
== 1) {
8957 bool success
= nsContentUtils::AddScriptRunner(
8958 NS_NewRunnableMethod(this, &nsDocument::AsyncBlockOnload
));
8960 // The script runner shouldn't fail to add. But if somebody broke
8961 // something and it does, we'll thrash at 100% cpu forever. The best
8962 // response is just to ignore the onload blocking request. See bug 579535.
8964 NS_WARNING("Disaster! Onload blocking script runner failed to add - expect bad things!");
8965 mAsyncOnloadBlockCount
= 0;
8970 nsCOMPtr
<nsILoadGroup
> loadGroup
= GetDocumentLoadGroup();
8972 loadGroup
->AddRequest(mOnloadBlocker
, nullptr);
8975 ++mOnloadBlockCount
;
8979 nsDocument::UnblockOnload(bool aFireSync
)
8981 if (mDisplayDocument
) {
8982 mDisplayDocument
->UnblockOnload(aFireSync
);
8986 if (mOnloadBlockCount
== 0 && mAsyncOnloadBlockCount
== 0) {
8987 NS_NOTREACHED("More UnblockOnload() calls than BlockOnload() calls; dropping call");
8991 --mOnloadBlockCount
;
8993 if (mOnloadBlockCount
== 0) {
8994 if (mScriptGlobalObject
) {
8995 // Only manipulate the loadgroup in this case, because if mScriptGlobalObject
8996 // is null, it's not ours.
8997 if (aFireSync
&& mAsyncOnloadBlockCount
== 0) {
8998 // Increment mOnloadBlockCount, since DoUnblockOnload will decrement it
8999 ++mOnloadBlockCount
;
9002 PostUnblockOnloadEvent();
9004 } else if (mIsBeingUsedAsImage
) {
9005 // To correctly unblock onload for a document that contains an SVG
9006 // image, we need to know when all of the SVG document's resources are
9007 // done loading, in a way comparable to |window.onload|. We fire this
9008 // event to indicate that the SVG should be considered fully loaded.
9009 // Because scripting is disabled on SVG-as-image documents, this event
9010 // is not accessible to content authors. (See bug 837135.)
9011 nsRefPtr
<AsyncEventDispatcher
> asyncDispatcher
=
9012 new AsyncEventDispatcher(this,
9013 NS_LITERAL_STRING("MozSVGAsImageDocumentLoad"),
9016 asyncDispatcher
->PostDOMEvent();
9021 class nsUnblockOnloadEvent
: public nsRunnable
{
9023 explicit nsUnblockOnloadEvent(nsDocument
* aDoc
) : mDoc(aDoc
) {}
9025 mDoc
->DoUnblockOnload();
9029 nsRefPtr
<nsDocument
> mDoc
;
9033 nsDocument::PostUnblockOnloadEvent()
9035 nsCOMPtr
<nsIRunnable
> evt
= new nsUnblockOnloadEvent(this);
9036 nsresult rv
= NS_DispatchToCurrentThread(evt
);
9037 if (NS_SUCCEEDED(rv
)) {
9038 // Stabilize block count so we don't post more events while this one is up
9039 ++mOnloadBlockCount
;
9041 NS_WARNING("failed to dispatch nsUnblockOnloadEvent");
9046 nsDocument::DoUnblockOnload()
9048 NS_PRECONDITION(!mDisplayDocument
,
9049 "Shouldn't get here for resource document");
9050 NS_PRECONDITION(mOnloadBlockCount
!= 0,
9051 "Shouldn't have a count of zero here, since we stabilized in "
9052 "PostUnblockOnloadEvent");
9054 --mOnloadBlockCount
;
9056 if (mOnloadBlockCount
!= 0) {
9057 // We blocked again after the last unblock. Nothing to do here. We'll
9058 // post a new event when we unblock again.
9062 if (mAsyncOnloadBlockCount
!= 0) {
9063 // We need to wait until the async onload block has been handled.
9064 PostUnblockOnloadEvent();
9067 // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
9068 // -- it's not ours.
9069 if (mScriptGlobalObject
) {
9070 nsCOMPtr
<nsILoadGroup
> loadGroup
= GetDocumentLoadGroup();
9072 loadGroup
->RemoveRequest(mOnloadBlocker
, nullptr, NS_OK
);
9078 nsDocument::GetContentInThisDocument(nsIFrame
* aFrame
) const
9080 for (nsIFrame
* f
= aFrame
; f
;
9081 f
= nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f
)) {
9082 nsIContent
* content
= f
->GetContent();
9083 if (!content
|| content
->IsInAnonymousSubtree())
9086 if (content
->OwnerDoc() == this) {
9089 // We must be in a subdocument so jump directly to the root frame.
9090 // GetParentOrPlaceholderForCrossDoc gets called immediately to jump up to
9091 // the containing document.
9092 f
= f
->PresContext()->GetPresShell()->GetRootFrame();
9099 nsDocument::DispatchPageTransition(EventTarget
* aDispatchTarget
,
9100 const nsAString
& aType
,
9103 if (!aDispatchTarget
) {
9107 PageTransitionEventInit init
;
9108 init
.mBubbles
= true;
9109 init
.mCancelable
= true;
9110 init
.mPersisted
= aPersisted
;
9112 nsRefPtr
<PageTransitionEvent
> event
=
9113 PageTransitionEvent::Constructor(this, aType
, init
);
9115 event
->SetTrusted(true);
9116 event
->SetTarget(this);
9117 EventDispatcher::DispatchDOMEvent(aDispatchTarget
, nullptr, event
,
9122 NotifyPageShow(nsIDocument
* aDocument
, void* aData
)
9124 const bool* aPersistedPtr
= static_cast<const bool*>(aData
);
9125 aDocument
->OnPageShow(*aPersistedPtr
, nullptr);
9130 nsDocument::OnPageShow(bool aPersisted
,
9131 EventTarget
* aDispatchStartTarget
)
9135 EnumerateActivityObservers(NotifyActivityChanged
, nullptr);
9136 EnumerateExternalResources(NotifyPageShow
, &aPersisted
);
9138 Element
* root
= GetRootElement();
9139 if (aPersisted
&& root
) {
9140 // Send out notifications that our <link> elements are attached.
9141 nsRefPtr
<nsContentList
> links
= NS_GetContentList(root
,
9143 NS_LITERAL_STRING("link"));
9145 uint32_t linkCount
= links
->Length(true);
9146 for (uint32_t i
= 0; i
< linkCount
; ++i
) {
9147 static_cast<HTMLLinkElement
*>(links
->Item(i
, false))->LinkAdded();
9152 if (!aDispatchStartTarget
) {
9153 // Set mIsShowing before firing events, in case those event handlers
9158 if (mAnimationController
) {
9159 mAnimationController
->OnPageShow();
9163 SetImagesNeedAnimating(true);
9166 UpdateVisibilityState();
9168 nsCOMPtr
<EventTarget
> target
= aDispatchStartTarget
;
9170 target
= do_QueryInterface(GetWindow());
9173 // Dispatch observer notification to notify observers page is shown.
9174 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
9175 nsIPrincipal
*principal
= GetPrincipal();
9176 os
->NotifyObservers(static_cast<nsIDocument
*>(this),
9177 nsContentUtils::IsSystemPrincipal(principal
) ?
9178 "chrome-page-shown" :
9179 "content-page-shown",
9181 if (!mObservingAppThemeChanged
) {
9182 os
->AddObserver(this, "app-theme-changed", /* ownsWeak */ false);
9183 mObservingAppThemeChanged
= true;
9186 DispatchPageTransition(target
, NS_LITERAL_STRING("pageshow"), aPersisted
);
9190 NotifyPageHide(nsIDocument
* aDocument
, void* aData
)
9192 const bool* aPersistedPtr
= static_cast<const bool*>(aData
);
9193 aDocument
->OnPageHide(*aPersistedPtr
, nullptr);
9198 DispatchFullScreenChange(nsIDocument
* aTarget
)
9200 nsRefPtr
<AsyncEventDispatcher
> asyncDispatcher
=
9201 new AsyncEventDispatcher(aTarget
,
9202 NS_LITERAL_STRING("mozfullscreenchange"),
9205 asyncDispatcher
->PostDOMEvent();
9209 nsDocument::OnPageHide(bool aPersisted
,
9210 EventTarget
* aDispatchStartTarget
)
9212 // Send out notifications that our <link> elements are detached,
9213 // but only if this is not a full unload.
9214 Element
* root
= GetRootElement();
9215 if (aPersisted
&& root
) {
9216 nsRefPtr
<nsContentList
> links
= NS_GetContentList(root
,
9218 NS_LITERAL_STRING("link"));
9220 uint32_t linkCount
= links
->Length(true);
9221 for (uint32_t i
= 0; i
< linkCount
; ++i
) {
9222 static_cast<HTMLLinkElement
*>(links
->Item(i
, false))->LinkRemoved();
9227 if (!aDispatchStartTarget
) {
9228 // Set mIsShowing before firing events, in case those event handlers
9233 if (mAnimationController
) {
9234 mAnimationController
->OnPageHide();
9238 SetImagesNeedAnimating(false);
9241 MozExitPointerLock();
9243 // Now send out a PageHide event.
9244 nsCOMPtr
<EventTarget
> target
= aDispatchStartTarget
;
9246 target
= do_QueryInterface(GetWindow());
9249 // Dispatch observer notification to notify observers page is hidden.
9250 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
9252 nsIPrincipal
* principal
= GetPrincipal();
9253 os
->NotifyObservers(static_cast<nsIDocument
*>(this),
9254 nsContentUtils::IsSystemPrincipal(principal
) ?
9255 "chrome-page-hidden" :
9256 "content-page-hidden",
9259 os
->RemoveObserver(this, "app-theme-changed");
9260 mObservingAppThemeChanged
= false;
9263 DispatchPageTransition(target
, NS_LITERAL_STRING("pagehide"), aPersisted
);
9267 UpdateVisibilityState();
9269 EnumerateExternalResources(NotifyPageHide
, &aPersisted
);
9270 EnumerateActivityObservers(NotifyActivityChanged
, nullptr);
9272 if (IsFullScreenDoc()) {
9273 // If this document was fullscreen, we should exit fullscreen in this
9274 // doctree branch. This ensures that if the user navigates while in
9275 // fullscreen mode we don't leave its still visible ancestor documents
9276 // in fullscreen mode. So exit fullscreen in the document's fullscreen
9277 // root document, as this will exit fullscreen in all the root's
9278 // descendant documents. Note that documents are removed from the
9279 // doctree by the time OnPageHide() is called, so we must store a
9280 // reference to the root (in nsDocument::mFullscreenRoot) since we can't
9281 // just traverse the doctree to get the root.
9282 nsIDocument::ExitFullscreen(this, /* async */ false);
9284 // Since the document is removed from the doctree before OnPageHide() is
9285 // called, ExitFullscreen() can't traverse from the root down to *this*
9286 // document, so we must manually call CleanupFullscreenState() below too.
9287 // Note that CleanupFullscreenState() clears nsDocument::mFullscreenRoot,
9288 // so we *must* call it after ExitFullscreen(), not before.
9289 // OnPageHide() is called in every hidden (i.e. descendant) document,
9290 // so calling CleanupFullscreenState() here will ensure all hidden
9291 // documents have their fullscreen state reset.
9292 CleanupFullscreenState();
9294 // If anyone was listening to this document's state, advertizing the state
9295 // change would be the least of the politeness.
9296 DispatchFullScreenChange(this);
9301 nsDocument::WillDispatchMutationEvent(nsINode
* aTarget
)
9303 NS_ASSERTION(mSubtreeModifiedDepth
!= 0 ||
9304 mSubtreeModifiedTargets
.Count() == 0,
9305 "mSubtreeModifiedTargets not cleared after dispatching?");
9306 ++mSubtreeModifiedDepth
;
9308 // MayDispatchMutationEvent is often called just before this method,
9309 // so it has already appended the node to mSubtreeModifiedTargets.
9310 int32_t count
= mSubtreeModifiedTargets
.Count();
9311 if (!count
|| mSubtreeModifiedTargets
[count
- 1] != aTarget
) {
9312 mSubtreeModifiedTargets
.AppendObject(aTarget
);
9318 nsDocument::MutationEventDispatched(nsINode
* aTarget
)
9320 --mSubtreeModifiedDepth
;
9321 if (mSubtreeModifiedDepth
== 0) {
9322 int32_t count
= mSubtreeModifiedTargets
.Count();
9327 nsPIDOMWindow
* window
= GetInnerWindow();
9329 !window
->HasMutationListeners(NS_EVENT_BITS_MUTATION_SUBTREEMODIFIED
)) {
9330 mSubtreeModifiedTargets
.Clear();
9334 nsCOMArray
<nsINode
> realTargets
;
9335 for (int32_t i
= 0; i
< count
; ++i
) {
9336 nsINode
* possibleTarget
= mSubtreeModifiedTargets
[i
];
9337 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(possibleTarget
);
9338 if (content
&& content
->ChromeOnlyAccess()) {
9342 nsINode
* commonAncestor
= nullptr;
9343 int32_t realTargetCount
= realTargets
.Count();
9344 for (int32_t j
= 0; j
< realTargetCount
; ++j
) {
9346 nsContentUtils::GetCommonAncestor(possibleTarget
, realTargets
[j
]);
9347 if (commonAncestor
) {
9348 realTargets
.ReplaceObjectAt(commonAncestor
, j
);
9352 if (!commonAncestor
) {
9353 realTargets
.AppendObject(possibleTarget
);
9357 mSubtreeModifiedTargets
.Clear();
9359 int32_t realTargetCount
= realTargets
.Count();
9360 for (int32_t k
= 0; k
< realTargetCount
; ++k
) {
9361 InternalMutationEvent
mutation(true, NS_MUTATION_SUBTREEMODIFIED
);
9362 (new AsyncEventDispatcher(realTargets
[k
], mutation
))->
9363 RunDOMEventWhenSafe();
9369 nsDocument::AddStyleRelevantLink(Link
* aLink
)
9371 NS_ASSERTION(aLink
, "Passing in a null link. Expect crashes RSN!");
9373 nsPtrHashKey
<Link
>* entry
= mStyledLinks
.GetEntry(aLink
);
9374 NS_ASSERTION(!entry
, "Document already knows about this Link!");
9375 mStyledLinksCleared
= false;
9377 (void)mStyledLinks
.PutEntry(aLink
);
9381 nsDocument::ForgetLink(Link
* aLink
)
9383 NS_ASSERTION(aLink
, "Passing in a null link. Expect crashes RSN!");
9385 nsPtrHashKey
<Link
>* entry
= mStyledLinks
.GetEntry(aLink
);
9386 NS_ASSERTION(entry
|| mStyledLinksCleared
,
9387 "Document knows nothing about this Link!");
9389 (void)mStyledLinks
.RemoveEntry(aLink
);
9393 nsDocument::DestroyElementMaps()
9396 mStyledLinksCleared
= true;
9398 mStyledLinks
.Clear();
9399 mIdentifierMap
.Clear();
9400 ++mExpandoAndGeneration
.generation
;
9405 EnumerateStyledLinks(nsPtrHashKey
<Link
>* aEntry
, void* aArray
)
9407 LinkArray
* array
= static_cast<LinkArray
*>(aArray
);
9408 (void)array
->AppendElement(aEntry
->GetKey());
9409 return PL_DHASH_NEXT
;
9413 nsDocument::RefreshLinkHrefs()
9415 // Get a list of all links we know about. We will reset them, which will
9416 // remove them from the document, so we need a copy of what is in the
9418 LinkArray
linksToNotify(mStyledLinks
.Count());
9419 (void)mStyledLinks
.EnumerateEntries(EnumerateStyledLinks
, &linksToNotify
);
9421 // Reset all of our styled links.
9422 nsAutoScriptBlocker scriptBlocker
;
9423 for (LinkArray::size_type i
= 0; i
< linksToNotify
.Length(); i
++) {
9424 linksToNotify
[i
]->ResetLinkState(true, linksToNotify
[i
]->ElementHasHref());
9429 nsDocument::CloneDocHelper(nsDocument
* clone
) const
9431 clone
->mIsStaticDocument
= mCreatingStaticClone
;
9434 nsresult rv
= clone
->Init();
9435 NS_ENSURE_SUCCESS(rv
, rv
);
9437 if (mCreatingStaticClone
) {
9438 nsCOMPtr
<nsILoadGroup
> loadGroup
;
9440 // |mDocumentContainer| is the container of the document that is being
9441 // created and not the original container. See CreateStaticClone function().
9442 nsCOMPtr
<nsIDocumentLoader
> docLoader(mDocumentContainer
);
9444 docLoader
->GetLoadGroup(getter_AddRefs(loadGroup
));
9446 nsCOMPtr
<nsIChannel
> channel
= GetChannel();
9447 nsCOMPtr
<nsIURI
> uri
;
9449 NS_GetFinalChannelURI(channel
, getter_AddRefs(uri
));
9451 uri
= nsIDocument::GetDocumentURI();
9453 clone
->mChannel
= channel
;
9455 clone
->ResetToURI(uri
, loadGroup
, NodePrincipal());
9458 clone
->SetContainer(mDocumentContainer
);
9461 // Now ensure that our clone has the same URI, base URI, and principal as us.
9462 // We do this after the mCreatingStaticClone block above, because that block
9463 // can set the base URI to an incorrect value in cases when base URI
9464 // information came from the channel. So we override explicitly, and do it
9465 // for all these properties, in case ResetToURI messes with any of the rest of
9467 clone
->nsDocument::SetDocumentURI(nsIDocument::GetDocumentURI());
9468 clone
->SetChromeXHRDocURI(mChromeXHRDocURI
);
9469 clone
->SetPrincipal(NodePrincipal());
9470 clone
->mDocumentBaseURI
= mDocumentBaseURI
;
9471 clone
->SetChromeXHRDocBaseURI(mChromeXHRDocBaseURI
);
9473 // Set scripting object
9474 bool hasHadScriptObject
= true;
9475 nsIScriptGlobalObject
* scriptObject
=
9476 GetScriptHandlingObject(hasHadScriptObject
);
9477 NS_ENSURE_STATE(scriptObject
|| !hasHadScriptObject
);
9479 clone
->SetScriptHandlingObject(scriptObject
);
9481 clone
->SetScopeObject(GetScopeObject());
9483 // Make the clone a data document
9484 clone
->SetLoadedAsData(true);
9488 // State from nsIDocument
9489 clone
->mCharacterSet
= mCharacterSet
;
9490 clone
->mCharacterSetSource
= mCharacterSetSource
;
9491 clone
->mCompatMode
= mCompatMode
;
9492 clone
->mBidiOptions
= mBidiOptions
;
9493 clone
->mContentLanguage
= mContentLanguage
;
9494 clone
->SetContentTypeInternal(GetContentTypeInternal());
9495 clone
->mSecurityInfo
= mSecurityInfo
;
9497 // State from nsDocument
9498 clone
->mType
= mType
;
9499 clone
->mXMLDeclarationBits
= mXMLDeclarationBits
;
9500 clone
->mBaseTarget
= mBaseTarget
;
9505 nsDocument::SetReadyStateInternal(ReadyState rs
)
9508 if (rs
== READYSTATE_UNINITIALIZED
) {
9509 // Transition back to uninitialized happens only to keep assertions happy
9510 // right before readyState transitions to something else. Make this
9511 // transition undetectable by Web content.
9516 case READYSTATE_LOADING
:
9517 mTiming
->NotifyDOMLoading(nsIDocument::GetDocumentURI());
9519 case READYSTATE_INTERACTIVE
:
9520 mTiming
->NotifyDOMInteractive(nsIDocument::GetDocumentURI());
9522 case READYSTATE_COMPLETE
:
9523 mTiming
->NotifyDOMComplete(nsIDocument::GetDocumentURI());
9526 NS_WARNING("Unexpected ReadyState value");
9530 // At the time of loading start, we don't have timing object, record time.
9531 if (READYSTATE_LOADING
== rs
) {
9532 mLoadingTimeStamp
= mozilla::TimeStamp::Now();
9535 nsRefPtr
<AsyncEventDispatcher
> asyncDispatcher
=
9536 new AsyncEventDispatcher(this, NS_LITERAL_STRING("readystatechange"),
9538 asyncDispatcher
->RunDOMEventWhenSafe();
9542 nsDocument::GetReadyState(nsAString
& aReadyState
)
9544 nsIDocument::GetReadyState(aReadyState
);
9549 nsIDocument::GetReadyState(nsAString
& aReadyState
) const
9551 switch(mReadyState
) {
9552 case READYSTATE_LOADING
:
9553 aReadyState
.AssignLiteral(MOZ_UTF16("loading"));
9555 case READYSTATE_INTERACTIVE
:
9556 aReadyState
.AssignLiteral(MOZ_UTF16("interactive"));
9558 case READYSTATE_COMPLETE
:
9559 aReadyState
.AssignLiteral(MOZ_UTF16("complete"));
9562 aReadyState
.AssignLiteral(MOZ_UTF16("uninitialized"));
9570 nsIDocument::SuppressionType mWhat
;
9577 SuppressEventHandlingInDocument(nsIDocument
* aDocument
, void* aData
)
9579 SuppressArgs
* args
= static_cast<SuppressArgs
*>(aData
);
9580 aDocument
->SuppressEventHandling(args
->mWhat
, args
->mIncrease
);
9585 nsDocument::SuppressEventHandling(nsIDocument::SuppressionType aWhat
,
9588 if (mEventsSuppressed
== 0 && mAnimationsPaused
== 0 &&
9589 aIncrease
!= 0 && mPresShell
&& mScriptGlobalObject
) {
9590 RevokeAnimationFrameNotifications();
9593 if (aWhat
== eAnimationsOnly
) {
9594 mAnimationsPaused
+= aIncrease
;
9596 mEventsSuppressed
+= aIncrease
;
9599 SuppressArgs args
= { aWhat
, aIncrease
};
9600 EnumerateSubDocuments(SuppressEventHandlingInDocument
, &args
);
9604 FireOrClearDelayedEvents(nsTArray
<nsCOMPtr
<nsIDocument
> >& aDocuments
,
9607 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
9611 for (uint32_t i
= 0; i
< aDocuments
.Length(); ++i
) {
9612 // NB: Don't bother trying to fire delayed events on documents that were
9613 // closed before this event ran.
9614 if (!aDocuments
[i
]->EventHandlingSuppressed()) {
9615 fm
->FireDelayedEvents(aDocuments
[i
]);
9616 nsCOMPtr
<nsIPresShell
> shell
= aDocuments
[i
]->GetShell();
9618 // Only fire events for active documents.
9619 bool fire
= aFireEvents
&&
9620 aDocuments
[i
]->GetInnerWindow() &&
9621 aDocuments
[i
]->GetInnerWindow()->IsCurrentInnerWindow();
9622 shell
->FireOrClearDelayedEvents(fire
);
9629 nsDocument::MaybePreLoadImage(nsIURI
* uri
, const nsAString
&aCrossOriginAttr
,
9630 ReferrerPolicy aReferrerPolicy
)
9632 // Early exit if the img is already present in the img-cache
9633 // which indicates that the "real" load has already started and
9634 // that we shouldn't preload it.
9635 int16_t blockingStatus
;
9636 if (nsContentUtils::IsImageInCache(uri
, static_cast<nsIDocument
*>(this)) ||
9637 !nsContentUtils::CanLoadImage(uri
, static_cast<nsIDocument
*>(this),
9638 this, NodePrincipal(), &blockingStatus
)) {
9642 nsLoadFlags loadFlags
= nsIRequest::LOAD_NORMAL
;
9643 switch (Element::StringToCORSMode(aCrossOriginAttr
)) {
9647 case CORS_ANONYMOUS
:
9648 loadFlags
|= imgILoader::LOAD_CORS_ANONYMOUS
;
9650 case CORS_USE_CREDENTIALS
:
9651 loadFlags
|= imgILoader::LOAD_CORS_USE_CREDENTIALS
;
9654 MOZ_CRASH("Unknown CORS mode!");
9657 // Image not in cache - trigger preload
9658 nsRefPtr
<imgRequestProxy
> request
;
9660 nsContentUtils::LoadImage(uri
,
9663 mDocumentURI
, // uri of document used as referrer
9665 nullptr, // no observer
9667 NS_LITERAL_STRING("img"),
9668 getter_AddRefs(request
));
9670 // Pin image-reference to avoid evicting it from the img-cache before
9671 // the "real" load occurs. Unpinned in DispatchContentLoadedEvents and
9673 if (NS_SUCCEEDED(rv
)) {
9674 mPreloadingImages
.Put(uri
, request
.forget());
9679 nsDocument::ForgetImagePreload(nsIURI
* aURI
)
9681 // Checking count is faster than hashing the URI in the common
9682 // case of empty table.
9683 if (mPreloadingImages
.Count() != 0) {
9684 nsCOMPtr
<imgIRequest
> req
;
9685 mPreloadingImages
.Remove(aURI
, getter_AddRefs(req
));
9687 // Make sure to cancel the request so imagelib knows it's gone.
9688 req
->CancelAndForgetObserver(NS_BINDING_ABORTED
);
9694 nsDocument::GetDocumentState()
9696 if (!mGotDocumentState
.HasState(NS_DOCUMENT_STATE_RTL_LOCALE
)) {
9697 if (IsDocumentRightToLeft()) {
9698 mDocumentState
|= NS_DOCUMENT_STATE_RTL_LOCALE
;
9700 mGotDocumentState
|= NS_DOCUMENT_STATE_RTL_LOCALE
;
9702 if (!mGotDocumentState
.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE
)) {
9703 nsIPresShell
* shell
= GetShell();
9704 if (shell
&& shell
->GetPresContext() &&
9705 shell
->GetPresContext()->IsTopLevelWindowInactive()) {
9706 mDocumentState
|= NS_DOCUMENT_STATE_WINDOW_INACTIVE
;
9708 mGotDocumentState
|= NS_DOCUMENT_STATE_WINDOW_INACTIVE
;
9710 return mDocumentState
;
9716 * Stub for LoadSheet(), since all we want is to get the sheet into
9717 * the CSSLoader's style cache
9719 class StubCSSLoaderObserver MOZ_FINAL
: public nsICSSLoaderObserver
{
9720 ~StubCSSLoaderObserver() {}
9723 StyleSheetLoaded(CSSStyleSheet
*, bool, nsresult
) MOZ_OVERRIDE
9729 NS_IMPL_ISUPPORTS(StubCSSLoaderObserver
, nsICSSLoaderObserver
)
9734 nsDocument::PreloadStyle(nsIURI
* uri
, const nsAString
& charset
,
9735 const nsAString
& aCrossOriginAttr
,
9736 const ReferrerPolicy aReferrerPolicy
)
9738 // The CSSLoader will retain this object after we return.
9739 nsCOMPtr
<nsICSSLoaderObserver
> obs
= new StubCSSLoaderObserver();
9741 // Charset names are always ASCII.
9742 CSSLoader()->LoadSheet(uri
, NodePrincipal(),
9743 NS_LossyConvertUTF16toASCII(charset
),
9745 Element::StringToCORSMode(aCrossOriginAttr
),
9750 nsDocument::LoadChromeSheetSync(nsIURI
* uri
, bool isAgentSheet
,
9751 CSSStyleSheet
** sheet
)
9753 return CSSLoader()->LoadSheetSync(uri
, isAgentSheet
, isAgentSheet
, sheet
);
9756 class nsDelayedEventDispatcher
: public nsRunnable
9759 explicit nsDelayedEventDispatcher(nsTArray
<nsCOMPtr
<nsIDocument
>>& aDocuments
)
9761 mDocuments
.SwapElements(aDocuments
);
9763 virtual ~nsDelayedEventDispatcher() {}
9767 FireOrClearDelayedEvents(mDocuments
, true);
9772 nsTArray
<nsCOMPtr
<nsIDocument
> > mDocuments
;
9777 struct UnsuppressArgs
9779 explicit UnsuppressArgs(nsIDocument::SuppressionType aWhat
)
9784 nsIDocument::SuppressionType mWhat
;
9785 nsTArray
<nsCOMPtr
<nsIDocument
>> mDocs
;
9791 GetAndUnsuppressSubDocuments(nsIDocument
* aDocument
,
9794 UnsuppressArgs
* args
= static_cast<UnsuppressArgs
*>(aData
);
9795 if (args
->mWhat
!= nsIDocument::eAnimationsOnly
&&
9796 aDocument
->EventHandlingSuppressed() > 0) {
9797 static_cast<nsDocument
*>(aDocument
)->DecreaseEventSuppression();
9798 } else if (args
->mWhat
== nsIDocument::eAnimationsOnly
&&
9799 aDocument
->AnimationsPaused()) {
9800 static_cast<nsDocument
*>(aDocument
)->ResumeAnimations();
9803 if (args
->mWhat
!= nsIDocument::eAnimationsOnly
) {
9804 // No need to remember documents if we only care about animation frames.
9805 args
->mDocs
.AppendElement(aDocument
);
9808 aDocument
->EnumerateSubDocuments(GetAndUnsuppressSubDocuments
, aData
);
9813 nsDocument::UnsuppressEventHandlingAndFireEvents(nsIDocument::SuppressionType aWhat
,
9816 UnsuppressArgs
args(aWhat
);
9817 GetAndUnsuppressSubDocuments(this, &args
);
9819 if (aWhat
== nsIDocument::eAnimationsOnly
) {
9820 // No need to fire events if we only care about animations here.
9825 NS_DispatchToCurrentThread(new nsDelayedEventDispatcher(args
.mDocs
));
9827 FireOrClearDelayedEvents(args
.mDocs
, false);
9832 nsDocument::GetCurrentContentSink()
9834 return mParser
? mParser
->GetContentSink() : nullptr;
9838 nsDocument::GetTemplateContentsOwner()
9840 if (!mTemplateContentsOwner
) {
9841 bool hasHadScriptObject
= true;
9842 nsIScriptGlobalObject
* scriptObject
=
9843 GetScriptHandlingObject(hasHadScriptObject
);
9845 nsCOMPtr
<nsIDOMDocument
> domDocument
;
9846 nsresult rv
= NS_NewDOMDocument(getter_AddRefs(domDocument
),
9847 EmptyString(), // aNamespaceURI
9848 EmptyString(), // aQualifiedName
9849 nullptr, // aDoctype
9850 nsIDocument::GetDocumentURI(),
9851 nsIDocument::GetDocBaseURI(),
9853 true, // aLoadedAsData
9854 scriptObject
, // aEventObject
9855 DocumentFlavorHTML
);
9856 NS_ENSURE_SUCCESS(rv
, nullptr);
9858 mTemplateContentsOwner
= do_QueryInterface(domDocument
);
9859 NS_ENSURE_TRUE(mTemplateContentsOwner
, nullptr);
9861 nsDocument
* doc
= static_cast<nsDocument
*>(mTemplateContentsOwner
.get());
9863 if (!scriptObject
) {
9864 mTemplateContentsOwner
->SetScopeObject(GetScopeObject());
9867 doc
->mHasHadScriptHandlingObject
= hasHadScriptObject
;
9869 // Set |doc| as the template contents owner of itself so that
9870 // |doc| is the template contents owner of template elements created
9872 doc
->mTemplateContentsOwner
= doc
;
9875 return mTemplateContentsOwner
;
9879 nsDocument::RegisterHostObjectUri(const nsACString
& aUri
)
9881 mHostObjectURIs
.AppendElement(aUri
);
9885 nsDocument::UnregisterHostObjectUri(const nsACString
& aUri
)
9887 mHostObjectURIs
.RemoveElement(aUri
);
9891 nsDocument::SetScrollToRef(nsIURI
*aDocumentURI
)
9893 if (!aDocumentURI
) {
9899 // Since all URI's that pass through here aren't URL's we can't
9900 // rely on the nsIURI implementation for providing a way for
9901 // finding the 'ref' part of the URI, we'll haveto revert to
9902 // string routines for finding the data past '#'
9904 aDocumentURI
->GetSpec(ref
);
9906 nsReadingIterator
<char> start
, end
;
9908 ref
.BeginReading(start
);
9909 ref
.EndReading(end
);
9911 if (FindCharInReadable('#', start
, end
)) {
9912 ++start
; // Skip over the '#'
9914 mScrollToRef
= Substring(start
, end
);
9919 nsDocument::ScrollToRef()
9921 if (mScrolledToRefAlready
) {
9922 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
9924 shell
->ScrollToAnchor();
9929 if (mScrollToRef
.IsEmpty()) {
9933 char* tmpstr
= ToNewCString(mScrollToRef
);
9939 nsAutoCString unescapedRef
;
9940 unescapedRef
.Assign(tmpstr
);
9941 nsMemory::Free(tmpstr
);
9943 nsresult rv
= NS_ERROR_FAILURE
;
9944 // We assume that the bytes are in UTF-8, as it says in the spec:
9945 // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1
9946 NS_ConvertUTF8toUTF16
ref(unescapedRef
);
9948 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
9950 // Check an empty string which might be caused by the UTF-8 conversion
9951 if (!ref
.IsEmpty()) {
9952 // Note that GoToAnchor will handle flushing layout as needed.
9953 rv
= shell
->GoToAnchor(ref
, mChangeScrollPosWhenScrollingToRef
);
9955 rv
= NS_ERROR_FAILURE
;
9958 // If UTF-8 URI failed then try to assume the string as a
9959 // document's charset.
9961 if (NS_FAILED(rv
)) {
9962 const nsACString
&docCharset
= GetDocumentCharacterSet();
9964 rv
= nsContentUtils::ConvertStringFromEncoding(docCharset
,
9968 if (NS_SUCCEEDED(rv
) && !ref
.IsEmpty()) {
9969 rv
= shell
->GoToAnchor(ref
, mChangeScrollPosWhenScrollingToRef
);
9972 if (NS_SUCCEEDED(rv
)) {
9973 mScrolledToRefAlready
= true;
9979 nsDocument::ResetScrolledToRefAlready()
9981 mScrolledToRefAlready
= false;
9985 nsDocument::SetChangeScrollPosWhenScrollingToRef(bool aValue
)
9987 mChangeScrollPosWhenScrollingToRef
= aValue
;
9991 nsIDocument::RegisterActivityObserver(nsISupports
* aSupports
)
9993 if (!mActivityObservers
) {
9994 mActivityObservers
= new nsTHashtable
<nsPtrHashKey
<nsISupports
> >();
9995 if (!mActivityObservers
)
9998 mActivityObservers
->PutEntry(aSupports
);
10002 nsIDocument::UnregisterActivityObserver(nsISupports
* aSupports
)
10004 if (!mActivityObservers
)
10006 if (!mActivityObservers
->GetEntry(aSupports
))
10008 mActivityObservers
->RemoveEntry(aSupports
);
10012 struct EnumerateActivityObserversData
{
10013 nsIDocument::ActivityObserverEnumerator mEnumerator
;
10017 static PLDHashOperator
10018 EnumerateObservers(nsPtrHashKey
<nsISupports
>* aEntry
, void* aData
)
10020 EnumerateActivityObserversData
* data
= static_cast<EnumerateActivityObserversData
*>(aData
);
10021 data
->mEnumerator(aEntry
->GetKey(), data
->mData
);
10022 return PL_DHASH_NEXT
;
10026 nsIDocument::EnumerateActivityObservers(ActivityObserverEnumerator aEnumerator
,
10029 if (!mActivityObservers
)
10031 EnumerateActivityObserversData data
= { aEnumerator
, aData
};
10032 mActivityObservers
->EnumerateEntries(EnumerateObservers
, &data
);
10036 nsIDocument::RegisterPendingLinkUpdate(Link
* aLink
)
10038 MOZ_ASSERT(!mIsLinkUpdateRegistrationsForbidden
);
10039 mLinksToUpdate
.PutEntry(aLink
);
10040 mHasLinksToUpdate
= true;
10044 nsIDocument::UnregisterPendingLinkUpdate(Link
* aLink
)
10046 MOZ_ASSERT(!mIsLinkUpdateRegistrationsForbidden
);
10047 if (!mHasLinksToUpdate
)
10050 mLinksToUpdate
.RemoveEntry(aLink
);
10053 static PLDHashOperator
10054 EnumeratePendingLinkUpdates(nsPtrHashKey
<Link
>* aEntry
, void* aData
)
10056 aEntry
->GetKey()->GetElement()->UpdateLinkState(aEntry
->GetKey()->LinkState());
10057 return PL_DHASH_NEXT
;
10061 nsIDocument::FlushPendingLinkUpdates()
10063 MOZ_ASSERT(!mIsLinkUpdateRegistrationsForbidden
);
10064 if (!mHasLinksToUpdate
)
10068 AutoRestore
<bool> saved(mIsLinkUpdateRegistrationsForbidden
);
10069 mIsLinkUpdateRegistrationsForbidden
= true;
10071 mLinksToUpdate
.EnumerateEntries(EnumeratePendingLinkUpdates
, nullptr);
10072 mLinksToUpdate
.Clear();
10073 mHasLinksToUpdate
= false;
10076 already_AddRefed
<nsIDocument
>
10077 nsIDocument::CreateStaticClone(nsIDocShell
* aCloneContainer
)
10079 nsDocument
* thisAsDoc
= static_cast<nsDocument
*>(this);
10080 mCreatingStaticClone
= true;
10082 // Make document use different container during cloning.
10083 nsRefPtr
<nsDocShell
> originalShell
= mDocumentContainer
.get();
10084 SetContainer(static_cast<nsDocShell
*>(aCloneContainer
));
10085 nsCOMPtr
<nsIDOMNode
> clonedNode
;
10086 nsresult rv
= thisAsDoc
->CloneNode(true, 1, getter_AddRefs(clonedNode
));
10087 SetContainer(originalShell
);
10089 nsRefPtr
<nsDocument
> clonedDoc
;
10090 if (NS_SUCCEEDED(rv
)) {
10091 nsCOMPtr
<nsIDocument
> tmp
= do_QueryInterface(clonedNode
);
10093 clonedDoc
= static_cast<nsDocument
*>(tmp
.get());
10094 if (IsStaticDocument()) {
10095 clonedDoc
->mOriginalDocument
= mOriginalDocument
;
10097 clonedDoc
->mOriginalDocument
= this;
10099 int32_t sheetsCount
= GetNumberOfStyleSheets();
10100 for (int32_t i
= 0; i
< sheetsCount
; ++i
) {
10101 nsRefPtr
<CSSStyleSheet
> sheet
= do_QueryObject(GetStyleSheetAt(i
));
10103 if (sheet
->IsApplicable()) {
10104 nsRefPtr
<CSSStyleSheet
> clonedSheet
=
10105 sheet
->Clone(nullptr, nullptr, clonedDoc
, nullptr);
10106 NS_WARN_IF_FALSE(clonedSheet
, "Cloning a stylesheet didn't work!");
10108 clonedDoc
->AddStyleSheet(clonedSheet
);
10114 sheetsCount
= thisAsDoc
->mOnDemandBuiltInUASheets
.Count();
10115 // Iterate backwards to maintain order
10116 for (int32_t i
= sheetsCount
- 1; i
>= 0; --i
) {
10117 nsRefPtr
<CSSStyleSheet
> sheet
=
10118 do_QueryObject(thisAsDoc
->mOnDemandBuiltInUASheets
[i
]);
10120 if (sheet
->IsApplicable()) {
10121 nsRefPtr
<CSSStyleSheet
> clonedSheet
=
10122 sheet
->Clone(nullptr, nullptr, clonedDoc
, nullptr);
10123 NS_WARN_IF_FALSE(clonedSheet
, "Cloning a stylesheet didn't work!");
10125 clonedDoc
->AddOnDemandBuiltInUASheet(clonedSheet
);
10132 mCreatingStaticClone
= false;
10133 return clonedDoc
.forget();
10137 nsIDocument::ScheduleFrameRequestCallback(const FrameRequestCallbackHolder
& aCallback
,
10140 if (mFrameRequestCallbackCounter
== INT32_MAX
) {
10141 // Can't increment without overflowing; bail out
10142 return NS_ERROR_NOT_AVAILABLE
;
10144 int32_t newHandle
= ++mFrameRequestCallbackCounter
;
10146 bool alreadyRegistered
= !mFrameRequestCallbacks
.IsEmpty();
10147 DebugOnly
<FrameRequest
*> request
=
10148 mFrameRequestCallbacks
.AppendElement(FrameRequest(aCallback
, newHandle
));
10149 NS_ASSERTION(request
, "This is supposed to be infallible!");
10150 if (!alreadyRegistered
&& mPresShell
&& IsEventHandlingEnabled()) {
10151 mPresShell
->GetPresContext()->RefreshDriver()->
10152 ScheduleFrameRequestCallbacks(this);
10155 *aHandle
= newHandle
;
10160 nsIDocument::CancelFrameRequestCallback(int32_t aHandle
)
10162 // mFrameRequestCallbacks is stored sorted by handle
10163 if (mFrameRequestCallbacks
.RemoveElementSorted(aHandle
) &&
10164 mFrameRequestCallbacks
.IsEmpty() &&
10165 mPresShell
&& IsEventHandlingEnabled()) {
10166 mPresShell
->GetPresContext()->RefreshDriver()->
10167 RevokeFrameRequestCallbacks(this);
10172 nsDocument::GetStateObject(nsIVariant
** aState
)
10174 // Get the document's current state object. This is the object backing both
10175 // history.state and popStateEvent.state.
10177 // mStateObjectContainer may be null; this just means that there's no
10178 // current state object.
10180 nsCOMPtr
<nsIVariant
> stateObj
;
10181 if (!mStateObjectCached
&& mStateObjectContainer
) {
10183 nsIGlobalObject
* sgo
= GetScopeObject();
10184 NS_ENSURE_TRUE(sgo
, NS_ERROR_UNEXPECTED
);
10185 JS::Rooted
<JSObject
*> global(cx
, sgo
->GetGlobalJSObject());
10186 NS_ENSURE_TRUE(global
, NS_ERROR_UNEXPECTED
);
10187 JSAutoCompartment
ac(cx
, global
);
10189 mStateObjectContainer
->
10190 DeserializeToVariant(cx
, getter_AddRefs(mStateObjectCached
));
10193 NS_IF_ADDREF(*aState
= mStateObjectCached
);
10198 nsDOMNavigationTiming
*
10199 nsDocument::GetNavigationTiming() const
10205 nsDocument::SetNavigationTiming(nsDOMNavigationTiming
* aTiming
)
10208 if (!mLoadingTimeStamp
.IsNull() && mTiming
) {
10209 mTiming
->SetDOMLoadingTimeStamp(nsIDocument::GetDocumentURI(), mLoadingTimeStamp
);
10215 nsDocument::FindImageMap(const nsAString
& aUseMapValue
)
10217 if (aUseMapValue
.IsEmpty()) {
10221 nsAString::const_iterator start
, end
;
10222 aUseMapValue
.BeginReading(start
);
10223 aUseMapValue
.EndReading(end
);
10225 int32_t hash
= aUseMapValue
.FindChar('#');
10229 // aUsemap contains a '#', set start to point right after the '#'
10230 start
.advance(hash
+ 1);
10232 if (start
== end
) {
10233 return nullptr; // aUsemap == "#"
10236 const nsAString
& mapName
= Substring(start
, end
);
10239 mImageMaps
= new nsContentList(this, kNameSpaceID_XHTML
, nsGkAtoms::map
, nsGkAtoms::map
);
10242 uint32_t i
, n
= mImageMaps
->Length(true);
10244 for (i
= 0; i
< n
; ++i
) {
10245 nsIContent
* map
= mImageMaps
->Item(i
);
10246 if (map
->AttrValueIs(kNameSpaceID_None
, nsGkAtoms::id
, mapName
,
10248 (map
->GetAttr(kNameSpaceID_None
, nsGkAtoms::name
, name
) &&
10249 mapName
.Equals(name
, nsCaseInsensitiveStringComparator()))) {
10250 return map
->AsElement();
10257 #define DEPRECATED_OPERATION(_op) #_op "Warning",
10258 static const char* kDeprecationWarnings
[] = {
10259 #include "nsDeprecatedOperationList.h"
10262 #undef DEPRECATED_OPERATION
10264 #define DOCUMENT_WARNING(_op) #_op "Warning",
10265 static const char* kDocumentWarnings
[] = {
10266 #include "nsDocumentWarningList.h"
10269 #undef DOCUMENT_WARNING
10272 nsIDocument::HasWarnedAbout(DeprecatedOperations aOperation
)
10274 static_assert(eDeprecatedOperationCount
<= 64,
10275 "Too many deprecated operations");
10276 return mDeprecationWarnedAbout
& (1ull << aOperation
);
10280 nsIDocument::WarnOnceAbout(DeprecatedOperations aOperation
,
10281 bool asError
/* = false */)
10283 if (HasWarnedAbout(aOperation
)) {
10286 mDeprecationWarnedAbout
|= (1ull << aOperation
);
10287 uint32_t flags
= asError
? nsIScriptError::errorFlag
10288 : nsIScriptError::warningFlag
;
10289 nsContentUtils::ReportToConsole(flags
,
10290 NS_LITERAL_CSTRING("DOM Core"), this,
10291 nsContentUtils::eDOM_PROPERTIES
,
10292 kDeprecationWarnings
[aOperation
]);
10296 nsIDocument::HasWarnedAbout(DocumentWarnings aWarning
)
10298 static_assert(eDocumentWarningCount
<= 64,
10299 "Too many document warnings");
10300 return mDocWarningWarnedAbout
& (1ull << aWarning
);
10304 nsIDocument::WarnOnceAbout(DocumentWarnings aWarning
,
10305 bool asError
/* = false */,
10306 const char16_t
**aParams
/* = nullptr */,
10307 uint32_t aParamsLength
/* = 0 */)
10309 if (HasWarnedAbout(aWarning
)) {
10312 mDocWarningWarnedAbout
|= (1ull << aWarning
);
10313 uint32_t flags
= asError
? nsIScriptError::errorFlag
10314 : nsIScriptError::warningFlag
;
10315 nsContentUtils::ReportToConsole(flags
,
10316 NS_LITERAL_CSTRING("DOM Core"), this,
10317 nsContentUtils::eDOM_PROPERTIES
,
10318 kDocumentWarnings
[aWarning
],
10324 nsDocument::AddImage(imgIRequest
* aImage
)
10326 NS_ENSURE_ARG_POINTER(aImage
);
10328 // See if the image is already in the hashtable. If it is, get the old count.
10329 uint32_t oldCount
= 0;
10330 mImageTracker
.Get(aImage
, &oldCount
);
10332 // Put the image in the hashtable, with the proper count.
10333 mImageTracker
.Put(aImage
, oldCount
+ 1);
10335 nsresult rv
= NS_OK
;
10337 // If this is the first insertion and we're locking images, lock this image
10339 if (oldCount
== 0) {
10340 if (mLockingImages
)
10341 rv
= aImage
->LockImage();
10342 if (NS_SUCCEEDED(rv
) && (!sOnloadDecodeLimit
||
10343 mImageTracker
.Count() < sOnloadDecodeLimit
))
10344 rv
= aImage
->StartDecoding();
10347 // If this is the first insertion and we're animating images, request
10348 // that this image be animated too.
10349 if (oldCount
== 0 && mAnimatingImages
) {
10350 nsresult rv2
= aImage
->IncrementAnimationConsumers();
10351 rv
= NS_SUCCEEDED(rv
) ? rv2
: rv
;
10358 nsDocument::RemoveImage(imgIRequest
* aImage
, uint32_t aFlags
)
10360 NS_ENSURE_ARG_POINTER(aImage
);
10362 // Get the old count. It should exist and be > 0.
10363 uint32_t count
= 0;
10364 DebugOnly
<bool> found
= mImageTracker
.Get(aImage
, &count
);
10365 NS_ABORT_IF_FALSE(found
, "Removing image that wasn't in the tracker!");
10366 NS_ABORT_IF_FALSE(count
> 0, "Entry in the cache tracker with count 0!");
10368 // We're removing, so decrement the count.
10371 // If the count is now zero, remove from the tracker.
10372 // Otherwise, set the new value.
10374 mImageTracker
.Put(aImage
, count
);
10378 mImageTracker
.Remove(aImage
);
10380 nsresult rv
= NS_OK
;
10382 // Now that we're no longer tracking this image, unlock it if we'd
10383 // previously locked it.
10384 if (mLockingImages
) {
10385 rv
= aImage
->UnlockImage();
10388 // If we're animating images, remove our request to animate this one.
10389 if (mAnimatingImages
) {
10390 nsresult rv2
= aImage
->DecrementAnimationConsumers();
10391 rv
= NS_SUCCEEDED(rv
) ? rv2
: rv
;
10394 if (aFlags
& REQUEST_DISCARD
) {
10395 // Request that the image be discarded if nobody else holds a lock on it.
10396 // Do this even if !mLockingImages, because even if we didn't just unlock
10397 // this image, it might still be a candidate for discarding.
10398 aImage
->RequestDiscard();
10405 nsDocument::AddPlugin(nsIObjectLoadingContent
* aPlugin
)
10407 MOZ_ASSERT(aPlugin
);
10408 if (!mPlugins
.PutEntry(aPlugin
)) {
10409 return NS_ERROR_OUT_OF_MEMORY
;
10415 nsDocument::RemovePlugin(nsIObjectLoadingContent
* aPlugin
)
10417 MOZ_ASSERT(aPlugin
);
10418 mPlugins
.RemoveEntry(aPlugin
);
10422 AllSubDocumentPluginEnum(nsIDocument
* aDocument
, void* userArg
)
10424 nsTArray
<nsIObjectLoadingContent
*>* plugins
=
10425 reinterpret_cast< nsTArray
<nsIObjectLoadingContent
*>* >(userArg
);
10426 MOZ_ASSERT(plugins
);
10427 aDocument
->GetPlugins(*plugins
);
10431 static PLDHashOperator
10432 AllPluginEnum(nsPtrHashKey
<nsIObjectLoadingContent
>* aPlugin
, void* userArg
)
10434 nsTArray
<nsIObjectLoadingContent
*>* allPlugins
=
10435 reinterpret_cast< nsTArray
<nsIObjectLoadingContent
*>* >(userArg
);
10436 MOZ_ASSERT(allPlugins
);
10437 allPlugins
->AppendElement(aPlugin
->GetKey());
10438 return PL_DHASH_NEXT
;
10442 nsDocument::GetPlugins(nsTArray
<nsIObjectLoadingContent
*>& aPlugins
)
10444 aPlugins
.SetCapacity(aPlugins
.Length() + mPlugins
.Count());
10445 mPlugins
.EnumerateEntries(AllPluginEnum
, &aPlugins
);
10446 EnumerateSubDocuments(AllSubDocumentPluginEnum
, &aPlugins
);
10449 PLDHashOperator
LockEnumerator(imgIRequest
* aKey
,
10454 aKey
->RequestDecode();
10455 return PL_DHASH_NEXT
;
10458 PLDHashOperator
UnlockEnumerator(imgIRequest
* aKey
,
10462 aKey
->UnlockImage();
10463 return PL_DHASH_NEXT
;
10468 nsDocument::SetImageLockingState(bool aLocked
)
10470 if (XRE_GetProcessType() == GeckoProcessType_Content
&&
10471 !Preferences::GetBool("image.mem.allow_locking_in_content_processes", true)) {
10475 // If there's no change, there's nothing to do.
10476 if (mLockingImages
== aLocked
)
10479 // Otherwise, iterate over our images and perform the appropriate action.
10480 mImageTracker
.EnumerateRead(aLocked
? LockEnumerator
10481 : UnlockEnumerator
,
10485 mLockingImages
= aLocked
;
10490 PLDHashOperator
IncrementAnimationEnumerator(imgIRequest
* aKey
,
10494 aKey
->IncrementAnimationConsumers();
10495 return PL_DHASH_NEXT
;
10498 PLDHashOperator
DecrementAnimationEnumerator(imgIRequest
* aKey
,
10502 aKey
->DecrementAnimationConsumers();
10503 return PL_DHASH_NEXT
;
10507 nsDocument::SetImagesNeedAnimating(bool aAnimating
)
10509 // If there's no change, there's nothing to do.
10510 if (mAnimatingImages
== aAnimating
)
10513 // Otherwise, iterate over our images and perform the appropriate action.
10514 mImageTracker
.EnumerateRead(aAnimating
? IncrementAnimationEnumerator
10515 : DecrementAnimationEnumerator
,
10519 mAnimatingImages
= aAnimating
;
10522 already_AddRefed
<Touch
>
10523 nsIDocument::CreateTouch(nsIDOMWindow
* aView
,
10524 EventTarget
* aTarget
,
10525 int32_t aIdentifier
,
10526 int32_t aPageX
, int32_t aPageY
,
10527 int32_t aScreenX
, int32_t aScreenY
,
10528 int32_t aClientX
, int32_t aClientY
,
10529 int32_t aRadiusX
, int32_t aRadiusY
,
10530 float aRotationAngle
,
10533 nsRefPtr
<Touch
> touch
= new Touch(aTarget
,
10536 aScreenX
, aScreenY
,
10537 aClientX
, aClientY
,
10538 aRadiusX
, aRadiusY
,
10541 return touch
.forget();
10544 already_AddRefed
<TouchList
>
10545 nsIDocument::CreateTouchList()
10547 nsRefPtr
<TouchList
> retval
= new TouchList(ToSupports(this));
10548 return retval
.forget();
10551 already_AddRefed
<TouchList
>
10552 nsIDocument::CreateTouchList(Touch
& aTouch
,
10553 const Sequence
<OwningNonNull
<Touch
> >& aTouches
)
10555 nsRefPtr
<TouchList
> retval
= new TouchList(ToSupports(this));
10556 retval
->Append(&aTouch
);
10557 for (uint32_t i
= 0; i
< aTouches
.Length(); ++i
) {
10558 retval
->Append(aTouches
[i
].get());
10560 return retval
.forget();
10563 already_AddRefed
<TouchList
>
10564 nsIDocument::CreateTouchList(const Sequence
<OwningNonNull
<Touch
> >& aTouches
)
10566 nsRefPtr
<TouchList
> retval
= new TouchList(ToSupports(this));
10567 for (uint32_t i
= 0; i
< aTouches
.Length(); ++i
) {
10568 retval
->Append(aTouches
[i
].get());
10570 return retval
.forget();
10573 already_AddRefed
<nsDOMCaretPosition
>
10574 nsIDocument::CaretPositionFromPoint(float aX
, float aY
)
10576 nscoord x
= nsPresContext::CSSPixelsToAppUnits(aX
);
10577 nscoord y
= nsPresContext::CSSPixelsToAppUnits(aY
);
10580 FlushPendingNotifications(Flush_Layout
);
10582 nsIPresShell
*ps
= GetShell();
10587 nsIFrame
*rootFrame
= ps
->GetRootFrame();
10589 // XUL docs, unlike HTML, have no frame tree until everything's done loading
10594 nsIFrame
*ptFrame
= nsLayoutUtils::GetFrameForPoint(rootFrame
, pt
,
10595 nsLayoutUtils::IGNORE_PAINT_SUPPRESSION
| nsLayoutUtils::IGNORE_CROSS_DOC
);
10600 // GetContentOffsetsFromPoint requires frame-relative coordinates, so we need
10601 // to adjust to frame-relative coordinates before we can perform this call.
10602 // It should also not take into account the padding of the frame.
10603 nsPoint adjustedPoint
= pt
- ptFrame
->GetOffsetTo(rootFrame
);
10605 nsFrame::ContentOffsets offsets
=
10606 ptFrame
->GetContentOffsetsFromPoint(adjustedPoint
);
10608 nsCOMPtr
<nsIContent
> node
= offsets
.content
;
10609 uint32_t offset
= offsets
.offset
;
10610 nsCOMPtr
<nsIContent
> anonNode
= node
;
10611 bool nodeIsAnonymous
= node
&& node
->IsInNativeAnonymousSubtree();
10612 if (nodeIsAnonymous
) {
10613 node
= ptFrame
->GetContent();
10614 nsIContent
* nonanon
= node
->FindFirstNonChromeOnlyAccessContent();
10615 nsCOMPtr
<nsIDOMHTMLInputElement
> input
= do_QueryInterface(nonanon
);
10616 nsCOMPtr
<nsIDOMHTMLTextAreaElement
> textArea
= do_QueryInterface(nonanon
);
10618 if (textArea
|| (input
&&
10619 NS_SUCCEEDED(input
->MozIsTextField(false, &isText
)) &&
10621 // If the anonymous content node has a child, then we need to make sure
10622 // that we get the appropriate child, as otherwise the offset may not be
10623 // correct when we construct a range for it.
10624 nsCOMPtr
<nsIContent
> firstChild
= anonNode
->GetFirstChild();
10626 anonNode
= firstChild
;
10630 offset
= nsContentUtils::GetAdjustedOffsetInTextControl(ptFrame
, offset
);
10640 nsRefPtr
<nsDOMCaretPosition
> aCaretPos
= new nsDOMCaretPosition(node
, offset
);
10641 if (nodeIsAnonymous
) {
10642 aCaretPos
->SetAnonymousContentNode(anonNode
);
10644 return aCaretPos
.forget();
10648 nsDocument::CaretPositionFromPoint(float aX
, float aY
, nsISupports
** aCaretPos
)
10650 NS_ENSURE_ARG_POINTER(aCaretPos
);
10651 *aCaretPos
= nsIDocument::CaretPositionFromPoint(aX
, aY
).take();
10656 nsIDocument::ObsoleteSheet(nsIURI
*aSheetURI
, ErrorResult
& rv
)
10658 nsresult res
= CSSLoader()->ObsoleteSheet(aSheetURI
);
10659 if (NS_FAILED(res
)) {
10665 nsIDocument::ObsoleteSheet(const nsAString
& aSheetURI
, ErrorResult
& rv
)
10667 nsCOMPtr
<nsIURI
> uri
;
10668 nsresult res
= NS_NewURI(getter_AddRefs(uri
), aSheetURI
);
10669 if (NS_FAILED(res
)) {
10673 res
= CSSLoader()->ObsoleteSheet(uri
);
10674 if (NS_FAILED(res
)) {
10680 nsIDocument::Children()
10682 if (!mChildrenCollection
) {
10683 mChildrenCollection
= new nsContentList(this, kNameSpaceID_Wildcard
,
10684 nsGkAtoms::_asterix
,
10685 nsGkAtoms::_asterix
,
10689 return mChildrenCollection
;
10693 nsIDocument::ChildElementCount()
10695 return Children()->Length();
10698 namespace mozilla
{
10700 // Singleton class to manage the list of fullscreen documents which are the
10701 // root of a branch which contains fullscreen documents. We maintain this list
10702 // so that we can easily exit all windows from fullscreen when the user
10703 // presses the escape key.
10704 class FullscreenRoots
{
10706 // Adds a root to the manager. Adding a root multiple times does not result
10707 // in duplicate entries for that item, only one.
10708 static void Add(nsIDocument
* aRoot
);
10710 // Iterates over every root in the root list, and calls aFunction, passing
10711 // each root once to aFunction. It is safe to call Add() and Remove() while
10712 // iterating over the list (i.e. in aFunction). Documents that are removed
10713 // from the manager during traversal are not traversed, and documents that
10714 // are added to the manager during traversal are also not traversed.
10715 static void ForEach(void(*aFunction
)(nsIDocument
* aDoc
));
10717 // Removes a specific root from the manager.
10718 static void Remove(nsIDocument
* aRoot
);
10720 // Returns true if all roots added to the list have been removed.
10721 static bool IsEmpty();
10725 FullscreenRoots() {
10726 MOZ_COUNT_CTOR(FullscreenRoots
);
10728 ~FullscreenRoots() {
10729 MOZ_COUNT_DTOR(FullscreenRoots
);
10733 NotFound
= uint32_t(-1)
10735 // Looks in mRoots for aRoot. Returns the index if found, otherwise NotFound.
10736 static uint32_t Find(nsIDocument
* aRoot
);
10738 // Returns true if aRoot is in the list of fullscreen roots.
10739 static bool Contains(nsIDocument
* aRoot
);
10741 // Singleton instance of the FullscreenRoots. This is instantiated when a
10742 // root is added, and it is deleted when the last root is removed.
10743 static FullscreenRoots
* sInstance
;
10745 // List of weak pointers to roots.
10746 nsTArray
<nsWeakPtr
> mRoots
;
10749 FullscreenRoots
* FullscreenRoots::sInstance
= nullptr;
10753 FullscreenRoots::ForEach(void(*aFunction
)(nsIDocument
* aDoc
))
10758 // Create a copy of the roots array, and iterate over the copy. This is so
10759 // that if an element is removed from mRoots we don't mess up our iteration.
10760 nsTArray
<nsWeakPtr
> roots(sInstance
->mRoots
);
10761 // Call aFunction on all entries.
10762 for (uint32_t i
= 0; i
< roots
.Length(); i
++) {
10763 nsCOMPtr
<nsIDocument
> root
= do_QueryReferent(roots
[i
]);
10764 // Check that the root isn't in the manager. This is so that new additions
10765 // while we were running don't get traversed.
10766 if (root
&& FullscreenRoots::Contains(root
)) {
10774 FullscreenRoots::Contains(nsIDocument
* aRoot
)
10776 return FullscreenRoots::Find(aRoot
) != NotFound
;
10781 FullscreenRoots::Add(nsIDocument
* aRoot
)
10783 if (!FullscreenRoots::Contains(aRoot
)) {
10785 sInstance
= new FullscreenRoots();
10787 sInstance
->mRoots
.AppendElement(do_GetWeakReference(aRoot
));
10793 FullscreenRoots::Find(nsIDocument
* aRoot
)
10798 nsTArray
<nsWeakPtr
>& roots
= sInstance
->mRoots
;
10799 for (uint32_t i
= 0; i
< roots
.Length(); i
++) {
10800 nsCOMPtr
<nsIDocument
> otherRoot(do_QueryReferent(roots
[i
]));
10801 if (otherRoot
== aRoot
) {
10810 FullscreenRoots::Remove(nsIDocument
* aRoot
)
10812 uint32_t index
= Find(aRoot
);
10813 NS_ASSERTION(index
!= NotFound
,
10814 "Should only try to remove roots which are still added!");
10815 if (index
== NotFound
|| !sInstance
) {
10818 sInstance
->mRoots
.RemoveElementAt(index
);
10819 if (sInstance
->mRoots
.IsEmpty()) {
10821 sInstance
= nullptr;
10827 FullscreenRoots::IsEmpty()
10832 } // end namespace mozilla.
10833 using mozilla::FullscreenRoots
;
10836 nsDocument::GetFullscreenRoot()
10838 nsCOMPtr
<nsIDocument
> root
= do_QueryReferent(mFullscreenRoot
);
10843 nsDocument::SetFullscreenRoot(nsIDocument
* aRoot
)
10845 mFullscreenRoot
= do_GetWeakReference(aRoot
);
10849 nsDocument::MozCancelFullScreen()
10851 nsIDocument::MozCancelFullScreen();
10856 nsIDocument::MozCancelFullScreen()
10858 RestorePreviousFullScreenState();
10861 // Runnable to set window full-screen mode. Used as a script runner
10862 // to ensure we only call nsGlobalWindow::SetFullScreen() when it's safe to
10863 // run script. nsGlobalWindow::SetFullScreen() dispatches a synchronous event
10864 // (handled in chome code) which is unsafe to run if this is called in
10865 // Element::UnbindFromTree().
10866 class nsSetWindowFullScreen
: public nsRunnable
{
10868 nsSetWindowFullScreen(nsIDocument
* aDoc
, bool aValue
, gfx::VRHMDInfo
* aHMD
= nullptr)
10869 : mDoc(aDoc
), mValue(aValue
), mHMD(aHMD
) {}
10873 if (mDoc
->GetWindow()) {
10874 mDoc
->GetWindow()->SetFullScreenInternal(mValue
, false, mHMD
);
10880 nsCOMPtr
<nsIDocument
> mDoc
;
10882 nsRefPtr
<gfx::VRHMDInfo
> mHMD
;
10885 static nsIDocument
*
10886 GetFullscreenRootDocument(nsIDocument
* aDoc
)
10891 nsIDocument
* doc
= aDoc
;
10892 nsIDocument
* parent
;
10893 while ((parent
= doc
->GetParentDocument()) &&
10894 (!nsContentUtils::IsFullscreenApiContentOnly() ||
10895 !nsContentUtils::IsChromeDoc(parent
))) {
10902 SetWindowFullScreen(nsIDocument
* aDoc
, bool aValue
, gfx::VRHMDInfo
*aVRHMD
= nullptr)
10904 // Maintain list of fullscreen root documents.
10905 nsCOMPtr
<nsIDocument
> root
= GetFullscreenRootDocument(aDoc
);
10907 FullscreenRoots::Add(root
);
10909 FullscreenRoots::Remove(root
);
10911 if (!nsContentUtils::IsFullscreenApiContentOnly()) {
10912 nsContentUtils::AddScriptRunner(new nsSetWindowFullScreen(aDoc
, aValue
, aVRHMD
));
10916 class nsCallExitFullscreen
: public nsRunnable
{
10918 explicit nsCallExitFullscreen(nsIDocument
* aDoc
)
10922 nsDocument::ExitFullscreen(mDoc
);
10926 nsCOMPtr
<nsIDocument
> mDoc
;
10931 nsIDocument::ExitFullscreen(nsIDocument
* aDoc
, bool aRunAsync
)
10933 if (aDoc
&& !aDoc
->IsFullScreenDoc()) {
10937 NS_DispatchToCurrentThread(new nsCallExitFullscreen(aDoc
));
10940 nsDocument::ExitFullscreen(aDoc
);
10943 // Returns true if the document is a direct child of a cross process parent
10944 // mozbrowser iframe or TabParent. This is the case when the document has
10945 // a null parent and its DocShell reports that it is a browser frame, or
10946 // we can get a TabChild from it.
10948 HasCrossProcessParent(nsIDocument
* aDocument
)
10950 if (XRE_GetProcessType() != GeckoProcessType_Content
) {
10953 if (aDocument
->GetParentDocument() != nullptr) {
10956 nsPIDOMWindow
* win
= aDocument
->GetWindow();
10960 nsCOMPtr
<nsIDocShell
> docShell
= win
->GetDocShell();
10964 TabChild
* tabChild(TabChild::GetFrom(docShell
));
10973 CountFullscreenSubDocuments(nsIDocument
* aDoc
, void* aData
)
10975 if (aDoc
->IsFullScreenDoc()) {
10976 uint32_t* count
= static_cast<uint32_t*>(aData
);
10983 CountFullscreenSubDocuments(nsIDocument
* aDoc
)
10985 uint32_t count
= 0;
10986 aDoc
->EnumerateSubDocuments(CountFullscreenSubDocuments
, &count
);
10991 nsDocument::IsFullscreenLeaf()
10993 // A fullscreen leaf document is fullscreen, and has no fullscreen
10995 if (!IsFullScreenDoc()) {
10998 return CountFullscreenSubDocuments(this) == 0;
11002 ResetFullScreen(nsIDocument
* aDocument
, void* aData
)
11004 if (aDocument
->IsFullScreenDoc()) {
11005 NS_ASSERTION(CountFullscreenSubDocuments(aDocument
) <= 1,
11006 "Should have at most 1 fullscreen subdocument.");
11007 static_cast<nsDocument
*>(aDocument
)->CleanupFullscreenState();
11008 NS_ASSERTION(!aDocument
->IsFullScreenDoc(), "Should reset full-screen");
11009 nsTArray
<nsIDocument
*>* changed
= reinterpret_cast<nsTArray
<nsIDocument
*>*>(aData
);
11010 changed
->AppendElement(aDocument
);
11012 if (HasCrossProcessParent(aDocument
)) {
11013 // We're at the top of the content-process side doc tree. Ask the parent
11014 // process to exit fullscreen.
11015 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
11016 os
->NotifyObservers(aDocument
, "ask-parent-to-exit-fullscreen", nullptr);
11019 // Dispatch a notification so that if this document has any
11020 // cross-process subdocuments, they'll be notified to exit fullscreen.
11021 // The BrowserElementParent listens for this event and performs the
11022 // cross process notification if it has a remote child process.
11023 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
11024 os
->NotifyObservers(aDocument
, "ask-children-to-exit-fullscreen", nullptr);
11026 aDocument
->EnumerateSubDocuments(ResetFullScreen
, aData
);
11032 ExitFullscreenInDocTree(nsIDocument
* aMaybeNotARootDoc
)
11034 MOZ_ASSERT(aMaybeNotARootDoc
);
11035 nsCOMPtr
<nsIDocument
> root
= aMaybeNotARootDoc
->GetFullscreenRoot();
11036 NS_ASSERTION(root
, "Should have root when in fullscreen!");
11040 NS_ASSERTION(root
->IsFullScreenDoc(),
11041 "Fullscreen root should be a fullscreen doc...");
11043 // Stores a list of documents to which we must dispatch "mozfullscreenchange".
11044 // We're required by the spec to dispatch the events in leaf-to-root
11045 // order when exiting fullscreen, but we traverse the doctree in a
11046 // root-to-leaf order, so we save references to the documents we must
11047 // dispatch to so that we dispatch in the specified order.
11048 nsAutoTArray
<nsIDocument
*, 8> changed
;
11050 // Walk the tree of fullscreen documents, and reset their fullscreen state.
11051 ResetFullScreen(root
, static_cast<void*>(&changed
));
11053 // Dispatch "mozfullscreenchange" events. Note this loop is in reverse
11054 // order so that the events for the leaf document arrives before the root
11055 // document, as required by the spec.
11056 for (uint32_t i
= 0; i
< changed
.Length(); ++i
) {
11057 DispatchFullScreenChange(changed
[changed
.Length() - i
- 1]);
11060 NS_ASSERTION(!root
->IsFullScreenDoc(),
11061 "Fullscreen root should no longer be a fullscreen doc...");
11063 // Move the top-level window out of fullscreen mode.
11064 SetWindowFullScreen(root
, false);
11069 nsDocument::ExitFullscreen(nsIDocument
* aDoc
)
11071 // Unlock the pointer, if it's locked.
11072 nsCOMPtr
<Element
> pointerLockedElement
=
11073 do_QueryReferent(EventStateManager::sPointerLockedElement
);
11074 if (pointerLockedElement
) {
11079 ExitFullscreenInDocTree(aDoc
);
11083 // Clear fullscreen stacks in all fullscreen roots' descendant documents.
11084 FullscreenRoots::ForEach(&ExitFullscreenInDocTree
);
11085 NS_ASSERTION(FullscreenRoots::IsEmpty(),
11086 "Should have exited all fullscreen roots from fullscreen");
11090 GetFullscreenLeaf(nsIDocument
* aDoc
, void* aData
)
11092 if (aDoc
->IsFullscreenLeaf()) {
11093 nsIDocument
** result
= static_cast<nsIDocument
**>(aData
);
11096 } else if (aDoc
->IsFullScreenDoc()) {
11097 aDoc
->EnumerateSubDocuments(GetFullscreenLeaf
, aData
);
11102 static nsIDocument
*
11103 GetFullscreenLeaf(nsIDocument
* aDoc
)
11105 nsIDocument
* leaf
= nullptr;
11106 GetFullscreenLeaf(aDoc
, &leaf
);
11110 // Otherwise we could be either in a non-fullscreen doc tree, or we're
11111 // below the fullscreen doc. Start the search from the root.
11112 nsIDocument
* root
= GetFullscreenRootDocument(aDoc
);
11113 // Check that the root is actually fullscreen so we don't waste time walking
11114 // around its descendants.
11115 if (!root
->IsFullScreenDoc()) {
11118 GetFullscreenLeaf(root
, &leaf
);
11123 nsDocument::RestorePreviousFullScreenState()
11125 NS_ASSERTION(!IsFullScreenDoc() || !FullscreenRoots::IsEmpty(),
11126 "Should have at least 1 fullscreen root when fullscreen!");
11127 NS_ASSERTION(!nsContentUtils::IsFullscreenApiContentOnly() ||
11128 !nsContentUtils::IsChromeDoc(this),
11129 "Should not run RestorePreviousFullScreenState() on "
11130 "chrome document when fullscreen is content only");
11132 if (!IsFullScreenDoc() || !GetWindow() || FullscreenRoots::IsEmpty()) {
11136 // If fullscreen mode is updated the pointer should be unlocked
11137 nsCOMPtr
<Element
> pointerLockedElement
=
11138 do_QueryReferent(EventStateManager::sPointerLockedElement
);
11139 if (pointerLockedElement
) {
11143 nsCOMPtr
<nsIDocument
> fullScreenDoc
= GetFullscreenLeaf(this);
11145 // The fullscreen document may contain a <iframe mozbrowser> element which
11146 // has a cross process child. So send a notification so that its browser
11147 // parent will send a message to its child process to also exit fullscreen.
11148 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
11149 os
->NotifyObservers(fullScreenDoc
, "ask-children-to-exit-fullscreen", nullptr);
11151 // Clear full-screen stacks in all descendant in process documents, bottom up.
11152 nsIDocument
* doc
= fullScreenDoc
;
11153 while (doc
!= this) {
11154 NS_ASSERTION(doc
->IsFullScreenDoc(), "Should be full-screen doc");
11155 static_cast<nsDocument
*>(doc
)->CleanupFullscreenState();
11157 DispatchFullScreenChange(doc
);
11158 doc
= doc
->GetParentDocument();
11161 // Roll-back full-screen state to previous full-screen element.
11162 NS_ASSERTION(doc
== this, "Must have reached this doc.");
11163 while (doc
!= nullptr) {
11164 static_cast<nsDocument
*>(doc
)->FullScreenStackPop();
11166 DispatchFullScreenChange(doc
);
11167 if (static_cast<nsDocument
*>(doc
)->mFullScreenStack
.IsEmpty()) {
11168 if (HasCrossProcessParent(doc
)) {
11169 // Send notification to the parent process to tell it to rollback to
11170 // the previous fullscreen elements in its fullscreen element stacks.
11171 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
11172 os
->NotifyObservers(doc
, "ask-parent-to-rollback-fullscreen", nullptr);
11174 // Full-screen stack in document is empty. Go back up to the parent
11175 // document. We'll pop the containing element off its stack, and use
11176 // its next full-screen element as the full-screen element.
11177 static_cast<nsDocument
*>(doc
)->CleanupFullscreenState();
11178 doc
= doc
->GetParentDocument();
11180 // Else we popped the top of the stack, and there's still another
11181 // element in there, so that will become the full-screen element.
11182 if (fullScreenDoc
!= doc
) {
11183 // We've popped so enough off the stack that we've rolled back to
11184 // a fullscreen element in a parent document. If this document isn't
11185 // approved for fullscreen, or if it's cross origin, dispatch an
11186 // event to chrome so it knows to show the authorization/warning UI.
11187 if (!nsContentUtils::HaveEqualPrincipals(fullScreenDoc
, doc
) ||
11188 (!nsContentUtils::IsSitePermAllow(doc
->NodePrincipal(), "fullscreen") &&
11189 !static_cast<nsDocument
*>(doc
)->mIsApprovedForFullscreen
)) {
11190 nsRefPtr
<AsyncEventDispatcher
> asyncDispatcher
=
11191 new AsyncEventDispatcher(doc
,
11192 NS_LITERAL_STRING("MozEnteredDomFullscreen"),
11195 asyncDispatcher
->PostDOMEvent();
11199 if (!nsContentUtils::HaveEqualPrincipals(doc
, fullScreenDoc
)) {
11200 // The origin which is fullscreen changed. Send a notification to
11201 // the root process so that a warning or approval UI can be shown
11203 nsAutoString origin
;
11204 nsContentUtils::GetUTFOrigin(doc
->NodePrincipal(), origin
);
11205 nsIDocument
* root
= GetFullscreenRootDocument(doc
);
11206 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
11207 os
->NotifyObservers(root
, "fullscreen-origin-change", origin
.get());
11214 if (doc
== nullptr) {
11215 // We moved all documents in this doctree out of fullscreen mode,
11216 // move the top-level window out of fullscreen mode.
11217 NS_ASSERTION(!GetFullscreenRootDocument(this)->IsFullScreenDoc(),
11218 "Should have cleared all docs' stacks");
11219 SetWindowFullScreen(this, false);
11224 nsDocument::IsFullScreenDoc()
11226 return GetFullScreenElement() != nullptr;
11229 class nsCallRequestFullScreen
: public nsRunnable
11232 explicit nsCallRequestFullScreen(Element
* aElement
, FullScreenOptions
& aOptions
)
11233 : mElement(aElement
),
11234 mDoc(aElement
->OwnerDoc()),
11235 mWasCallerChrome(nsContentUtils::IsCallerChrome()),
11236 mHadRequestPending(static_cast<nsDocument
*>(mDoc
.get())->
11237 mAsyncFullscreenPending
),
11240 static_cast<nsDocument
*>(mDoc
.get())->
11241 mAsyncFullscreenPending
= true;
11246 static_cast<nsDocument
*>(mDoc
.get())->
11247 mAsyncFullscreenPending
= mHadRequestPending
;
11248 nsDocument
* doc
= static_cast<nsDocument
*>(mDoc
.get());
11249 doc
->RequestFullScreen(mElement
,
11252 /* aNotifyOnOriginChange */ true);
11256 nsRefPtr
<Element
> mElement
;
11257 nsCOMPtr
<nsIDocument
> mDoc
;
11258 bool mWasCallerChrome
;
11259 bool mHadRequestPending
;
11260 FullScreenOptions mOptions
;
11264 nsDocument::AsyncRequestFullScreen(Element
* aElement
,
11265 FullScreenOptions
& aOptions
)
11267 NS_ASSERTION(aElement
,
11268 "Must pass non-null element to nsDocument::AsyncRequestFullScreen");
11272 // Request full-screen asynchronously.
11273 nsCOMPtr
<nsIRunnable
> event(new nsCallRequestFullScreen(aElement
, aOptions
));
11274 NS_DispatchToCurrentThread(event
);
11278 LogFullScreenDenied(bool aLogFailure
, const char* aMessage
, nsIDocument
* aDoc
)
11280 if (!aLogFailure
) {
11283 nsRefPtr
<AsyncEventDispatcher
> asyncDispatcher
=
11284 new AsyncEventDispatcher(aDoc
,
11285 NS_LITERAL_STRING("mozfullscreenerror"),
11288 asyncDispatcher
->PostDOMEvent();
11289 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag
,
11290 NS_LITERAL_CSTRING("DOM"), aDoc
,
11291 nsContentUtils::eDOM_PROPERTIES
,
11296 nsDocument::AddFullscreenApprovedObserver()
11298 if (mHasFullscreenApprovedObserver
||
11299 !Preferences::GetBool("full-screen-api.approval-required")) {
11303 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
11304 NS_ENSURE_TRUE(os
, NS_ERROR_FAILURE
);
11306 nsresult res
= os
->AddObserver(this, "fullscreen-approved", true);
11307 NS_ENSURE_SUCCESS(res
, res
);
11309 mHasFullscreenApprovedObserver
= true;
11315 nsDocument::RemoveFullscreenApprovedObserver()
11317 if (!mHasFullscreenApprovedObserver
) {
11320 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
11321 NS_ENSURE_TRUE(os
, NS_ERROR_FAILURE
);
11323 nsresult res
= os
->RemoveObserver(this, "fullscreen-approved");
11324 NS_ENSURE_SUCCESS(res
, res
);
11326 mHasFullscreenApprovedObserver
= false;
11332 nsDocument::CleanupFullscreenState()
11334 if (!mFullScreenStack
.IsEmpty()) {
11335 // The top element in the full-screen stack will have full-screen
11336 // style bits set on it and its ancestors. Remove the style bits.
11337 // Note the non-top elements won't have the style bits set.
11338 Element
* top
= FullScreenStackTop();
11339 NS_ASSERTION(top
, "Should have a top when full-screen stack isn't empty");
11341 // Remove any VR state properties
11342 top
->DeleteProperty(nsGkAtoms::vr_state
);
11344 EventStateManager::SetFullScreenState(top
, false);
11346 mFullScreenStack
.Clear();
11348 SetApprovedForFullscreen(false);
11349 RemoveFullscreenApprovedObserver();
11350 mFullscreenRoot
= nullptr;
11354 nsDocument::FullScreenStackPush(Element
* aElement
)
11356 NS_ASSERTION(aElement
, "Must pass non-null to FullScreenStackPush()");
11357 Element
* top
= FullScreenStackTop();
11358 if (top
== aElement
|| !aElement
) {
11362 // We're pushing a new element onto the full-screen stack, so we must
11363 // remove the ancestor and full-screen styles from the former top of the
11365 EventStateManager::SetFullScreenState(top
, false);
11367 EventStateManager::SetFullScreenState(aElement
, true);
11368 mFullScreenStack
.AppendElement(do_GetWeakReference(aElement
));
11369 NS_ASSERTION(GetFullScreenElement() == aElement
, "Should match");
11374 nsDocument::FullScreenStackPop()
11376 if (mFullScreenStack
.IsEmpty()) {
11380 Element
* top
= FullScreenStackTop();
11382 // Remove any VR state properties
11383 top
->DeleteProperty(nsGkAtoms::vr_state
);
11385 // Remove styles from existing top element.
11386 EventStateManager::SetFullScreenState(top
, false);
11388 // Remove top element. Note the remaining top element in the stack
11389 // will not have full-screen style bits set, so we will need to restore
11390 // them on the new top element before returning.
11391 uint32_t last
= mFullScreenStack
.Length() - 1;
11392 mFullScreenStack
.RemoveElementAt(last
);
11394 // Pop from the stack null elements (references to elements which have
11395 // been GC'd since they were added to the stack) and elements which are
11396 // no longer in this document.
11397 while (!mFullScreenStack
.IsEmpty()) {
11398 Element
* element
= FullScreenStackTop();
11399 if (!element
|| !element
->IsInDoc() || element
->OwnerDoc() != this) {
11400 NS_ASSERTION(!element
->IsFullScreenAncestor(),
11401 "Should have already removed full-screen styles");
11402 uint32_t last
= mFullScreenStack
.Length() - 1;
11403 mFullScreenStack
.RemoveElementAt(last
);
11405 // The top element of the stack is now an in-doc element. Apply the
11406 // full-screen styles and return.
11407 EventStateManager::SetFullScreenState(element
, true);
11414 nsDocument::FullScreenStackTop()
11416 if (mFullScreenStack
.IsEmpty()) {
11419 uint32_t last
= mFullScreenStack
.Length() - 1;
11420 nsCOMPtr
<Element
> element(do_QueryReferent(mFullScreenStack
[last
]));
11421 NS_ASSERTION(element
, "Should have full-screen element!");
11422 NS_ASSERTION(element
->IsInDoc(), "Full-screen element should be in doc");
11423 NS_ASSERTION(element
->OwnerDoc() == this, "Full-screen element should be in this doc");
11427 // Returns true if aDoc is in the focused tab in the active window.
11429 IsInActiveTab(nsIDocument
* aDoc
)
11431 nsCOMPtr
<nsIDocShell
> docshell
= aDoc
->GetDocShell();
11436 bool isActive
= false;
11437 docshell
->GetIsActive(&isActive
);
11442 nsCOMPtr
<nsIDocShellTreeItem
> rootItem
;
11443 docshell
->GetRootTreeItem(getter_AddRefs(rootItem
));
11447 nsCOMPtr
<nsIDOMWindow
> rootWin
= rootItem
->GetWindow();
11452 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
11457 nsCOMPtr
<nsIDOMWindow
> activeWindow
;
11458 fm
->GetActiveWindow(getter_AddRefs(activeWindow
));
11459 if (!activeWindow
) {
11463 return activeWindow
== rootWin
;
11466 nsresult
nsDocument::RemoteFrameFullscreenChanged(nsIDOMElement
* aFrameElement
,
11467 const nsAString
& aOrigin
)
11469 // Ensure the frame element is the fullscreen element in this document.
11470 // If the frame element is already the fullscreen element in this document,
11471 // this has no effect.
11472 nsCOMPtr
<nsIContent
> content(do_QueryInterface(aFrameElement
));
11473 FullScreenOptions opts
;
11474 RequestFullScreen(content
->AsElement(),
11476 /* aWasCallerChrome */ false,
11477 /* aNotifyOnOriginChange */ false);
11479 // Origin changed in child process, send notifiction, so that chrome can
11480 // update the UI to reflect the fullscreen origin change if necessary.
11481 // The BrowserElementChild listens on this, and forwards it over its
11482 // parent process, where it is redispatched. Chrome (in the root process,
11483 // which could be *this* process) listens for this notification so that
11484 // it can show a warning or approval UI.
11485 if (!aOrigin
.IsEmpty()) {
11486 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
11487 os
->NotifyObservers(GetFullscreenRootDocument(this),
11488 "fullscreen-origin-change",
11489 PromiseFlatString(aOrigin
).get());
11495 nsresult
nsDocument::RemoteFrameFullscreenReverted()
11497 RestorePreviousFullScreenState();
11502 ReleaseHMDInfoRef(void *, nsIAtom
*, void *aPropertyValue
, void *)
11504 if (aPropertyValue
) {
11505 static_cast<gfx::VRHMDInfo
*>(aPropertyValue
)->Release();
11510 nsDocument::RequestFullScreen(Element
* aElement
,
11511 FullScreenOptions
& aOptions
,
11512 bool aWasCallerChrome
,
11513 bool aNotifyOnOriginChange
)
11515 NS_ASSERTION(aElement
,
11516 "Must pass non-null element to nsDocument::RequestFullScreen");
11517 if (!aElement
|| aElement
== GetFullScreenElement()) {
11520 if (!aElement
->IsInDoc()) {
11521 LogFullScreenDenied(true, "FullScreenDeniedNotInDocument", this);
11524 if (aElement
->OwnerDoc() != this) {
11525 LogFullScreenDenied(true, "FullScreenDeniedMovedDocument", this);
11528 if (!GetWindow()) {
11529 LogFullScreenDenied(true, "FullScreenDeniedLostWindow", this);
11532 if (nsContentUtils::IsFullscreenApiContentOnly() &&
11533 nsContentUtils::IsChromeDoc(this)) {
11534 // Block fullscreen requests in the chrome document when the fullscreen API
11535 // is configured for content only.
11536 LogFullScreenDenied(true, "FullScreenDeniedContentOnly", this);
11539 if (!IsFullScreenEnabled(aWasCallerChrome
, true)) {
11540 // IsFullScreenEnabled calls LogFullScreenDenied, no need to log.
11543 if (GetFullScreenElement() &&
11544 !nsContentUtils::ContentIsDescendantOf(aElement
, GetFullScreenElement())) {
11545 // If this document is full-screen, only grant full-screen requests from
11546 // a descendant of the current full-screen element.
11547 LogFullScreenDenied(true, "FullScreenDeniedNotDescendant", this);
11550 if (!nsContentUtils::IsChromeDoc(this) && !IsInActiveTab(this)) {
11551 LogFullScreenDenied(true, "FullScreenDeniedNotFocusedTab", this);
11554 // Deny requests when a windowed plugin is focused.
11555 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
11557 NS_WARNING("Failed to retrieve focus manager in full-screen request.");
11560 nsCOMPtr
<nsIDOMElement
> focusedElement
;
11561 fm
->GetFocusedElement(getter_AddRefs(focusedElement
));
11562 if (focusedElement
) {
11563 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(focusedElement
);
11564 if (nsContentUtils::HasPluginWithUncontrolledEventDispatch(content
)) {
11565 LogFullScreenDenied(true, "FullScreenDeniedFocusedPlugin", this);
11570 // Stash a reference to any existing fullscreen doc, we'll use this later
11571 // to detect if the origin which is fullscreen has changed.
11572 nsCOMPtr
<nsIDocument
> previousFullscreenDoc
= GetFullscreenLeaf(this);
11574 AddFullscreenApprovedObserver();
11576 // Stores a list of documents which we must dispatch "mozfullscreenchange"
11577 // too. We're required by the spec to dispatch the events in root-to-leaf
11578 // order, but we traverse the doctree in a leaf-to-root order, so we save
11579 // references to the documents we must dispatch to so that we get the order
11581 nsAutoTArray
<nsIDocument
*, 8> changed
;
11583 // Remember the root document, so that if a full-screen document is hidden
11584 // we can reset full-screen state in the remaining visible full-screen documents.
11585 nsIDocument
* fullScreenRootDoc
= GetFullscreenRootDocument(this);
11586 if (fullScreenRootDoc
->IsFullScreenDoc()) {
11587 // A document is already in fullscreen, unlock the mouse pointer
11588 // before setting a new document to fullscreen
11592 // If a document is already in fullscreen, then unlock the mouse pointer
11593 // before setting a new document to fullscreen
11594 nsCOMPtr
<Element
> pointerLockedElement
=
11595 do_QueryReferent(EventStateManager::sPointerLockedElement
);
11596 if (pointerLockedElement
) {
11600 // Process options -- in this case, just HMD
11601 if (aOptions
.mVRHMDDevice
) {
11602 nsRefPtr
<gfx::VRHMDInfo
> hmdRef
= aOptions
.mVRHMDDevice
;
11603 aElement
->SetProperty(nsGkAtoms::vr_state
, hmdRef
.forget().take(),
11608 // Set the full-screen element. This sets the full-screen style on the
11609 // element, and the full-screen-ancestor styles on ancestors of the element
11610 // in this document.
11611 DebugOnly
<bool> x
= FullScreenStackPush(aElement
);
11612 NS_ASSERTION(x
, "Full-screen state of requesting doc should always change!");
11613 changed
.AppendElement(this);
11615 // Propagate up the document hierarchy, setting the full-screen element as
11616 // the element's container in ancestor documents. This also sets the
11617 // appropriate css styles as well. Note we don't propagate down the
11618 // document hierarchy, the full-screen element (or its container) is not
11619 // visible there. Stop when we reach the root document.
11620 nsIDocument
* child
= this;
11622 child
->SetFullscreenRoot(fullScreenRootDoc
);
11623 NS_ASSERTION(child
->GetFullscreenRoot() == fullScreenRootDoc
,
11624 "Fullscreen root should be set!");
11625 if (child
== fullScreenRootDoc
) {
11628 nsIDocument
* parent
= child
->GetParentDocument();
11629 Element
* element
= parent
->FindContentForSubDocument(child
)->AsElement();
11630 if (static_cast<nsDocument
*>(parent
)->FullScreenStackPush(element
)) {
11631 changed
.AppendElement(parent
);
11634 // We've reached either the root, or a point in the doctree where the
11635 // new full-screen element container is the same as the previous
11636 // full-screen element's container. No more changes need to be made
11637 // to the full-screen stacks of documents further up the tree.
11642 // Dispatch "mozfullscreenchange" events. Note this loop is in reverse
11643 // order so that the events for the root document arrives before the leaf
11644 // document, as required by the spec.
11645 for (uint32_t i
= 0; i
< changed
.Length(); ++i
) {
11646 DispatchFullScreenChange(changed
[changed
.Length() - i
- 1]);
11649 // If this document hasn't already been approved in this session,
11650 // check to see if the user has granted the fullscreen access
11651 // to the document's principal's host, if it has one. Note that documents
11652 // in web apps which are the same origin as the web app are considered
11653 // trusted and so are automatically approved.
11654 if (!mIsApprovedForFullscreen
) {
11655 mIsApprovedForFullscreen
=
11656 !Preferences::GetBool("full-screen-api.approval-required") ||
11657 NodePrincipal()->GetAppStatus() >= nsIPrincipal::APP_STATUS_INSTALLED
||
11658 nsContentUtils::IsSitePermAllow(NodePrincipal(), "fullscreen");
11661 // If this document, or a document with the same principal has not
11662 // already been approved for fullscreen this fullscreen-session, dispatch
11663 // an event so that chrome knows to pop up a warning/approval UI.
11664 // Note previousFullscreenDoc=nullptr upon first entry, so we always
11665 // take this path on the first time we enter fullscreen in a fullscreen
11667 if (!mIsApprovedForFullscreen
||
11668 !nsContentUtils::HaveEqualPrincipals(previousFullscreenDoc
, this)) {
11669 nsRefPtr
<AsyncEventDispatcher
> asyncDispatcher
=
11670 new AsyncEventDispatcher(this,
11671 NS_LITERAL_STRING("MozEnteredDomFullscreen"),
11674 asyncDispatcher
->PostDOMEvent();
11678 // Note assertions must run before SetWindowFullScreen() as that does
11679 // synchronous event dispatch which can run script which exits full-screen!
11680 NS_ASSERTION(GetFullScreenElement() == aElement
,
11681 "Full-screen element should be the requested element!");
11682 NS_ASSERTION(IsFullScreenDoc(), "Should be full-screen doc");
11683 nsCOMPtr
<nsIDOMElement
> fse
;
11684 GetMozFullScreenElement(getter_AddRefs(fse
));
11685 nsCOMPtr
<nsIContent
> c(do_QueryInterface(fse
));
11686 NS_ASSERTION(c
->AsElement() == aElement
,
11687 "GetMozFullScreenElement should match GetFullScreenElement()");
11690 // The origin which is fullscreen changed, send a notifiction so that the
11691 // root document knows the origin of the document which requested fullscreen.
11692 // This is used for the fullscreen approval UI. If we're in a child
11693 // process, the root BrowserElementChild listens for this notification,
11694 // and forwards it across to its BrowserElementParent, which
11695 // re-broadcasts the message for the root document in its process.
11696 if (aNotifyOnOriginChange
&&
11697 !nsContentUtils::HaveEqualPrincipals(previousFullscreenDoc
, this)) {
11698 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
11699 nsIDocument
* root
= GetFullscreenRootDocument(this);
11700 nsAutoString origin
;
11701 nsContentUtils::GetUTFOrigin(NodePrincipal(), origin
);
11702 os
->NotifyObservers(root
, "fullscreen-origin-change", origin
.get());
11705 // Make the window full-screen. Note we must make the state changes above
11706 // before making the window full-screen, as then the document reports as
11707 // being in full-screen mode when the chrome "fullscreen" event fires,
11708 // enabling chrome to distinguish between browser and dom full-screen
11709 // modes. Also note that nsGlobalWindow::SetFullScreen() (which
11710 // SetWindowFullScreen() calls) proxies to the root window in its hierarchy,
11711 // and does not operate on the a per-nsIDOMWindow basis.
11712 SetWindowFullScreen(this, true, aOptions
.mVRHMDDevice
);
11716 nsDocument::GetMozFullScreenElement(nsIDOMElement
**aFullScreenElement
)
11719 Element
* el
= GetMozFullScreenElement(rv
);
11721 return rv
.ErrorCode();
11723 nsCOMPtr
<nsIDOMElement
> retval
= do_QueryInterface(el
);
11724 retval
.forget(aFullScreenElement
);
11729 nsDocument::GetMozFullScreenElement(ErrorResult
& rv
)
11731 if (IsFullScreenDoc()) {
11732 // Must have a full-screen element while in full-screen mode.
11733 Element
* el
= GetFullScreenElement();
11735 rv
.Throw(NS_ERROR_UNEXPECTED
);
11743 nsDocument::GetFullScreenElement()
11745 Element
* element
= FullScreenStackTop();
11746 NS_ASSERTION(!element
||
11747 element
->IsFullScreenAncestor(),
11748 "Fullscreen element should have fullscreen styles applied");
11753 nsDocument::GetMozFullScreen(bool *aFullScreen
)
11755 *aFullScreen
= MozFullScreen();
11760 nsDocument::GetMozFullScreenEnabled(bool *aFullScreen
)
11762 NS_ENSURE_ARG_POINTER(aFullScreen
);
11763 *aFullScreen
= MozFullScreenEnabled();
11768 nsDocument::MozFullScreenEnabled()
11770 return IsFullScreenEnabled(nsContentUtils::IsCallerChrome(), false);
11774 HasFullScreenSubDocument(nsIDocument
* aDoc
)
11776 uint32_t count
= CountFullscreenSubDocuments(aDoc
);
11777 NS_ASSERTION(count
<= 1, "Fullscreen docs should have at most 1 fullscreen child!");
11782 nsDocument::IsFullScreenEnabled(bool aCallerIsChrome
, bool aLogFailure
)
11784 if (nsContentUtils::IsFullScreenApiEnabled() && aCallerIsChrome
) {
11785 // Chrome code can always use the full-screen API, provided it's not
11786 // explicitly disabled. Note IsCallerChrome() returns true when running
11787 // in an nsRunnable, so don't use GetMozFullScreenEnabled() from an
11792 if (!nsContentUtils::IsFullScreenApiEnabled()) {
11793 LogFullScreenDenied(aLogFailure
, "FullScreenDeniedDisabled", this);
11796 if (!IsVisible()) {
11797 LogFullScreenDenied(aLogFailure
, "FullScreenDeniedHidden", this);
11800 if (HasFullScreenSubDocument(this)) {
11801 LogFullScreenDenied(aLogFailure
, "FullScreenDeniedSubDocFullScreen", this);
11805 // Ensure that all ancestor <iframe> elements have the allowfullscreen
11806 // boolean attribute set.
11807 nsCOMPtr
<nsIDocShell
> docShell(mDocumentContainer
);
11808 bool allowed
= false;
11810 docShell
->GetFullscreenAllowed(&allowed
);
11813 LogFullScreenDenied(aLogFailure
, "FullScreenDeniedIframeNotAllowed", this);
11820 DispatchPointerLockChange(nsIDocument
* aTarget
)
11826 nsRefPtr
<AsyncEventDispatcher
> asyncDispatcher
=
11827 new AsyncEventDispatcher(aTarget
,
11828 NS_LITERAL_STRING("mozpointerlockchange"),
11831 asyncDispatcher
->PostDOMEvent();
11835 DispatchPointerLockError(nsIDocument
* aTarget
)
11841 nsRefPtr
<AsyncEventDispatcher
> asyncDispatcher
=
11842 new AsyncEventDispatcher(aTarget
,
11843 NS_LITERAL_STRING("mozpointerlockerror"),
11846 asyncDispatcher
->PostDOMEvent();
11849 mozilla::StaticRefPtr
<nsPointerLockPermissionRequest
> gPendingPointerLockRequest
;
11851 class nsPointerLockPermissionRequest
: public nsRunnable
,
11852 public nsIContentPermissionRequest
11855 nsPointerLockPermissionRequest(Element
* aElement
, bool aUserInputOrChromeCaller
)
11856 : mElement(do_GetWeakReference(aElement
)),
11857 mDocument(do_GetWeakReference(aElement
->OwnerDoc())),
11858 mUserInputOrChromeCaller(aUserInputOrChromeCaller
) {}
11860 NS_DECL_ISUPPORTS_INHERITED
11861 NS_DECL_NSICONTENTPERMISSIONREQUEST
11863 NS_IMETHOD
Run() MOZ_OVERRIDE
11865 nsCOMPtr
<Element
> e
= do_QueryReferent(mElement
);
11866 nsCOMPtr
<nsIDocument
> d
= do_QueryReferent(mDocument
);
11867 if (!e
|| !d
|| gPendingPointerLockRequest
!= this ||
11868 e
->GetUncomposedDoc() != d
) {
11870 DispatchPointerLockError(d
);
11874 // We're about to enter fullscreen mode.
11875 nsDocument
* doc
= static_cast<nsDocument
*>(d
.get());
11876 if (doc
->mAsyncFullscreenPending
||
11877 (doc
->mHasFullscreenApprovedObserver
&& !doc
->mIsApprovedForFullscreen
)) {
11878 // We're still waiting for approval.
11882 if (doc
->mIsApprovedForFullscreen
|| doc
->mAllowRelocking
) {
11883 Allow(JS::UndefinedHandleValue
);
11887 // In non-fullscreen mode user input (or chrome caller) is required!
11888 // Also, don't let the page to try to get the permission too many times.
11889 if (!mUserInputOrChromeCaller
||
11890 doc
->mCancelledPointerLockRequests
> 2) {
11892 DispatchPointerLockError(d
);
11896 // Handling a request from user input in non-fullscreen mode.
11897 // Do a normal permission check.
11898 nsCOMPtr
<nsPIDOMWindow
> window
= doc
->GetInnerWindow();
11899 nsContentPermissionUtils::AskPermission(this, window
);
11905 mElement
= nullptr;
11906 mDocument
= nullptr;
11907 if (gPendingPointerLockRequest
== this) {
11908 gPendingPointerLockRequest
= nullptr;
11912 nsWeakPtr mElement
;
11913 nsWeakPtr mDocument
;
11914 bool mUserInputOrChromeCaller
;
11917 virtual ~nsPointerLockPermissionRequest() {}
11920 NS_IMPL_ISUPPORTS_INHERITED(nsPointerLockPermissionRequest
,
11922 nsIContentPermissionRequest
)
11925 nsPointerLockPermissionRequest::GetTypes(nsIArray
** aTypes
)
11927 nsTArray
<nsString
> emptyOptions
;
11928 return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("pointerLock"),
11929 NS_LITERAL_CSTRING("unused"),
11935 nsPointerLockPermissionRequest::GetPrincipal(nsIPrincipal
** aPrincipal
)
11937 nsCOMPtr
<nsIDocument
> d
= do_QueryReferent(mDocument
);
11939 NS_ADDREF(*aPrincipal
= d
->NodePrincipal());
11945 nsPointerLockPermissionRequest::GetWindow(nsIDOMWindow
** aWindow
)
11947 nsCOMPtr
<nsIDocument
> d
= do_QueryReferent(mDocument
);
11949 NS_IF_ADDREF(*aWindow
= d
->GetInnerWindow());
11955 nsPointerLockPermissionRequest::GetElement(nsIDOMElement
** aElement
)
11957 // It is enough to implement GetWindow.
11958 *aElement
= nullptr;
11963 nsPointerLockPermissionRequest::Cancel()
11965 nsCOMPtr
<nsIDocument
> d
= do_QueryReferent(mDocument
);
11968 static_cast<nsDocument
*>(d
.get())->mCancelledPointerLockRequests
++;
11969 DispatchPointerLockError(d
);
11975 nsPointerLockPermissionRequest::Allow(JS::HandleValue aChoices
)
11977 MOZ_ASSERT(aChoices
.isUndefined());
11979 nsCOMPtr
<Element
> e
= do_QueryReferent(mElement
);
11980 nsCOMPtr
<nsIDocument
> doc
= do_QueryReferent(mDocument
);
11981 nsDocument
* d
= static_cast<nsDocument
*>(doc
.get());
11982 if (!e
|| !d
|| gPendingPointerLockRequest
!= this ||
11983 e
->GetUncomposedDoc() != d
||
11984 (!mUserInputOrChromeCaller
&& !d
->mIsApprovedForFullscreen
)) {
11986 DispatchPointerLockError(d
);
11990 // Mark handled here so that we don't need to call it everywhere below.
11993 nsCOMPtr
<Element
> pointerLockedElement
=
11994 do_QueryReferent(EventStateManager::sPointerLockedElement
);
11995 if (e
== pointerLockedElement
) {
11996 DispatchPointerLockChange(d
);
12000 // Note, we must bypass focus change, so pass true as the last parameter!
12001 if (!d
->ShouldLockPointer(e
, pointerLockedElement
, true)) {
12002 DispatchPointerLockError(d
);
12006 if (!d
->SetPointerLock(e
, NS_STYLE_CURSOR_NONE
)) {
12007 DispatchPointerLockError(d
);
12011 d
->mCancelledPointerLockRequests
= 0;
12012 e
->SetPointerLock();
12013 EventStateManager::sPointerLockedElement
= do_GetWeakReference(e
);
12014 EventStateManager::sPointerLockedDoc
= do_GetWeakReference(doc
);
12015 NS_ASSERTION(EventStateManager::sPointerLockedElement
&&
12016 EventStateManager::sPointerLockedDoc
,
12017 "aElement and this should support weak references!");
12019 DispatchPointerLockChange(d
);
12024 nsDocument::SetApprovedForFullscreen(bool aIsApproved
)
12026 mIsApprovedForFullscreen
= aIsApproved
;
12030 nsDocument::Observe(nsISupports
*aSubject
,
12031 const char *aTopic
,
12032 const char16_t
*aData
)
12034 if (strcmp("fullscreen-approved", aTopic
) == 0) {
12035 nsCOMPtr
<nsIDocument
> subject(do_QueryInterface(aSubject
));
12036 if (subject
!= this) {
12039 SetApprovedForFullscreen(true);
12040 if (gPendingPointerLockRequest
) {
12041 // We have a request pending. Create a clone of it and re-dispatch so that
12042 // Run() method gets called again.
12043 nsCOMPtr
<Element
> el
=
12044 do_QueryReferent(gPendingPointerLockRequest
->mElement
);
12045 nsCOMPtr
<nsIDocument
> doc
=
12046 do_QueryReferent(gPendingPointerLockRequest
->mDocument
);
12047 bool userInputOrChromeCaller
=
12048 gPendingPointerLockRequest
->mUserInputOrChromeCaller
;
12049 gPendingPointerLockRequest
->Handled();
12050 if (doc
== this && el
&& el
->GetUncomposedDoc() == doc
) {
12051 nsPointerLockPermissionRequest
* clone
=
12052 new nsPointerLockPermissionRequest(el
, userInputOrChromeCaller
);
12053 gPendingPointerLockRequest
= clone
;
12054 nsCOMPtr
<nsIRunnable
> r
= gPendingPointerLockRequest
.get();
12055 NS_DispatchToMainThread(r
);
12058 } else if (strcmp("app-theme-changed", aTopic
) == 0) {
12059 if (!nsContentUtils::IsSystemPrincipal(NodePrincipal()) &&
12060 !IsUnstyledDocument()) {
12061 // We don't want to style the chrome window, only app ones.
12062 OnAppThemeChanged();
12069 nsDocument::OnAppThemeChanged()
12071 // Bail out if there is no theme support set up properly.
12072 auto themeOrigin
= Preferences::GetString("b2g.theme.origin");
12073 if (!themeOrigin
|| !Preferences::GetBool("dom.mozApps.themable")) {
12077 for (int32_t i
= 0; i
< GetNumberOfStyleSheets(); i
++) {
12078 nsRefPtr
<CSSStyleSheet
> sheet
= do_QueryObject(GetStyleSheetAt(i
));
12083 nsINode
* owningNode
= sheet
->GetOwnerNode();
12087 // Get a DOM stylesheet link to check the href against the theme origin.
12088 nsIURI
* sheetURI
= sheet
->GetOriginalURI();
12092 nsAutoString sheetOrigin
;
12093 nsContentUtils::GetUTFOrigin(sheetURI
, sheetOrigin
);
12094 if (!sheetOrigin
.Equals(themeOrigin
)) {
12098 // Finally getting a Stylesheet link.
12099 nsCOMPtr
<nsIStyleSheetLinkingElement
> link
= do_QueryInterface(owningNode
);
12105 link
->UpdateStyleSheet(nullptr, &willNotify
, &isAlternate
, true);
12110 nsDocument::RequestPointerLock(Element
* aElement
)
12112 NS_ASSERTION(aElement
,
12113 "Must pass non-null element to nsDocument::RequestPointerLock");
12115 nsCOMPtr
<Element
> pointerLockedElement
=
12116 do_QueryReferent(EventStateManager::sPointerLockedElement
);
12117 if (aElement
== pointerLockedElement
) {
12118 DispatchPointerLockChange(this);
12122 if (!ShouldLockPointer(aElement
, pointerLockedElement
)) {
12123 DispatchPointerLockError(this);
12127 bool userInputOrChromeCaller
= EventStateManager::IsHandlingUserInput() ||
12128 nsContentUtils::IsCallerChrome();
12130 gPendingPointerLockRequest
=
12131 new nsPointerLockPermissionRequest(aElement
, userInputOrChromeCaller
);
12132 nsCOMPtr
<nsIRunnable
> r
= gPendingPointerLockRequest
.get();
12133 NS_DispatchToMainThread(r
);
12137 nsDocument::ShouldLockPointer(Element
* aElement
, Element
* aCurrentLock
,
12138 bool aNoFocusCheck
)
12140 // Check if pointer lock pref is enabled
12141 if (!Preferences::GetBool("full-screen-api.pointer-lock.enabled")) {
12142 NS_WARNING("ShouldLockPointer(): Pointer Lock pref not enabled");
12146 if (aCurrentLock
&& aCurrentLock
->OwnerDoc() != aElement
->OwnerDoc()) {
12147 NS_WARNING("ShouldLockPointer(): Existing pointer lock element in a different document");
12151 if (!aElement
->IsInDoc()) {
12152 NS_WARNING("ShouldLockPointer(): Element without Document");
12156 if (mSandboxFlags
& SANDBOXED_POINTER_LOCK
) {
12157 NS_WARNING("ShouldLockPointer(): Document is sandboxed and doesn't allow pointer-lock");
12161 // Check if the element is in a document with a docshell.
12162 nsCOMPtr
<nsIDocument
> ownerDoc
= aElement
->OwnerDoc();
12163 if (!ownerDoc
->GetContainer()) {
12166 nsCOMPtr
<nsPIDOMWindow
> ownerWindow
= ownerDoc
->GetWindow();
12167 if (!ownerWindow
) {
12170 nsCOMPtr
<nsPIDOMWindow
> ownerInnerWindow
= ownerDoc
->GetInnerWindow();
12171 if (!ownerInnerWindow
) {
12174 if (ownerWindow
->GetCurrentInnerWindow() != ownerInnerWindow
) {
12178 nsCOMPtr
<nsIDOMWindow
> top
;
12179 ownerWindow
->GetScriptableTop(getter_AddRefs(top
));
12180 nsCOMPtr
<nsPIDOMWindow
> piTop
= do_QueryInterface(top
);
12181 if (!piTop
|| !piTop
->GetExtantDoc() ||
12182 piTop
->GetExtantDoc()->Hidden()) {
12183 NS_WARNING("ShouldLockPointer(): Top document isn't visible.");
12187 if (!aNoFocusCheck
) {
12188 mozilla::ErrorResult rv
;
12189 if (!piTop
->GetExtantDoc()->HasFocus(rv
)) {
12190 NS_WARNING("ShouldLockPointer(): Top document isn't focused.");
12199 nsDocument::SetPointerLock(Element
* aElement
, int aCursorStyle
)
12201 // NOTE: aElement will be nullptr when unlocking.
12202 nsCOMPtr
<nsPIDOMWindow
> window
= GetWindow();
12204 NS_WARNING("SetPointerLock(): No Window");
12208 nsIDocShell
*docShell
= window
->GetDocShell();
12210 NS_WARNING("SetPointerLock(): No DocShell (window already closed?)");
12214 nsRefPtr
<nsPresContext
> presContext
;
12215 docShell
->GetPresContext(getter_AddRefs(presContext
));
12216 if (!presContext
) {
12217 NS_WARNING("SetPointerLock(): Unable to get presContext in \
12218 domWindow->GetDocShell()->GetPresContext()");
12222 nsCOMPtr
<nsIPresShell
> shell
= presContext
->PresShell();
12224 NS_WARNING("SetPointerLock(): Unable to find presContext->PresShell()");
12228 nsIFrame
* rootFrame
= shell
->GetRootFrame();
12230 NS_WARNING("SetPointerLock(): Unable to get root frame");
12234 nsCOMPtr
<nsIWidget
> widget
= rootFrame
->GetNearestWidget();
12236 NS_WARNING("SetPointerLock(): Unable to find widget in \
12237 shell->GetRootFrame()->GetNearestWidget();");
12241 if (aElement
&& (aElement
->OwnerDoc() != this)) {
12242 NS_WARNING("SetPointerLock(): Element not in this document.");
12246 // Hide the cursor and set pointer lock for future mouse events
12247 nsRefPtr
<EventStateManager
> esm
= presContext
->EventStateManager();
12248 esm
->SetCursor(aCursorStyle
, nullptr, false,
12249 0.0f
, 0.0f
, widget
, true);
12250 esm
->SetPointerLock(widget
, aElement
);
12256 nsDocument::UnlockPointer(nsIDocument
* aDoc
)
12258 if (!EventStateManager::sIsPointerLocked
) {
12262 nsCOMPtr
<nsIDocument
> pointerLockedDoc
=
12263 do_QueryReferent(EventStateManager::sPointerLockedDoc
);
12264 if (!pointerLockedDoc
|| (aDoc
&& aDoc
!= pointerLockedDoc
)) {
12267 nsDocument
* doc
= static_cast<nsDocument
*>(pointerLockedDoc
.get());
12268 if (!doc
->SetPointerLock(nullptr, NS_STYLE_CURSOR_AUTO
)) {
12272 nsCOMPtr
<Element
> pointerLockedElement
=
12273 do_QueryReferent(EventStateManager::sPointerLockedElement
);
12274 if (pointerLockedElement
) {
12275 pointerLockedElement
->ClearPointerLock();
12278 EventStateManager::sPointerLockedElement
= nullptr;
12279 EventStateManager::sPointerLockedDoc
= nullptr;
12280 static_cast<nsDocument
*>(pointerLockedDoc
.get())->mAllowRelocking
= !!aDoc
;
12281 gPendingPointerLockRequest
= nullptr;
12282 DispatchPointerLockChange(pointerLockedDoc
);
12286 nsIDocument::UnlockPointer(nsIDocument
* aDoc
)
12288 nsDocument::UnlockPointer(aDoc
);
12292 nsDocument::MozExitPointerLock()
12294 nsIDocument::MozExitPointerLock();
12299 nsDocument::GetMozPointerLockElement(nsIDOMElement
** aPointerLockedElement
)
12301 Element
* el
= nsIDocument::GetMozPointerLockElement();
12302 nsCOMPtr
<nsIDOMElement
> retval
= do_QueryInterface(el
);
12303 retval
.forget(aPointerLockedElement
);
12308 nsIDocument::GetMozPointerLockElement()
12310 nsCOMPtr
<Element
> pointerLockedElement
=
12311 do_QueryReferent(EventStateManager::sPointerLockedElement
);
12312 if (!pointerLockedElement
) {
12316 // Make sure pointer locked element is in the same document.
12317 nsCOMPtr
<nsIDocument
> pointerLockedDoc
=
12318 do_QueryReferent(EventStateManager::sPointerLockedDoc
);
12319 if (pointerLockedDoc
!= this) {
12323 return pointerLockedElement
;
12327 nsDocument::XPCOMShutdown()
12329 gPendingPointerLockRequest
= nullptr;
12330 sProcessingStack
.reset();
12334 nsDocument::UpdateVisibilityState()
12336 dom::VisibilityState oldState
= mVisibilityState
;
12337 mVisibilityState
= GetVisibilityState();
12338 if (oldState
!= mVisibilityState
) {
12339 nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument
*>(this),
12340 NS_LITERAL_STRING("visibilitychange"),
12341 /* bubbles = */ true,
12342 /* cancelable = */ false);
12343 nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument
*>(this),
12344 NS_LITERAL_STRING("mozvisibilitychange"),
12345 /* bubbles = */ true,
12346 /* cancelable = */ false);
12348 EnumerateActivityObservers(NotifyActivityChanged
, nullptr);
12353 nsDocument::GetVisibilityState() const
12355 // We have to check a few pieces of information here:
12356 // 1) Are we in bfcache (!IsVisible())? If so, nothing else matters.
12357 // 2) Do we have an outer window? If not, we're hidden. Note that we don't
12358 // want to use GetWindow here because it does weird groveling for windows
12360 // 3) Is our outer window background? If so, we're hidden.
12361 // Otherwise, we're visible.
12362 if (!IsVisible() || !mWindow
|| !mWindow
->GetOuterWindow() ||
12363 mWindow
->GetOuterWindow()->IsBackground()) {
12364 return dom::VisibilityState::Hidden
;
12367 return dom::VisibilityState::Visible
;
12371 nsDocument::PostVisibilityUpdateEvent()
12373 nsCOMPtr
<nsIRunnable
> event
=
12374 NS_NewRunnableMethod(this, &nsDocument::UpdateVisibilityState
);
12375 NS_DispatchToMainThread(event
);
12379 nsDocument::GetMozHidden(bool* aHidden
)
12381 *aHidden
= MozHidden();
12386 nsDocument::GetHidden(bool* aHidden
)
12388 *aHidden
= Hidden();
12393 nsDocument::GetMozVisibilityState(nsAString
& aState
)
12395 WarnOnceAbout(ePrefixedVisibilityAPI
);
12396 return GetVisibilityState(aState
);
12400 nsDocument::GetVisibilityState(nsAString
& aState
)
12402 const EnumEntry
& entry
=
12403 VisibilityStateValues::strings
[static_cast<int>(mVisibilityState
)];
12404 aState
.AssignASCII(entry
.value
, entry
.length
);
12409 nsIDocument::DocAddSizeOfExcludingThis(nsWindowSizes
* aWindowSizes
) const
12411 aWindowSizes
->mDOMOtherSize
+=
12412 nsINode::SizeOfExcludingThis(aWindowSizes
->mMallocSizeOf
);
12415 mPresShell
->AddSizeOfIncludingThis(aWindowSizes
->mMallocSizeOf
,
12416 &aWindowSizes
->mArenaStats
,
12417 &aWindowSizes
->mLayoutPresShellSize
,
12418 &aWindowSizes
->mLayoutStyleSetsSize
,
12419 &aWindowSizes
->mLayoutTextRunsSize
,
12420 &aWindowSizes
->mLayoutPresContextSize
);
12423 aWindowSizes
->mPropertyTablesSize
+=
12424 mPropertyTable
.SizeOfExcludingThis(aWindowSizes
->mMallocSizeOf
);
12425 for (uint32_t i
= 0, count
= mExtraPropertyTables
.Length();
12427 aWindowSizes
->mPropertyTablesSize
+=
12428 mExtraPropertyTables
[i
]->SizeOfIncludingThis(aWindowSizes
->mMallocSizeOf
);
12431 if (EventListenerManager
* elm
= GetExistingListenerManager()) {
12432 aWindowSizes
->mDOMEventListenersCount
+= elm
->ListenerCount();
12435 // Measurement of the following members may be added later if DMD finds it
12441 nsIDocument::DocAddSizeOfIncludingThis(nsWindowSizes
* aWindowSizes
) const
12443 aWindowSizes
->mDOMOtherSize
+= aWindowSizes
->mMallocSizeOf(this);
12444 DocAddSizeOfExcludingThis(aWindowSizes
);
12448 SizeOfStyleSheetsElementIncludingThis(nsIStyleSheet
* aStyleSheet
,
12449 MallocSizeOf aMallocSizeOf
,
12452 if (!aStyleSheet
->GetOwningDocument()) {
12453 // Avoid over-reporting shared sheets.
12456 return aStyleSheet
->SizeOfIncludingThis(aMallocSizeOf
);
12460 nsDocument::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf
) const
12462 // This SizeOfExcludingThis() overrides the one from nsINode. But
12463 // nsDocuments can only appear at the top of the DOM tree, and we use the
12464 // specialized DocAddSizeOfExcludingThis() in that case. So this should never
12470 nsDocument::DocAddSizeOfExcludingThis(nsWindowSizes
* aWindowSizes
) const
12472 nsIDocument::DocAddSizeOfExcludingThis(aWindowSizes
);
12474 for (nsIContent
* node
= nsINode::GetFirstChild();
12476 node
= node
->GetNextNode(this))
12478 size_t nodeSize
= node
->SizeOfIncludingThis(aWindowSizes
->mMallocSizeOf
);
12481 switch (node
->NodeType()) {
12482 case nsIDOMNode::ELEMENT_NODE
:
12483 p
= &aWindowSizes
->mDOMElementNodesSize
;
12485 case nsIDOMNode::TEXT_NODE
:
12486 p
= &aWindowSizes
->mDOMTextNodesSize
;
12488 case nsIDOMNode::CDATA_SECTION_NODE
:
12489 p
= &aWindowSizes
->mDOMCDATANodesSize
;
12491 case nsIDOMNode::COMMENT_NODE
:
12492 p
= &aWindowSizes
->mDOMCommentNodesSize
;
12495 p
= &aWindowSizes
->mDOMOtherSize
;
12501 if (EventListenerManager
* elm
= node
->GetExistingListenerManager()) {
12502 aWindowSizes
->mDOMEventListenersCount
+= elm
->ListenerCount();
12506 aWindowSizes
->mStyleSheetsSize
+=
12507 mStyleSheets
.SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis
,
12508 aWindowSizes
->mMallocSizeOf
);
12509 // Note that we do not own the sheets pointed to by mOnDemandBuiltInUASheets
12510 // (the nsLayoutStyleSheetCache singleton does) so pass nullptr as the
12511 // aSizeOfElementIncludingThis callback argument.
12512 aWindowSizes
->mStyleSheetsSize
+=
12513 mOnDemandBuiltInUASheets
.SizeOfExcludingThis(nullptr,
12514 aWindowSizes
->mMallocSizeOf
);
12515 aWindowSizes
->mStyleSheetsSize
+=
12516 mAdditionalSheets
[eAgentSheet
].
12517 SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis
,
12518 aWindowSizes
->mMallocSizeOf
);
12519 aWindowSizes
->mStyleSheetsSize
+=
12520 mAdditionalSheets
[eUserSheet
].
12521 SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis
,
12522 aWindowSizes
->mMallocSizeOf
);
12523 aWindowSizes
->mStyleSheetsSize
+=
12524 mAdditionalSheets
[eAuthorSheet
].
12525 SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis
,
12526 aWindowSizes
->mMallocSizeOf
);
12527 // Lumping in the loader with the style-sheets size is not ideal,
12528 // but most of the things in there are in fact stylesheets, so it
12529 // doesn't seem worthwhile to separate it out.
12530 aWindowSizes
->mStyleSheetsSize
+=
12531 CSSLoader()->SizeOfIncludingThis(aWindowSizes
->mMallocSizeOf
);
12533 aWindowSizes
->mDOMOtherSize
+=
12535 mAttrStyleSheet
->DOMSizeOfIncludingThis(aWindowSizes
->mMallocSizeOf
) :
12538 aWindowSizes
->mDOMOtherSize
+=
12539 mSVGAttrAnimationRuleProcessor
?
12540 mSVGAttrAnimationRuleProcessor
->DOMSizeOfIncludingThis(
12541 aWindowSizes
->mMallocSizeOf
) :
12544 aWindowSizes
->mDOMOtherSize
+=
12545 mStyledLinks
.SizeOfExcludingThis(nullptr, aWindowSizes
->mMallocSizeOf
);
12547 aWindowSizes
->mDOMOtherSize
+=
12548 mIdentifierMap
.SizeOfExcludingThis(aWindowSizes
->mMallocSizeOf
);
12550 // Measurement of the following members may be added later if DMD finds it
12556 nsDocument::QuerySelector(const nsAString
& aSelector
, nsIDOMElement
**aReturn
)
12558 return nsINode::QuerySelector(aSelector
, aReturn
);
12562 nsDocument::QuerySelectorAll(const nsAString
& aSelector
, nsIDOMNodeList
**aReturn
)
12564 return nsINode::QuerySelectorAll(aSelector
, aReturn
);
12567 already_AddRefed
<nsIDocument
>
12568 nsIDocument::Constructor(const GlobalObject
& aGlobal
,
12571 nsCOMPtr
<nsIScriptGlobalObject
> global
= do_QueryInterface(aGlobal
.GetAsSupports());
12573 rv
.Throw(NS_ERROR_UNEXPECTED
);
12577 nsCOMPtr
<nsIScriptObjectPrincipal
> prin
= do_QueryInterface(aGlobal
.GetAsSupports());
12579 rv
.Throw(NS_ERROR_UNEXPECTED
);
12583 nsCOMPtr
<nsIURI
> uri
;
12584 NS_NewURI(getter_AddRefs(uri
), "about:blank");
12586 rv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
12590 nsCOMPtr
<nsIDOMDocument
> document
;
12592 NS_NewDOMDocument(getter_AddRefs(document
),
12598 prin
->GetPrincipal(),
12601 DocumentFlavorPlain
);
12602 if (NS_FAILED(res
)) {
12607 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(document
);
12608 doc
->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE
);
12610 return doc
.forget();
12614 nsIDocument::CreateExpression(const nsAString
& aExpression
,
12615 XPathNSResolver
* aResolver
,
12618 return XPathEvaluator()->CreateExpression(aExpression
, aResolver
, rv
);
12622 nsIDocument::CreateNSResolver(nsINode
& aNodeResolver
)
12624 return XPathEvaluator()->CreateNSResolver(aNodeResolver
);
12627 already_AddRefed
<XPathResult
>
12628 nsIDocument::Evaluate(JSContext
* aCx
, const nsAString
& aExpression
,
12629 nsINode
& aContextNode
, XPathNSResolver
* aResolver
,
12630 uint16_t aType
, JS::Handle
<JSObject
*> aResult
,
12633 return XPathEvaluator()->Evaluate(aCx
, aExpression
, aContextNode
, aResolver
,
12634 aType
, aResult
, rv
);
12638 nsDocument::Evaluate(const nsAString
& aExpression
, nsIDOMNode
* aContextNode
,
12639 nsIDOMNode
* aResolver
, uint16_t aType
,
12640 nsISupports
* aInResult
, nsISupports
** aResult
)
12642 return XPathEvaluator()->Evaluate(aExpression
, aContextNode
, aResolver
, aType
,
12643 aInResult
, aResult
);
12647 nsIDocument::XPathEvaluator()
12649 if (!mXPathEvaluator
) {
12650 mXPathEvaluator
= new dom::XPathEvaluator(this);
12652 return mXPathEvaluator
;
12655 already_AddRefed
<nsIDocumentEncoder
>
12656 nsIDocument::GetCachedEncoder()
12658 return mCachedEncoder
.forget();
12662 nsIDocument::SetCachedEncoder(already_AddRefed
<nsIDocumentEncoder
> aEncoder
)
12664 mCachedEncoder
= aEncoder
;
12668 nsIDocument::SetContentTypeInternal(const nsACString
& aType
)
12670 mCachedEncoder
= nullptr;
12671 mContentType
= aType
;
12675 nsIDocument::GetLoadContext() const
12677 return mDocumentContainer
;
12681 nsIDocument::GetDocShell() const
12683 return mDocumentContainer
;
12687 nsIDocument::SetStateObject(nsIStructuredCloneContainer
*scContainer
)
12689 mStateObjectContainer
= scContainer
;
12690 mStateObjectCached
= nullptr;
12693 already_AddRefed
<Element
>
12694 nsIDocument::CreateHTMLElement(nsIAtom
* aTag
)
12696 nsRefPtr
<mozilla::dom::NodeInfo
> nodeInfo
;
12697 nodeInfo
= mNodeInfoManager
->GetNodeInfo(aTag
, nullptr, kNameSpaceID_XHTML
,
12698 nsIDOMNode::ELEMENT_NODE
);
12699 MOZ_ASSERT(nodeInfo
, "GetNodeInfo should never fail");
12701 nsCOMPtr
<Element
> element
;
12702 DebugOnly
<nsresult
> rv
= NS_NewHTMLElement(getter_AddRefs(element
),
12704 mozilla::dom::NOT_FROM_PARSER
);
12706 MOZ_ASSERT(NS_SUCCEEDED(rv
), "NS_NewHTMLElement should never fail");
12707 return element
.forget();
12711 MarkDocumentTreeToBeInSyncOperation(nsIDocument
* aDoc
, void* aData
)
12713 nsCOMArray
<nsIDocument
>* documents
=
12714 static_cast<nsCOMArray
<nsIDocument
>*>(aData
);
12716 aDoc
->SetIsInSyncOperation(true);
12717 documents
->AppendObject(aDoc
);
12718 aDoc
->EnumerateSubDocuments(MarkDocumentTreeToBeInSyncOperation
, aData
);
12723 nsAutoSyncOperation::nsAutoSyncOperation(nsIDocument
* aDoc
)
12725 mMicroTaskLevel
= nsContentUtils::MicroTaskLevel();
12726 nsContentUtils::SetMicroTaskLevel(0);
12728 nsPIDOMWindow
* win
= aDoc
->GetWindow();
12730 nsCOMPtr
<nsIDOMWindow
> topWindow
;
12731 win
->GetTop(getter_AddRefs(topWindow
));
12732 nsCOMPtr
<nsPIDOMWindow
> top
= do_QueryInterface(topWindow
);
12734 nsCOMPtr
<nsIDocument
> doc
= top
->GetExtantDoc();
12735 MarkDocumentTreeToBeInSyncOperation(doc
, &mDocuments
);
12741 nsAutoSyncOperation::~nsAutoSyncOperation()
12743 for (int32_t i
= 0; i
< mDocuments
.Count(); ++i
) {
12744 mDocuments
[i
]->SetIsInSyncOperation(false);
12746 nsContentUtils::SetMicroTaskLevel(mMicroTaskLevel
);
12750 nsIDocument::GetFonts(ErrorResult
& aRv
)
12752 nsIPresShell
* shell
= GetShell();
12754 aRv
.Throw(NS_ERROR_FAILURE
);
12758 nsPresContext
* presContext
= shell
->GetPresContext();
12759 if (!presContext
) {
12760 aRv
.Throw(NS_ERROR_FAILURE
);
12764 return presContext
->Fonts();