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/DebugOnly.h"
16 #include "mozilla/MemoryReporting.h"
17 #include "mozilla/Likely.h"
21 // so we can get logging even in release builds
22 #define FORCE_PR_LOG 1
28 #include "mozilla/Telemetry.h"
29 #include "nsIInterfaceRequestor.h"
30 #include "nsIInterfaceRequestorUtils.h"
31 #include "nsILoadContext.h"
32 #include "nsUnicharUtils.h"
33 #include "nsContentList.h"
34 #include "nsIObserver.h"
35 #include "nsIBaseWindow.h"
36 #include "mozilla/css/Loader.h"
37 #include "mozilla/css/ImageLoader.h"
38 #include "nsDocShell.h"
39 #include "nsIDocShellTreeItem.h"
40 #include "nsCOMArray.h"
41 #include "nsDOMClassInfo.h"
42 #include "mozilla/Services.h"
44 #include "mozilla/AsyncEventDispatcher.h"
45 #include "mozilla/BasicEvents.h"
46 #include "mozilla/EventListenerManager.h"
47 #include "mozilla/EventStateManager.h"
48 #include "nsIDOMNodeFilter.h"
50 #include "nsIDOMStyleSheet.h"
51 #include "mozilla/dom/Attr.h"
52 #include "nsIDOMDOMImplementation.h"
53 #include "nsIDOMDocumentXBL.h"
54 #include "mozilla/dom/Element.h"
55 #include "nsGenericHTMLElement.h"
56 #include "mozilla/dom/CDATASection.h"
57 #include "mozilla/dom/ProcessingInstruction.h"
58 #include "nsDOMString.h"
59 #include "nsNodeUtils.h"
60 #include "nsLayoutUtils.h" // for GetFrameForPoint
62 #include "nsITabChild.h"
65 #include "nsIDOMText.h"
66 #include "nsIDOMComment.h"
67 #include "mozilla/dom/DocumentType.h"
68 #include "mozilla/dom/NodeIterator.h"
69 #include "mozilla/dom/TreeWalker.h"
71 #include "nsIServiceManager.h"
72 #include "nsIServiceWorkerManager.h"
74 #include "nsContentCID.h"
76 #include "nsPresShell.h"
77 #include "nsPresContext.h"
79 #include "nsThreadUtils.h"
80 #include "nsNodeInfoManager.h"
81 #include "nsIFileChannel.h"
82 #include "nsIMultiPartChannel.h"
83 #include "nsIRefreshURI.h"
84 #include "nsIWebNavigation.h"
85 #include "nsIScriptError.h"
86 #include "nsStyleSheetService.h"
88 #include "nsNetUtil.h" // for NS_MakeAbsoluteURI
90 #include "nsIScriptSecurityManager.h"
91 #include "nsIPrincipal.h"
93 #include "nsIDOMWindow.h"
94 #include "nsPIDOMWindow.h"
95 #include "nsIDOMElement.h"
96 #include "nsFocusManager.h"
98 // for radio group stuff
99 #include "nsIDOMHTMLInputElement.h"
100 #include "nsIRadioVisitor.h"
101 #include "nsIFormControl.h"
103 #include "nsBidiUtils.h"
105 #include "nsIDOMUserDataHandler.h"
106 #include "nsIDOMXPathNSResolver.h"
107 #include "nsIParserService.h"
108 #include "nsContentCreatorFunctions.h"
110 #include "nsIScriptContext.h"
111 #include "nsBindingManager.h"
112 #include "nsIDOMHTMLDocument.h"
113 #include "nsHTMLDocument.h"
114 #include "nsIDOMHTMLFormElement.h"
115 #include "nsIRequest.h"
116 #include "nsHostObjectProtocolHandler.h"
118 #include "nsCharsetSource.h"
119 #include "nsIParser.h"
120 #include "nsIContentSink.h"
122 #include "nsDateTimeFormatCID.h"
123 #include "nsIDateTimeFormat.h"
124 #include "mozilla/EventDispatcher.h"
125 #include "mozilla/EventStates.h"
126 #include "mozilla/InternalMutationEvent.h"
127 #include "nsDOMCID.h"
130 #include "nsIXPConnect.h"
131 #include "nsCCUncollectableMarker.h"
132 #include "nsIContentPolicy.h"
133 #include "nsContentPolicyUtils.h"
134 #include "nsICategoryManager.h"
135 #include "nsIDocumentLoaderFactory.h"
136 #include "nsIDocumentLoader.h"
137 #include "nsIContentViewer.h"
138 #include "nsIXMLContentSink.h"
139 #include "nsIXULDocument.h"
140 #include "nsIPrompt.h"
141 #include "nsIPropertyBag2.h"
142 #include "mozilla/dom/PageTransitionEvent.h"
143 #include "mozilla/dom/StyleRuleChangeEvent.h"
144 #include "mozilla/dom/StyleSheetChangeEvent.h"
145 #include "mozilla/dom/StyleSheetApplicableStateChangeEvent.h"
146 #include "nsJSUtils.h"
147 #include "nsFrameLoader.h"
148 #include "nsEscape.h"
149 #include "nsObjectLoadingContent.h"
150 #include "nsHtml5TreeOpExecutor.h"
151 #include "mozilla/dom/HTMLLinkElement.h"
152 #include "mozilla/dom/HTMLMediaElement.h"
154 #include "mozAutoDocUpdate.h"
155 #include "nsGlobalWindow.h"
156 #include "mozilla/dom/EncodingUtils.h"
157 #include "mozilla/dom/quota/QuotaManager.h"
158 #include "nsDOMNavigationTiming.h"
160 #include "nsSMILAnimationController.h"
161 #include "imgIContainer.h"
162 #include "nsSVGUtils.h"
163 #include "SVGElementFactory.h"
165 #include "nsRefreshDriver.h"
167 // FOR CSP (autogenerated by xpidl)
168 #include "nsIContentSecurityPolicy.h"
169 #include "nsCSPService.h"
170 #include "nsHTMLStyleSheet.h"
171 #include "nsHTMLCSSStyleSheet.h"
172 #include "mozilla/dom/DOMImplementation.h"
173 #include "mozilla/dom/ShadowRoot.h"
174 #include "mozilla/dom/Comment.h"
175 #include "nsTextNode.h"
176 #include "mozilla/dom/Link.h"
177 #include "mozilla/dom/HTMLElementBinding.h"
178 #include "mozilla/dom/SVGElementBinding.h"
179 #include "nsXULAppAPI.h"
180 #include "mozilla/dom/Touch.h"
181 #include "mozilla/dom/TouchEvent.h"
183 #include "mozilla/Preferences.h"
185 #include "imgILoader.h"
186 #include "imgRequestProxy.h"
187 #include "nsWrapperCacheInlines.h"
188 #include "nsSandboxFlags.h"
189 #include "nsIAppsService.h"
190 #include "mozilla/dom/AnimationTimeline.h"
191 #include "mozilla/dom/BindingUtils.h"
192 #include "mozilla/dom/DocumentFragment.h"
193 #include "mozilla/dom/Event.h"
194 #include "mozilla/dom/HTMLBodyElement.h"
195 #include "mozilla/dom/HTMLInputElement.h"
196 #include "mozilla/dom/NodeFilterBinding.h"
197 #include "mozilla/dom/OwningNonNull.h"
198 #include "mozilla/dom/TabChild.h"
199 #include "mozilla/dom/UndoManager.h"
200 #include "mozilla/dom/WebComponentsBinding.h"
202 #include "nsDOMCaretPosition.h"
203 #include "nsIDOMHTMLTextAreaElement.h"
204 #include "nsViewportInfo.h"
205 #include "nsIContentPermissionPrompt.h"
206 #include "mozilla/StaticPtr.h"
207 #include "nsITextControlElement.h"
208 #include "nsIDOMNSEditableElement.h"
209 #include "nsIEditor.h"
210 #include "nsIDOMCSSStyleRule.h"
211 #include "mozilla/css/Rule.h"
212 #include "nsIDOMLocation.h"
213 #include "nsIHttpChannelInternal.h"
214 #include "nsISecurityConsoleMessage.h"
215 #include "nsCharSeparatedTokenizer.h"
216 #include "mozilla/dom/XPathEvaluator.h"
217 #include "mozilla/dom/XPathResult.h"
218 #include "nsIDocumentEncoder.h"
219 #include "nsIDocumentActivity.h"
220 #include "nsIStructuredCloneContainer.h"
221 #include "nsIMutableArray.h"
222 #include "nsContentPermissionHelper.h"
223 #include "mozilla/dom/DOMStringList.h"
224 #include "nsWindowMemoryReporter.h"
225 #include "nsLocation.h"
227 #ifdef MOZ_MEDIA_NAVIGATOR
228 #include "mozilla/MediaManager.h"
229 #endif // MOZ_MEDIA_NAVIGATOR
231 #include "IPeerConnection.h"
234 using namespace mozilla
;
235 using namespace mozilla::dom
;
237 typedef nsTArray
<Link
*> LinkArray
;
240 static PRLogModuleInfo
* gDocumentLeakPRLog
;
241 static PRLogModuleInfo
* gCspPRLog
;
244 #define NAME_NOT_VALID ((nsSimpleContentList*)1)
246 nsIdentifierMapEntry::~nsIdentifierMapEntry()
251 nsIdentifierMapEntry::Traverse(nsCycleCollectionTraversalCallback
* aCallback
)
253 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback
,
254 "mIdentifierMap mNameContentList");
255 aCallback
->NoteXPCOMChild(static_cast<nsIDOMNodeList
*>(mNameContentList
));
258 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback
,
259 "mIdentifierMap mImageElement element");
260 nsIContent
* imageElement
= mImageElement
;
261 aCallback
->NoteXPCOMChild(imageElement
);
266 nsIdentifierMapEntry::IsEmpty()
268 return mIdContentList
.Count() == 0 && !mNameContentList
&&
269 !mChangeCallbacks
&& !mImageElement
;
273 nsIdentifierMapEntry::GetIdElement()
275 return static_cast<Element
*>(mIdContentList
.SafeElementAt(0));
279 nsIdentifierMapEntry::GetImageIdElement()
281 return mImageElement
? mImageElement
.get() : GetIdElement();
285 nsIdentifierMapEntry::AppendAllIdContent(nsCOMArray
<nsIContent
>* aElements
)
287 for (int32_t i
= 0; i
< mIdContentList
.Count(); ++i
) {
288 aElements
->AppendObject(static_cast<Element
*>(mIdContentList
[i
]));
293 nsIdentifierMapEntry::AddContentChangeCallback(nsIDocument::IDTargetObserver aCallback
,
294 void* aData
, bool aForImage
)
296 if (!mChangeCallbacks
) {
297 mChangeCallbacks
= new nsTHashtable
<ChangeCallbackEntry
>;
298 if (!mChangeCallbacks
)
302 ChangeCallback cc
= { aCallback
, aData
, aForImage
};
303 mChangeCallbacks
->PutEntry(cc
);
307 nsIdentifierMapEntry::RemoveContentChangeCallback(nsIDocument::IDTargetObserver aCallback
,
308 void* aData
, bool aForImage
)
310 if (!mChangeCallbacks
)
312 ChangeCallback cc
= { aCallback
, aData
, aForImage
};
313 mChangeCallbacks
->RemoveEntry(cc
);
314 if (mChangeCallbacks
->Count() == 0) {
315 mChangeCallbacks
= nullptr;
319 struct FireChangeArgs
{
323 bool mHaveImageOverride
;
326 // XXX Workaround for bug 980560 to maintain the existing broken semantics
328 struct nsIStyleRule::COMTypeInfo
<css::Rule
, void> {
329 static const nsIID kIID
;
331 const nsIID
nsIStyleRule::COMTypeInfo
<css::Rule
, void>::kIID
= NS_ISTYLE_RULE_IID
;
336 static PLDHashOperator
337 CustomDefinitionsTraverse(CustomElementHashKey
* aKey
,
338 CustomElementDefinition
* aDefinition
,
341 nsCycleCollectionTraversalCallback
* cb
=
342 static_cast<nsCycleCollectionTraversalCallback
*>(aArg
);
344 nsAutoPtr
<LifecycleCallbacks
>& callbacks
= aDefinition
->mCallbacks
;
346 if (callbacks
->mAttributeChangedCallback
.WasPassed()) {
347 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
348 "mCustomDefinitions->mCallbacks->mAttributeChangedCallback");
349 cb
->NoteXPCOMChild(aDefinition
->mCallbacks
->mAttributeChangedCallback
.Value());
352 if (callbacks
->mCreatedCallback
.WasPassed()) {
353 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
354 "mCustomDefinitions->mCallbacks->mCreatedCallback");
355 cb
->NoteXPCOMChild(aDefinition
->mCallbacks
->mCreatedCallback
.Value());
358 if (callbacks
->mAttachedCallback
.WasPassed()) {
359 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
360 "mCustomDefinitions->mCallbacks->mAttachedCallback");
361 cb
->NoteXPCOMChild(aDefinition
->mCallbacks
->mAttachedCallback
.Value());
364 if (callbacks
->mDetachedCallback
.WasPassed()) {
365 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
366 "mCustomDefinitions->mCallbacks->mDetachedCallback");
367 cb
->NoteXPCOMChild(aDefinition
->mCallbacks
->mDetachedCallback
.Value());
370 return PL_DHASH_NEXT
;
373 static PLDHashOperator
374 CandidatesTraverse(CustomElementHashKey
* aKey
,
375 nsTArray
<nsRefPtr
<Element
>>* aData
,
378 nsCycleCollectionTraversalCallback
*cb
=
379 static_cast<nsCycleCollectionTraversalCallback
*>(aArg
);
380 for (size_t i
= 0; i
< aData
->Length(); ++i
) {
381 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
, "mCandidatesMap->Element");
382 cb
->NoteXPCOMChild(aData
->ElementAt(i
));
384 return PL_DHASH_NEXT
;
387 struct CustomDefinitionTraceArgs
389 const TraceCallbacks
& callbacks
;
393 static PLDHashOperator
394 CustomDefinitionTrace(CustomElementHashKey
*aKey
,
395 CustomElementDefinition
*aData
,
398 CustomDefinitionTraceArgs
* traceArgs
= static_cast<CustomDefinitionTraceArgs
*>(aArg
);
399 MOZ_ASSERT(aData
, "Definition must not be null");
400 traceArgs
->callbacks
.Trace(&aData
->mPrototype
, "mCustomDefinitions prototype",
402 return PL_DHASH_NEXT
;
405 NS_IMPL_CYCLE_COLLECTION_CLASS(Registry
)
407 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Registry
)
408 CustomDefinitionTraceArgs customDefinitionArgs
= { aCallbacks
, aClosure
};
409 tmp
->mCustomDefinitions
.EnumerateRead(CustomDefinitionTrace
,
410 &customDefinitionArgs
);
411 NS_IMPL_CYCLE_COLLECTION_TRACE_END
413 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Registry
)
414 tmp
->mCustomDefinitions
.EnumerateRead(CustomDefinitionsTraverse
, &cb
);
415 tmp
->mCandidatesMap
.EnumerateRead(CandidatesTraverse
, &cb
);
416 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
417 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
419 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Registry
)
420 tmp
->mCustomDefinitions
.Clear();
421 tmp
->mCandidatesMap
.Clear();
422 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
424 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Registry
)
425 NS_INTERFACE_MAP_ENTRY(nsISupports
)
428 NS_IMPL_CYCLE_COLLECTING_ADDREF(Registry
)
429 NS_IMPL_CYCLE_COLLECTING_RELEASE(Registry
)
433 mozilla::HoldJSObjects(this);
436 Registry::~Registry()
438 mozilla::DropJSObjects(this);
442 CustomElementCallback::Call()
446 case nsIDocument::eCreated
:
447 // For the duration of this callback invocation, the element is being created
448 // flag must be set to true.
449 mOwnerData
->mElementIsBeingCreated
= true;
450 mOwnerData
->mCreatedCallbackInvoked
= true;
451 static_cast<LifecycleCreatedCallback
*>(mCallback
.get())->Call(mThisObject
, rv
);
452 mOwnerData
->mElementIsBeingCreated
= false;
454 case nsIDocument::eAttached
:
455 static_cast<LifecycleAttachedCallback
*>(mCallback
.get())->Call(mThisObject
, rv
);
457 case nsIDocument::eDetached
:
458 static_cast<LifecycleDetachedCallback
*>(mCallback
.get())->Call(mThisObject
, rv
);
460 case nsIDocument::eAttributeChanged
:
461 static_cast<LifecycleAttributeChangedCallback
*>(mCallback
.get())->Call(mThisObject
,
462 mArgs
.name
, mArgs
.oldValue
, mArgs
.newValue
, rv
);
468 CustomElementCallback::Traverse(nsCycleCollectionTraversalCallback
& aCb
) const
470 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb
, "mThisObject");
471 aCb
.NoteXPCOMChild(mThisObject
);
473 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb
, "mCallback");
474 aCb
.NoteXPCOMChild(mCallback
);
477 CustomElementCallback::CustomElementCallback(Element
* aThisObject
,
478 nsIDocument::ElementCallbackType aCallbackType
,
479 mozilla::dom::CallbackFunction
* aCallback
,
480 CustomElementData
* aOwnerData
)
481 : mThisObject(aThisObject
),
482 mCallback(aCallback
),
483 mType(aCallbackType
),
484 mOwnerData(aOwnerData
)
488 CustomElementDefinition::CustomElementDefinition(JSObject
* aPrototype
,
491 LifecycleCallbacks
* aCallbacks
,
492 uint32_t aNamespaceID
,
494 : mPrototype(aPrototype
),
496 mLocalName(aLocalName
),
497 mCallbacks(aCallbacks
),
498 mNamespaceID(aNamespaceID
),
503 CustomElementData::CustomElementData(nsIAtom
* aType
)
505 mCurrentCallback(-1),
506 mElementIsBeingCreated(false),
507 mCreatedCallbackInvoked(true),
508 mAssociatedMicroTask(-1)
513 CustomElementData::RunCallbackQueue()
515 // Note: It's possible to re-enter this method.
516 while (static_cast<uint32_t>(++mCurrentCallback
) < mCallbackQueue
.Length()) {
517 mCallbackQueue
[mCurrentCallback
]->Call();
520 mCallbackQueue
.Clear();
521 mCurrentCallback
= -1;
525 } // namespace mozilla
527 static PLDHashOperator
528 FireChangeEnumerator(nsIdentifierMapEntry::ChangeCallbackEntry
*aEntry
, void *aArg
)
530 FireChangeArgs
* args
= static_cast<FireChangeArgs
*>(aArg
);
531 // Don't fire image changes for non-image observers, and don't fire element
532 // changes for image observers when an image override is active.
533 if (aEntry
->mKey
.mForImage
? (args
->mHaveImageOverride
&& !args
->mImageOnly
) :
535 return PL_DHASH_NEXT
;
536 return aEntry
->mKey
.mCallback(args
->mFrom
, args
->mTo
, aEntry
->mKey
.mData
)
537 ? PL_DHASH_NEXT
: PL_DHASH_REMOVE
;
541 nsIdentifierMapEntry::FireChangeCallbacks(Element
* aOldElement
,
542 Element
* aNewElement
,
545 if (!mChangeCallbacks
)
548 FireChangeArgs args
= { aOldElement
, aNewElement
, aImageOnly
, !!mImageElement
};
549 mChangeCallbacks
->EnumerateEntries(FireChangeEnumerator
, &args
);
553 nsIdentifierMapEntry::AddIdElement(Element
* aElement
)
555 NS_PRECONDITION(aElement
, "Must have element");
556 NS_PRECONDITION(mIdContentList
.IndexOf(nullptr) < 0,
557 "Why is null in our list?");
560 Element
* currentElement
=
561 static_cast<Element
*>(mIdContentList
.SafeElementAt(0));
565 if (mIdContentList
.Count() == 0) {
566 if (!mIdContentList
.AppendElement(aElement
))
568 NS_ASSERTION(currentElement
== nullptr, "How did that happen?");
569 FireChangeCallbacks(nullptr, aElement
);
573 // We seem to have multiple content nodes for the same id, or XUL is messing
574 // with us. Search for the right place to insert the content.
576 int32_t end
= mIdContentList
.Count();
578 NS_ASSERTION(start
< end
, "Bogus start/end");
580 int32_t cur
= (start
+ end
) / 2;
581 NS_ASSERTION(cur
>= start
&& cur
< end
, "What happened here?");
583 Element
* curElement
= static_cast<Element
*>(mIdContentList
[cur
]);
584 if (curElement
== aElement
) {
585 // Already in the list, so already in the right spot. Get out of here.
586 // XXXbz this only happens because XUL does all sorts of random
587 // UpdateIdTableEntry calls. Hate, hate, hate!
591 if (nsContentUtils::PositionIsBefore(aElement
, curElement
)) {
596 } while (start
!= end
);
598 if (!mIdContentList
.InsertElementAt(aElement
, start
))
602 Element
* oldElement
=
603 static_cast<Element
*>(mIdContentList
.SafeElementAt(1));
604 NS_ASSERTION(currentElement
== oldElement
, "How did that happen?");
605 FireChangeCallbacks(oldElement
, aElement
);
611 nsIdentifierMapEntry::RemoveIdElement(Element
* aElement
)
613 NS_PRECONDITION(aElement
, "Missing element");
615 // This should only be called while the document is in an update.
616 // Assertions near the call to this method guarantee this.
618 // This could fire in OOM situations
619 // Only assert this in HTML documents for now as XUL does all sorts of weird
621 NS_ASSERTION(!aElement
->OwnerDoc()->IsHTML() ||
622 mIdContentList
.IndexOf(aElement
) >= 0,
623 "Removing id entry that doesn't exist");
625 // XXXbz should this ever Compact() I guess when all the content is gone
626 // we'll just get cleaned up in the natural order of things...
627 Element
* currentElement
=
628 static_cast<Element
*>(mIdContentList
.SafeElementAt(0));
629 mIdContentList
.RemoveElement(aElement
);
630 if (currentElement
== aElement
) {
631 FireChangeCallbacks(currentElement
,
632 static_cast<Element
*>(mIdContentList
.SafeElementAt(0)));
637 nsIdentifierMapEntry::SetImageElement(Element
* aElement
)
639 Element
* oldElement
= GetImageIdElement();
640 mImageElement
= aElement
;
641 Element
* newElement
= GetImageIdElement();
642 if (oldElement
!= newElement
) {
643 FireChangeCallbacks(oldElement
, newElement
, true);
648 nsIdentifierMapEntry::AddNameElement(nsINode
* aNode
, Element
* aElement
)
650 if (!mNameContentList
) {
651 mNameContentList
= new nsSimpleContentList(aNode
);
654 mNameContentList
->AppendElement(aElement
);
658 nsIdentifierMapEntry::RemoveNameElement(Element
* aElement
)
660 if (mNameContentList
) {
661 mNameContentList
->RemoveElement(aElement
);
666 nsIdentifierMapEntry::HasIdElementExposedAsHTMLDocumentProperty()
668 Element
* idElement
= GetIdElement();
670 nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(idElement
);
674 nsIdentifierMapEntry::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf
) const
676 return nsStringHashKey::SizeOfExcludingThis(aMallocSizeOf
);
679 // Helper structs for the content->subdoc map
681 class SubDocMapEntry
: public PLDHashEntryHdr
684 // Both of these are strong references
685 Element
*mKey
; // must be first, to look like PLDHashEntryStub
686 nsIDocument
*mSubDocument
;
689 struct FindContentData
691 explicit FindContentData(nsIDocument
* aSubDoc
)
692 : mSubDocument(aSubDoc
), mResult(nullptr)
696 nsISupports
*mSubDocument
;
702 * A struct that holds all the information about a radio group.
704 struct nsRadioGroupStruct
707 : mRequiredRadioCount(0)
708 , mGroupSuffersFromValueMissing(false)
712 * A strong pointer to the currently selected radio button.
714 nsRefPtr
<HTMLInputElement
> mSelectedRadioButton
;
715 nsCOMArray
<nsIFormControl
> mRadioButtons
;
716 uint32_t mRequiredRadioCount
;
717 bool mGroupSuffersFromValueMissing
;
721 nsDOMStyleSheetList::nsDOMStyleSheetList(nsIDocument
*aDocument
)
724 // Not reference counted to avoid circular references.
725 // The document will tell us when its going away.
726 mDocument
= aDocument
;
727 mDocument
->AddObserver(this);
730 nsDOMStyleSheetList::~nsDOMStyleSheetList()
733 mDocument
->RemoveObserver(this);
737 NS_IMPL_ISUPPORTS_INHERITED(nsDOMStyleSheetList
, StyleSheetList
,
742 nsDOMStyleSheetList::Length()
748 // XXX Find the number and then cache it. We'll use the
749 // observer notification to figure out if new ones have
750 // been added or removed.
752 mLength
= mDocument
->GetNumberOfStyleSheets();
756 for (i
= 0; i
< mLength
; i
++) {
757 nsIStyleSheet
*sheet
= mDocument
->GetStyleSheetAt(i
);
758 nsCOMPtr
<nsIDOMStyleSheet
> domss(do_QueryInterface(sheet
));
759 NS_ASSERTION(domss
, "All \"normal\" sheets implement nsIDOMStyleSheet");
767 nsDOMStyleSheetList::IndexedGetter(uint32_t aIndex
, bool& aFound
)
769 if (!mDocument
|| aIndex
>= (uint32_t)mDocument
->GetNumberOfStyleSheets()) {
775 nsIStyleSheet
*sheet
= mDocument
->GetStyleSheetAt(aIndex
);
776 NS_ASSERTION(sheet
, "Must have a sheet");
778 return static_cast<CSSStyleSheet
*>(sheet
);
782 nsDOMStyleSheetList::NodeWillBeDestroyed(const nsINode
*aNode
)
788 nsDOMStyleSheetList::StyleSheetAdded(nsIDocument
*aDocument
,
789 nsIStyleSheet
* aStyleSheet
,
792 if (aDocumentSheet
&& -1 != mLength
) {
793 nsCOMPtr
<nsIDOMStyleSheet
> domss(do_QueryInterface(aStyleSheet
));
801 nsDOMStyleSheetList::StyleSheetRemoved(nsIDocument
*aDocument
,
802 nsIStyleSheet
* aStyleSheet
,
805 if (aDocumentSheet
&& -1 != mLength
) {
806 nsCOMPtr
<nsIDOMStyleSheet
> domss(do_QueryInterface(aStyleSheet
));
813 // nsOnloadBlocker implementation
814 NS_IMPL_ISUPPORTS(nsOnloadBlocker
, nsIRequest
)
817 nsOnloadBlocker::GetName(nsACString
&aResult
)
819 aResult
.AssignLiteral("about:document-onload-blocker");
824 nsOnloadBlocker::IsPending(bool *_retval
)
831 nsOnloadBlocker::GetStatus(nsresult
*status
)
838 nsOnloadBlocker::Cancel(nsresult status
)
843 nsOnloadBlocker::Suspend(void)
848 nsOnloadBlocker::Resume(void)
854 nsOnloadBlocker::GetLoadGroup(nsILoadGroup
* *aLoadGroup
)
856 *aLoadGroup
= nullptr;
861 nsOnloadBlocker::SetLoadGroup(nsILoadGroup
* aLoadGroup
)
867 nsOnloadBlocker::GetLoadFlags(nsLoadFlags
*aLoadFlags
)
869 *aLoadFlags
= nsIRequest::LOAD_NORMAL
;
874 nsOnloadBlocker::SetLoadFlags(nsLoadFlags aLoadFlags
)
879 // ==================================================================
881 nsExternalResourceMap::nsExternalResourceMap()
882 : mHaveShutDown(false)
887 nsExternalResourceMap::RequestResource(nsIURI
* aURI
,
888 nsINode
* aRequestingNode
,
889 nsDocument
* aDisplayDocument
,
890 ExternalResourceLoad
** aPendingLoad
)
892 // If we ever start allowing non-same-origin loads here, we might need to do
893 // something interesting with aRequestingPrincipal even for the hashtable
895 NS_PRECONDITION(aURI
, "Must have a URI");
896 NS_PRECONDITION(aRequestingNode
, "Must have a node");
897 *aPendingLoad
= nullptr;
902 // First, make sure we strip the ref from aURI.
903 nsCOMPtr
<nsIURI
> clone
;
904 nsresult rv
= aURI
->CloneIgnoringRef(getter_AddRefs(clone
));
905 if (NS_FAILED(rv
) || !clone
) {
909 ExternalResource
* resource
;
910 mMap
.Get(clone
, &resource
);
912 return resource
->mDocument
;
915 nsRefPtr
<PendingLoad
> load
;
916 mPendingLoads
.Get(clone
, getter_AddRefs(load
));
918 load
.forget(aPendingLoad
);
922 load
= new PendingLoad(aDisplayDocument
);
924 mPendingLoads
.Put(clone
, load
);
926 if (NS_FAILED(load
->StartLoad(clone
, aRequestingNode
))) {
927 // Make sure we don't thrash things by trying this load again, since
928 // chances are it failed for good reasons (security check, etc).
929 AddExternalResource(clone
, nullptr, nullptr, aDisplayDocument
);
931 load
.forget(aPendingLoad
);
938 nsExternalResourceEnumArgs
940 nsIDocument::nsSubDocEnumFunc callback
;
944 static PLDHashOperator
945 ExternalResourceEnumerator(nsIURI
* aKey
,
946 nsExternalResourceMap::ExternalResource
* aData
,
949 nsExternalResourceEnumArgs
* args
=
950 static_cast<nsExternalResourceEnumArgs
*>(aClosure
);
952 aData
->mDocument
? args
->callback(aData
->mDocument
, args
->data
) : true;
953 return next
? PL_DHASH_NEXT
: PL_DHASH_STOP
;
957 nsExternalResourceMap::EnumerateResources(nsIDocument::nsSubDocEnumFunc aCallback
,
960 nsExternalResourceEnumArgs args
= { aCallback
, aData
};
961 mMap
.EnumerateRead(ExternalResourceEnumerator
, &args
);
964 static PLDHashOperator
965 ExternalResourceTraverser(nsIURI
* aKey
,
966 nsExternalResourceMap::ExternalResource
* aData
,
969 nsCycleCollectionTraversalCallback
*cb
=
970 static_cast<nsCycleCollectionTraversalCallback
*>(aClosure
);
972 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
973 "mExternalResourceMap.mMap entry"
975 cb
->NoteXPCOMChild(aData
->mDocument
);
977 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
978 "mExternalResourceMap.mMap entry"
980 cb
->NoteXPCOMChild(aData
->mViewer
);
982 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
983 "mExternalResourceMap.mMap entry"
985 cb
->NoteXPCOMChild(aData
->mLoadGroup
);
987 return PL_DHASH_NEXT
;
991 nsExternalResourceMap::Traverse(nsCycleCollectionTraversalCallback
* aCallback
) const
993 // mPendingLoads will get cleared out as the requests complete, so
994 // no need to worry about those here.
995 mMap
.EnumerateRead(ExternalResourceTraverser
, aCallback
);
998 static PLDHashOperator
999 ExternalResourceHider(nsIURI
* aKey
,
1000 nsExternalResourceMap::ExternalResource
* aData
,
1003 if (aData
->mViewer
) {
1004 aData
->mViewer
->Hide();
1006 return PL_DHASH_NEXT
;
1010 nsExternalResourceMap::HideViewers()
1012 mMap
.EnumerateRead(ExternalResourceHider
, nullptr);
1015 static PLDHashOperator
1016 ExternalResourceShower(nsIURI
* aKey
,
1017 nsExternalResourceMap::ExternalResource
* aData
,
1020 if (aData
->mViewer
) {
1021 aData
->mViewer
->Show();
1023 return PL_DHASH_NEXT
;
1027 nsExternalResourceMap::ShowViewers()
1029 mMap
.EnumerateRead(ExternalResourceShower
, nullptr);
1033 TransferZoomLevels(nsIDocument
* aFromDoc
,
1034 nsIDocument
* aToDoc
)
1036 NS_ABORT_IF_FALSE(aFromDoc
&& aToDoc
,
1037 "transferring zoom levels from/to null doc");
1039 nsIPresShell
* fromShell
= aFromDoc
->GetShell();
1043 nsPresContext
* fromCtxt
= fromShell
->GetPresContext();
1047 nsIPresShell
* toShell
= aToDoc
->GetShell();
1051 nsPresContext
* toCtxt
= toShell
->GetPresContext();
1055 toCtxt
->SetFullZoom(fromCtxt
->GetFullZoom());
1056 toCtxt
->SetBaseMinFontSize(fromCtxt
->BaseMinFontSize());
1057 toCtxt
->SetTextZoom(fromCtxt
->TextZoom());
1061 TransferShowingState(nsIDocument
* aFromDoc
, nsIDocument
* aToDoc
)
1063 NS_ABORT_IF_FALSE(aFromDoc
&& aToDoc
,
1064 "transferring showing state from/to null doc");
1066 if (aFromDoc
->IsShowing()) {
1067 aToDoc
->OnPageShow(true, nullptr);
1072 nsExternalResourceMap::AddExternalResource(nsIURI
* aURI
,
1073 nsIContentViewer
* aViewer
,
1074 nsILoadGroup
* aLoadGroup
,
1075 nsIDocument
* aDisplayDocument
)
1077 NS_PRECONDITION(aURI
, "Unexpected call");
1078 NS_PRECONDITION((aViewer
&& aLoadGroup
) || (!aViewer
&& !aLoadGroup
),
1079 "Must have both or neither");
1081 nsRefPtr
<PendingLoad
> load
;
1082 mPendingLoads
.Get(aURI
, getter_AddRefs(load
));
1083 mPendingLoads
.Remove(aURI
);
1085 nsresult rv
= NS_OK
;
1087 nsCOMPtr
<nsIDocument
> doc
;
1089 doc
= aViewer
->GetDocument();
1090 NS_ASSERTION(doc
, "Must have a document");
1092 nsCOMPtr
<nsIXULDocument
> xulDoc
= do_QueryInterface(doc
);
1094 // We don't handle XUL stuff here yet.
1095 rv
= NS_ERROR_NOT_AVAILABLE
;
1097 doc
->SetDisplayDocument(aDisplayDocument
);
1099 // Make sure that hiding our viewer will tear down its presentation.
1100 aViewer
->SetSticky(false);
1102 rv
= aViewer
->Init(nullptr, nsIntRect(0, 0, 0, 0));
1103 if (NS_SUCCEEDED(rv
)) {
1104 rv
= aViewer
->Open(nullptr, nullptr);
1108 if (NS_FAILED(rv
)) {
1111 aLoadGroup
= nullptr;
1115 ExternalResource
* newResource
= new ExternalResource();
1116 mMap
.Put(aURI
, newResource
);
1118 newResource
->mDocument
= doc
;
1119 newResource
->mViewer
= aViewer
;
1120 newResource
->mLoadGroup
= aLoadGroup
;
1122 TransferZoomLevels(aDisplayDocument
, doc
);
1123 TransferShowingState(aDisplayDocument
, doc
);
1126 const nsTArray
< nsCOMPtr
<nsIObserver
> > & obs
= load
->Observers();
1127 for (uint32_t i
= 0; i
< obs
.Length(); ++i
) {
1128 obs
[i
]->Observe(doc
, "external-resource-document-created", nullptr);
1134 NS_IMPL_ISUPPORTS(nsExternalResourceMap::PendingLoad
,
1139 nsExternalResourceMap::PendingLoad::OnStartRequest(nsIRequest
*aRequest
,
1140 nsISupports
*aContext
)
1142 nsExternalResourceMap
& map
= mDisplayDocument
->ExternalResourceMap();
1143 if (map
.HaveShutDown()) {
1144 return NS_BINDING_ABORTED
;
1147 nsCOMPtr
<nsIContentViewer
> viewer
;
1148 nsCOMPtr
<nsILoadGroup
> loadGroup
;
1149 nsresult rv
= SetupViewer(aRequest
, getter_AddRefs(viewer
),
1150 getter_AddRefs(loadGroup
));
1152 // Make sure to do this no matter what
1153 nsresult rv2
= map
.AddExternalResource(mURI
, viewer
, loadGroup
,
1155 if (NS_FAILED(rv
)) {
1158 if (NS_FAILED(rv2
)) {
1159 mTargetListener
= nullptr;
1163 return mTargetListener
->OnStartRequest(aRequest
, aContext
);
1167 nsExternalResourceMap::PendingLoad::SetupViewer(nsIRequest
* aRequest
,
1168 nsIContentViewer
** aViewer
,
1169 nsILoadGroup
** aLoadGroup
)
1171 NS_PRECONDITION(!mTargetListener
, "Unexpected call to OnStartRequest");
1173 *aLoadGroup
= nullptr;
1175 nsCOMPtr
<nsIChannel
> chan(do_QueryInterface(aRequest
));
1176 NS_ENSURE_TRUE(chan
, NS_ERROR_UNEXPECTED
);
1178 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aRequest
));
1180 bool requestSucceeded
;
1181 if (NS_FAILED(httpChannel
->GetRequestSucceeded(&requestSucceeded
)) ||
1182 !requestSucceeded
) {
1183 // Bail out on this load, since it looks like we have an HTTP error page
1184 return NS_BINDING_ABORTED
;
1189 chan
->GetContentType(type
);
1191 nsCOMPtr
<nsILoadGroup
> loadGroup
;
1192 chan
->GetLoadGroup(getter_AddRefs(loadGroup
));
1194 // Give this document its own loadgroup
1195 nsCOMPtr
<nsILoadGroup
> newLoadGroup
=
1196 do_CreateInstance(NS_LOADGROUP_CONTRACTID
);
1197 NS_ENSURE_TRUE(newLoadGroup
, NS_ERROR_OUT_OF_MEMORY
);
1198 newLoadGroup
->SetLoadGroup(loadGroup
);
1200 nsCOMPtr
<nsIInterfaceRequestor
> callbacks
;
1201 loadGroup
->GetNotificationCallbacks(getter_AddRefs(callbacks
));
1203 nsCOMPtr
<nsIInterfaceRequestor
> newCallbacks
=
1204 new LoadgroupCallbacks(callbacks
);
1205 newLoadGroup
->SetNotificationCallbacks(newCallbacks
);
1207 // This is some serious hackery cribbed from docshell
1208 nsCOMPtr
<nsICategoryManager
> catMan
=
1209 do_GetService(NS_CATEGORYMANAGER_CONTRACTID
);
1210 NS_ENSURE_TRUE(catMan
, NS_ERROR_NOT_AVAILABLE
);
1211 nsXPIDLCString contractId
;
1212 nsresult rv
= catMan
->GetCategoryEntry("Gecko-Content-Viewers", type
.get(),
1213 getter_Copies(contractId
));
1214 NS_ENSURE_SUCCESS(rv
, rv
);
1215 nsCOMPtr
<nsIDocumentLoaderFactory
> docLoaderFactory
=
1216 do_GetService(contractId
);
1217 NS_ENSURE_TRUE(docLoaderFactory
, NS_ERROR_NOT_AVAILABLE
);
1219 nsCOMPtr
<nsIContentViewer
> viewer
;
1220 nsCOMPtr
<nsIStreamListener
> listener
;
1221 rv
= docLoaderFactory
->CreateInstance("external-resource", chan
, newLoadGroup
,
1222 type
.get(), nullptr, nullptr,
1223 getter_AddRefs(listener
),
1224 getter_AddRefs(viewer
));
1225 NS_ENSURE_SUCCESS(rv
, rv
);
1226 NS_ENSURE_TRUE(viewer
, NS_ERROR_UNEXPECTED
);
1228 nsCOMPtr
<nsIParser
> parser
= do_QueryInterface(listener
);
1230 /// We don't want to deal with the various fake documents yet
1231 return NS_ERROR_NOT_IMPLEMENTED
;
1234 // We can't handle HTML and other weird things here yet.
1235 nsIContentSink
* sink
= parser
->GetContentSink();
1236 nsCOMPtr
<nsIXMLContentSink
> xmlSink
= do_QueryInterface(sink
);
1238 return NS_ERROR_NOT_IMPLEMENTED
;
1241 listener
.swap(mTargetListener
);
1242 viewer
.forget(aViewer
);
1243 newLoadGroup
.forget(aLoadGroup
);
1248 nsExternalResourceMap::PendingLoad::OnDataAvailable(nsIRequest
* aRequest
,
1249 nsISupports
* aContext
,
1250 nsIInputStream
* aStream
,
1254 NS_PRECONDITION(mTargetListener
, "Shouldn't be getting called!");
1255 if (mDisplayDocument
->ExternalResourceMap().HaveShutDown()) {
1256 return NS_BINDING_ABORTED
;
1258 return mTargetListener
->OnDataAvailable(aRequest
, aContext
, aStream
, aOffset
,
1263 nsExternalResourceMap::PendingLoad::OnStopRequest(nsIRequest
* aRequest
,
1264 nsISupports
* aContext
,
1267 // mTargetListener might be null if SetupViewer or AddExternalResource failed
1268 if (mTargetListener
) {
1269 nsCOMPtr
<nsIStreamListener
> listener
;
1270 mTargetListener
.swap(listener
);
1271 return listener
->OnStopRequest(aRequest
, aContext
, aStatus
);
1278 nsExternalResourceMap::PendingLoad::StartLoad(nsIURI
* aURI
,
1279 nsINode
* aRequestingNode
)
1281 NS_PRECONDITION(aURI
, "Must have a URI");
1282 NS_PRECONDITION(aRequestingNode
, "Must have a node");
1284 // Time to start a load. First, the security checks.
1286 nsIPrincipal
* requestingPrincipal
= aRequestingNode
->NodePrincipal();
1288 nsresult rv
= nsContentUtils::GetSecurityManager()->
1289 CheckLoadURIWithPrincipal(requestingPrincipal
, aURI
,
1290 nsIScriptSecurityManager::STANDARD
);
1291 NS_ENSURE_SUCCESS(rv
, rv
);
1293 // Allow data URIs and other URI's that inherit their principal by passing
1294 // true as the 3rd argument of CheckMayLoad, since we want
1295 // to allow external resources from data URIs regardless of the difference
1297 rv
= requestingPrincipal
->CheckMayLoad(aURI
, true, true);
1298 NS_ENSURE_SUCCESS(rv
, rv
);
1300 int16_t shouldLoad
= nsIContentPolicy::ACCEPT
;
1301 rv
= NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OTHER
,
1303 requestingPrincipal
,
1305 EmptyCString(), //mime guess
1308 nsContentUtils::GetContentPolicy(),
1309 nsContentUtils::GetSecurityManager());
1310 if (NS_FAILED(rv
)) return rv
;
1311 if (NS_CP_REJECTED(shouldLoad
)) {
1312 // Disallowed by content policy
1313 return NS_ERROR_CONTENT_BLOCKED
;
1316 nsIDocument
* doc
= aRequestingNode
->OwnerDoc();
1318 nsCOMPtr
<nsIInterfaceRequestor
> req
= nsContentUtils::GetSameOriginChecker();
1319 NS_ENSURE_TRUE(req
, NS_ERROR_OUT_OF_MEMORY
);
1321 nsCOMPtr
<nsILoadGroup
> loadGroup
= doc
->GetDocumentLoadGroup();
1322 nsCOMPtr
<nsIChannel
> channel
;
1323 rv
= NS_NewChannel(getter_AddRefs(channel
), aURI
, nullptr, loadGroup
, req
);
1324 NS_ENSURE_SUCCESS(rv
, rv
);
1328 return channel
->AsyncOpen(this, nullptr);
1331 NS_IMPL_ISUPPORTS(nsExternalResourceMap::LoadgroupCallbacks
,
1332 nsIInterfaceRequestor
)
1334 #define IMPL_SHIM(_i) \
1335 NS_IMPL_ISUPPORTS(nsExternalResourceMap::LoadgroupCallbacks::_i##Shim, _i)
1337 IMPL_SHIM(nsILoadContext
)
1338 IMPL_SHIM(nsIProgressEventSink
)
1339 IMPL_SHIM(nsIChannelEventSink
)
1340 IMPL_SHIM(nsISecurityEventSink
)
1341 IMPL_SHIM(nsIApplicationCacheContainer
)
1345 #define IID_IS(_i) aIID.Equals(NS_GET_IID(_i))
1347 #define TRY_SHIM(_i) \
1350 nsCOMPtr<_i> real = do_GetInterface(mCallbacks); \
1352 return NS_NOINTERFACE; \
1354 nsCOMPtr<_i> shim = new _i##Shim(this, real); \
1356 return NS_ERROR_OUT_OF_MEMORY; \
1358 shim.forget(aSink); \
1364 nsExternalResourceMap::LoadgroupCallbacks::GetInterface(const nsIID
& aIID
,
1368 (IID_IS(nsIPrompt
) || IID_IS(nsIAuthPrompt
) || IID_IS(nsIAuthPrompt2
) ||
1369 IID_IS(nsITabChild
))) {
1370 return mCallbacks
->GetInterface(aIID
, aSink
);
1375 TRY_SHIM(nsILoadContext
);
1376 TRY_SHIM(nsIProgressEventSink
);
1377 TRY_SHIM(nsIChannelEventSink
);
1378 TRY_SHIM(nsISecurityEventSink
);
1379 TRY_SHIM(nsIApplicationCacheContainer
);
1381 return NS_NOINTERFACE
;
1387 nsExternalResourceMap::ExternalResource::~ExternalResource()
1390 mViewer
->Close(nullptr);
1395 // ==================================================================
1397 // ==================================================================
1399 // If we ever have an nsIDocumentObserver notification for stylesheet title
1400 // changes we should update the list from that instead of overriding
1402 class nsDOMStyleSheetSetList MOZ_FINAL
: public DOMStringList
1405 explicit nsDOMStyleSheetSetList(nsIDocument
* aDocument
);
1409 mDocument
= nullptr;
1412 virtual void EnsureFresh() MOZ_OVERRIDE
;
1415 nsIDocument
* mDocument
; // Our document; weak ref. It'll let us know if it
1419 nsDOMStyleSheetSetList::nsDOMStyleSheetSetList(nsIDocument
* aDocument
)
1420 : mDocument(aDocument
)
1422 NS_ASSERTION(mDocument
, "Must have document!");
1426 nsDOMStyleSheetSetList::EnsureFresh()
1431 return; // Spec says "no exceptions", and we have no style sets if we have
1432 // no document, for sure
1435 int32_t count
= mDocument
->GetNumberOfStyleSheets();
1437 for (int32_t index
= 0; index
< count
; index
++) {
1438 nsIStyleSheet
* sheet
= mDocument
->GetStyleSheetAt(index
);
1439 NS_ASSERTION(sheet
, "Null sheet in sheet list!");
1440 sheet
->GetTitle(title
);
1441 if (!title
.IsEmpty() && !mNames
.Contains(title
) && !Add(title
)) {
1447 // ==================================================================
1448 nsIDocument::SelectorCache::SelectorCache()
1449 : nsExpirationTracker
<SelectorCacheKey
, 4>(1000) { }
1451 // CacheList takes ownership of aSelectorList.
1452 void nsIDocument::SelectorCache::CacheList(const nsAString
& aSelector
,
1453 nsCSSSelectorList
* aSelectorList
)
1455 SelectorCacheKey
* key
= new SelectorCacheKey(aSelector
);
1456 mTable
.Put(key
->mKey
, aSelectorList
);
1460 class nsIDocument::SelectorCacheKeyDeleter MOZ_FINAL
: public nsRunnable
1463 explicit SelectorCacheKeyDeleter(SelectorCacheKey
* aToDelete
)
1464 : mSelector(aToDelete
)
1466 MOZ_COUNT_CTOR(SelectorCacheKeyDeleter
);
1470 ~SelectorCacheKeyDeleter()
1472 MOZ_COUNT_DTOR(SelectorCacheKeyDeleter
);
1482 nsAutoPtr
<SelectorCacheKey
> mSelector
;
1485 void nsIDocument::SelectorCache::NotifyExpired(SelectorCacheKey
* aSelector
)
1487 RemoveObject(aSelector
);
1488 mTable
.Remove(aSelector
->mKey
);
1489 nsCOMPtr
<nsIRunnable
> runnable
= new SelectorCacheKeyDeleter(aSelector
);
1490 NS_DispatchToCurrentThread(runnable
);
1494 struct nsIDocument::FrameRequest
1496 FrameRequest(const FrameRequestCallbackHolder
& aCallback
,
1498 mCallback(aCallback
),
1502 // Conversion operator so that we can append these to a
1503 // FrameRequestCallbackList
1504 operator const FrameRequestCallbackHolder
& () const {
1508 // Comparator operators to allow RemoveElementSorted with an
1509 // integer argument on arrays of FrameRequest
1510 bool operator==(int32_t aHandle
) const {
1511 return mHandle
== aHandle
;
1513 bool operator<(int32_t aHandle
) const {
1514 return mHandle
< aHandle
;
1517 FrameRequestCallbackHolder mCallback
;
1521 static already_AddRefed
<mozilla::dom::NodeInfo
> nullNodeInfo
;
1523 // ==================================================================
1525 // ==================================================================
1526 nsIDocument::nsIDocument()
1527 : nsINode(nullNodeInfo
),
1528 mCharacterSet(NS_LITERAL_CSTRING("ISO-8859-1")),
1529 mNodeInfoManager(nullptr),
1530 mCompatMode(eCompatibility_FullStandards
),
1531 mVisibilityState(dom::VisibilityState::Hidden
),
1532 mIsInitialDocumentInWindow(false),
1533 mMayStartLayout(true),
1535 mRemovedFromDocShell(false),
1536 // mAllowDNSPrefetch starts true, so that we can always reliably && it
1537 // with various values that might disable it. Since we never prefetch
1538 // unless we get a window, and in that case the docshell value will get
1539 // &&-ed in, this is safe.
1540 mAllowDNSPrefetch(true),
1541 mIsBeingUsedAsImage(false),
1542 mHasLinksToUpdate(false),
1544 mDidFireDOMContentLoaded(true)
1549 // NOTE! nsDocument::operator new() zeroes out all members, so don't
1550 // bother initializing members to 0.
1552 nsDocument::nsDocument(const char* aContentType
)
1554 , mAnimatingImages(true)
1555 , mViewportType(Unknown
)
1557 SetContentTypeInternal(nsDependentCString(aContentType
));
1560 if (!gDocumentLeakPRLog
)
1561 gDocumentLeakPRLog
= PR_NewLogModule("DocumentLeak");
1563 if (gDocumentLeakPRLog
)
1564 PR_LOG(gDocumentLeakPRLog
, PR_LOG_DEBUG
,
1565 ("DOCUMENT %p created", this));
1568 gCspPRLog
= PR_NewLogModule("CSP");
1571 // Start out mLastStyleSheetSet as null, per spec
1572 SetDOMStringToNull(mLastStyleSheetSet
);
1574 if (!sProcessingStack
) {
1575 sProcessingStack
.emplace();
1576 // Add the base queue sentinel to the processing stack.
1577 sProcessingStack
->AppendElement((CustomElementData
*) nullptr);
1581 static PLDHashOperator
1582 ClearAllBoxObjects(nsIContent
* aKey
, nsPIBoxObject
* aBoxObject
, void* aUserArg
)
1585 aBoxObject
->Clear();
1587 return PL_DHASH_NEXT
;
1590 nsIDocument::~nsIDocument()
1592 if (mNodeInfoManager
) {
1593 mNodeInfoManager
->DropDocumentReference();
1598 nsDocument::~nsDocument()
1601 if (gDocumentLeakPRLog
)
1602 PR_LOG(gDocumentLeakPRLog
, PR_LOG_DEBUG
,
1603 ("DOCUMENT %p destroyed", this));
1606 NS_ASSERTION(!mIsShowing
, "Destroying a currently-showing document");
1608 // Note: This assert is only non-fatal because mochitest-bc triggers
1609 // it... as well as the preceding assert about !mIsShowing.
1610 NS_ASSERTION(!mObservingAppThemeChanged
,
1611 "Document leaked to shutdown, then the observer service dropped "
1612 "its ref to us so we were able to go away.");
1614 if (IsTopLevelContentDocument()) {
1615 //don't report for about: pages
1616 nsCOMPtr
<nsIPrincipal
> principal
= GetPrincipal();
1617 nsCOMPtr
<nsIURI
> uri
;
1618 principal
->GetURI(getter_AddRefs(uri
));
1619 bool isAboutScheme
= true;
1621 uri
->SchemeIs("about", &isAboutScheme
);
1624 if (!isAboutScheme
) {
1625 // Record the page load
1626 uint32_t pageLoaded
= 1;
1627 Accumulate(Telemetry::MIXED_CONTENT_UNBLOCK_COUNTER
, pageLoaded
);
1628 // Record the mixed content status of the docshell in Telemetry
1630 NO_MIXED_CONTENT
= 0, // There is no Mixed Content on the page
1631 MIXED_DISPLAY_CONTENT
= 1, // The page attempted to load Mixed Display Content
1632 MIXED_ACTIVE_CONTENT
= 2, // The page attempted to load Mixed Active Content
1633 MIXED_DISPLAY_AND_ACTIVE_CONTENT
= 3 // The page attempted to load Mixed Display & Mixed Active Content
1636 bool mixedActiveLoaded
= GetHasMixedActiveContentLoaded();
1637 bool mixedActiveBlocked
= GetHasMixedActiveContentBlocked();
1639 bool mixedDisplayLoaded
= GetHasMixedDisplayContentLoaded();
1640 bool mixedDisplayBlocked
= GetHasMixedDisplayContentBlocked();
1642 bool hasMixedDisplay
= (mixedDisplayBlocked
|| mixedDisplayLoaded
);
1643 bool hasMixedActive
= (mixedActiveBlocked
|| mixedActiveLoaded
);
1645 uint32_t mixedContentLevel
= NO_MIXED_CONTENT
;
1646 if (hasMixedDisplay
&& hasMixedActive
) {
1647 mixedContentLevel
= MIXED_DISPLAY_AND_ACTIVE_CONTENT
;
1648 } else if (hasMixedActive
){
1649 mixedContentLevel
= MIXED_ACTIVE_CONTENT
;
1650 } else if (hasMixedDisplay
) {
1651 mixedContentLevel
= MIXED_DISPLAY_CONTENT
;
1653 Accumulate(Telemetry::MIXED_CONTENT_PAGE_LOAD
, mixedContentLevel
);
1657 mInDestructor
= true;
1658 mInUnlinkOrDeletion
= true;
1660 mRegistry
= nullptr;
1662 mozilla::DropJSObjects(this);
1664 // Clear mObservers to keep it in sync with the mutationobserver list
1667 if (mStyleSheetSetList
) {
1668 mStyleSheetSetList
->Disconnect();
1671 if (mAnimationController
) {
1672 mAnimationController
->Disconnect();
1675 mParentDocument
= nullptr;
1677 // Kill the subdocument map, doing this will release its strong
1678 // references, if any.
1679 if (mSubDocuments
) {
1680 PL_DHashTableDestroy(mSubDocuments
);
1682 mSubDocuments
= nullptr;
1685 // Destroy link map now so we don't waste time removing
1687 DestroyElementMaps();
1689 nsAutoScriptBlocker scriptBlocker
;
1691 int32_t indx
; // must be signed
1692 uint32_t count
= mChildren
.ChildCount();
1693 for (indx
= int32_t(count
) - 1; indx
>= 0; --indx
) {
1694 mChildren
.ChildAt(indx
)->UnbindFromTree();
1695 mChildren
.RemoveChildAt(indx
);
1697 mFirstChild
= nullptr;
1698 mCachedRootElement
= nullptr;
1700 // Let the stylesheets know we're going away
1701 indx
= mStyleSheets
.Count();
1702 while (--indx
>= 0) {
1703 mStyleSheets
[indx
]->SetOwningDocument(nullptr);
1705 if (mAttrStyleSheet
) {
1706 mAttrStyleSheet
->SetOwningDocument(nullptr);
1708 // We don't own the mOnDemandBuiltInUASheets, so we don't need to reset them.
1710 if (mListenerManager
) {
1711 mListenerManager
->Disconnect();
1712 UnsetFlags(NODE_HAS_LISTENERMANAGER
);
1715 if (mScriptLoader
) {
1716 mScriptLoader
->DropDocumentReference();
1720 // Could be null here if Init() failed or if we have been unlinked.
1721 mCSSLoader
->DropDocumentReference();
1724 if (mStyleImageLoader
) {
1725 mStyleImageLoader
->DropDocumentReference();
1730 if (mBoxObjectTable
) {
1731 mBoxObjectTable
->EnumerateRead(ClearAllBoxObjects
, nullptr);
1732 delete mBoxObjectTable
;
1735 mPendingTitleChangeEvent
.Revoke();
1737 for (uint32_t i
= 0; i
< mHostObjectURIs
.Length(); ++i
) {
1738 nsHostObjectProtocolHandler::RemoveDataEntry(mHostObjectURIs
[i
]);
1741 // We don't want to leave residual locks on images. Make sure we're in an
1742 // unlocked state, and then clear the table.
1743 SetImageLockingState(false);
1744 mImageTracker
.Clear();
1749 NS_INTERFACE_TABLE_HEAD(nsDocument
)
1750 NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
1751 NS_INTERFACE_TABLE_BEGIN
1752 NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(nsDocument
, nsISupports
, nsINode
)
1753 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsINode
)
1754 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIDocument
)
1755 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIDOMDocument
)
1756 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIDOMNode
)
1757 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIDOMDocumentXBL
)
1758 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIScriptObjectPrincipal
)
1759 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIDOMEventTarget
)
1760 NS_INTERFACE_TABLE_ENTRY(nsDocument
, mozilla::dom::EventTarget
)
1761 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsISupportsWeakReference
)
1762 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIRadioGroupContainer
)
1763 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIMutationObserver
)
1764 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIApplicationCacheContainer
)
1765 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIObserver
)
1766 NS_INTERFACE_TABLE_ENTRY(nsDocument
, nsIDOMXPathEvaluator
)
1767 NS_INTERFACE_TABLE_END
1768 NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsDocument
)
1769 NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMXPathNSResolver
,
1770 new nsNode3Tearoff(this))
1771 NS_INTERFACE_MAP_END
1774 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDocument
)
1775 NS_IMETHODIMP_(MozExternalRefCountType
)
1776 nsDocument::Release()
1778 NS_PRECONDITION(0 != mRefCnt
, "dup release");
1779 NS_ASSERT_OWNINGTHREAD(nsDocument
);
1780 nsISupports
* base
= NS_CYCLE_COLLECTION_CLASSNAME(nsDocument
)::Upcast(this);
1781 bool shouldDelete
= false;
1782 nsrefcnt count
= mRefCnt
.decr(base
, &shouldDelete
);
1783 NS_LOG_RELEASE(this, count
, "nsDocument");
1785 if (mStackRefCnt
&& !mNeedsReleaseAfterStackRefCntRelease
) {
1786 mNeedsReleaseAfterStackRefCntRelease
= true;
1788 return mRefCnt
.get();
1791 nsNodeUtils::LastRelease(this);
1794 mRefCnt
.stabilizeForDeletion();
1795 DeleteCycleCollectable();
1801 NS_IMETHODIMP_(void)
1802 nsDocument::DeleteCycleCollectable()
1807 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsDocument
)
1808 if (Element::CanSkip(tmp
, aRemovingAllowed
)) {
1809 EventListenerManager
* elm
= tmp
->GetExistingListenerManager();
1815 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
1817 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsDocument
)
1818 return Element::CanSkipInCC(tmp
);
1819 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
1821 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsDocument
)
1822 return Element::CanSkipThis(tmp
);
1823 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
1825 static PLDHashOperator
1826 SubDocTraverser(PLDHashTable
*table
, PLDHashEntryHdr
*hdr
, uint32_t number
,
1829 SubDocMapEntry
*entry
= static_cast<SubDocMapEntry
*>(hdr
);
1830 nsCycleCollectionTraversalCallback
*cb
=
1831 static_cast<nsCycleCollectionTraversalCallback
*>(arg
);
1833 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
, "mSubDocuments entry->mKey");
1834 cb
->NoteXPCOMChild(entry
->mKey
);
1835 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
, "mSubDocuments entry->mSubDocument");
1836 cb
->NoteXPCOMChild(entry
->mSubDocument
);
1838 return PL_DHASH_NEXT
;
1841 static PLDHashOperator
1842 RadioGroupsTraverser(const nsAString
& aKey
, nsRadioGroupStruct
* aData
,
1845 nsCycleCollectionTraversalCallback
*cb
=
1846 static_cast<nsCycleCollectionTraversalCallback
*>(aClosure
);
1848 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
1849 "mRadioGroups entry->mSelectedRadioButton");
1850 cb
->NoteXPCOMChild(ToSupports(aData
->mSelectedRadioButton
));
1852 uint32_t i
, count
= aData
->mRadioButtons
.Count();
1853 for (i
= 0; i
< count
; ++i
) {
1854 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
,
1855 "mRadioGroups entry->mRadioButtons[i]");
1856 cb
->NoteXPCOMChild(aData
->mRadioButtons
[i
]);
1859 return PL_DHASH_NEXT
;
1862 static PLDHashOperator
1863 BoxObjectTraverser(nsIContent
* key
, nsPIBoxObject
* boxObject
, void* userArg
)
1865 nsCycleCollectionTraversalCallback
*cb
=
1866 static_cast<nsCycleCollectionTraversalCallback
*>(userArg
);
1868 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb
, "mBoxObjectTable entry");
1869 cb
->NoteXPCOMChild(boxObject
);
1871 return PL_DHASH_NEXT
;
1874 static PLDHashOperator
1875 IdentifierMapEntryTraverse(nsIdentifierMapEntry
*aEntry
, void *aArg
)
1877 nsCycleCollectionTraversalCallback
*cb
=
1878 static_cast<nsCycleCollectionTraversalCallback
*>(aArg
);
1879 aEntry
->Traverse(cb
);
1880 return PL_DHASH_NEXT
;
1883 static const char* kNSURIs
[] = {
1896 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument
)
1897 if (MOZ_UNLIKELY(cb
.WantDebugInfo())) {
1899 nsAutoCString loadedAsData
;
1900 if (tmp
->IsLoadedAsData()) {
1901 loadedAsData
.AssignLiteral("data");
1903 loadedAsData
.AssignLiteral("normal");
1905 uint32_t nsid
= tmp
->GetDefaultNamespaceID();
1907 if (tmp
->mDocumentURI
)
1908 tmp
->mDocumentURI
->GetSpec(uri
);
1909 if (nsid
< ArrayLength(kNSURIs
)) {
1910 PR_snprintf(name
, sizeof(name
), "nsDocument %s %s %s",
1911 loadedAsData
.get(), kNSURIs
[nsid
], uri
.get());
1914 PR_snprintf(name
, sizeof(name
), "nsDocument %s %s",
1915 loadedAsData
.get(), uri
.get());
1917 cb
.DescribeRefCountedNode(tmp
->mRefCnt
.get(), name
);
1920 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsDocument
, tmp
->mRefCnt
.get())
1923 // Always need to traverse script objects, so do that before we check
1924 // if we're uncollectable.
1925 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
1927 if (!nsINode::Traverse(tmp
, cb
)) {
1928 return NS_SUCCESS_INTERRUPTED_TRAVERSE
;
1931 tmp
->mIdentifierMap
.EnumerateEntries(IdentifierMapEntryTraverse
, &cb
);
1933 tmp
->mExternalResourceMap
.Traverse(&cb
);
1935 // Traverse the mChildren nsAttrAndChildArray.
1936 for (int32_t indx
= int32_t(tmp
->mChildren
.ChildCount()); indx
> 0; --indx
) {
1937 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mChildren[i]");
1938 cb
.NoteXPCOMChild(tmp
->mChildren
.ChildAt(indx
- 1));
1941 // Traverse all nsIDocument pointer members.
1942 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSecurityInfo
)
1943 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDisplayDocument
)
1945 // Traverse all nsDocument nsCOMPtrs.
1946 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParser
)
1947 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptGlobalObject
)
1948 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager
)
1949 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets
)
1950 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetSetList
)
1951 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptLoader
)
1952 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMasterDocument
)
1953 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImportManager
)
1955 tmp
->mRadioGroups
.EnumerateRead(RadioGroupsTraverser
, &cb
);
1957 // The boxobject for an element will only exist as long as it's in the
1958 // document, so we'll traverse the table here instead of from the element.
1959 if (tmp
->mBoxObjectTable
) {
1960 tmp
->mBoxObjectTable
->EnumerateRead(BoxObjectTraverser
, &cb
);
1963 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannel
)
1964 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleAttrStyleSheet
)
1965 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mXPathEvaluator
)
1966 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLayoutHistoryState
)
1967 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnloadBlocker
)
1968 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFirstBaseNodeWithHref
)
1969 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMImplementation
)
1970 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImageMaps
)
1971 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOriginalDocument
)
1972 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedEncoder
)
1973 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStateObjectCached
)
1974 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUndoManager
)
1975 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnimationTimeline
)
1976 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTemplateContentsOwner
)
1977 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildrenCollection
)
1978 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRegistry
)
1980 // Traverse all our nsCOMArrays.
1981 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets
)
1982 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnDemandBuiltInUASheets
)
1983 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPreloadingImages
)
1985 for (uint32_t i
= 0; i
< tmp
->mFrameRequestCallbacks
.Length(); ++i
) {
1986 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mFrameRequestCallbacks[i]");
1987 cb
.NoteXPCOMChild(tmp
->mFrameRequestCallbacks
[i
].mCallback
.GetISupports());
1990 // Traverse animation components
1991 if (tmp
->mAnimationController
) {
1992 tmp
->mAnimationController
->Traverse(&cb
);
1995 if (tmp
->mSubDocuments
&& tmp
->mSubDocuments
->ops
) {
1996 PL_DHashTableEnumerate(tmp
->mSubDocuments
, SubDocTraverser
, &cb
);
1999 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCSSLoader
)
2001 for (uint32_t i
= 0; i
< tmp
->mHostObjectURIs
.Length(); ++i
) {
2002 nsHostObjectProtocolHandler::Traverse(tmp
->mHostObjectURIs
[i
], cb
);
2004 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
2006 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocument
)
2008 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDocument
)
2009 if (tmp
->PreservingWrapper()) {
2010 NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mExpandoAndGeneration
.expando
);
2012 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
2013 NS_IMPL_CYCLE_COLLECTION_TRACE_END
2016 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument
)
2017 tmp
->mInUnlinkOrDeletion
= true;
2019 // Clear out our external resources
2020 tmp
->mExternalResourceMap
.Shutdown();
2022 nsAutoScriptBlocker scriptBlocker
;
2024 nsINode::Unlink(tmp
);
2026 // Unlink the mChildren nsAttrAndChildArray.
2027 for (int32_t indx
= int32_t(tmp
->mChildren
.ChildCount()) - 1;
2028 indx
>= 0; --indx
) {
2029 tmp
->mChildren
.ChildAt(indx
)->UnbindFromTree();
2030 tmp
->mChildren
.RemoveChildAt(indx
);
2032 tmp
->mFirstChild
= nullptr;
2034 NS_IMPL_CYCLE_COLLECTION_UNLINK(mXPathEvaluator
)
2035 tmp
->mCachedRootElement
= nullptr; // Avoid a dangling pointer
2036 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDisplayDocument
)
2037 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFirstBaseNodeWithHref
)
2038 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMImplementation
)
2039 NS_IMPL_CYCLE_COLLECTION_UNLINK(mImageMaps
)
2040 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOriginalDocument
)
2041 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedEncoder
)
2042 NS_IMPL_CYCLE_COLLECTION_UNLINK(mUndoManager
)
2043 NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnimationTimeline
)
2044 NS_IMPL_CYCLE_COLLECTION_UNLINK(mTemplateContentsOwner
)
2045 NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildrenCollection
)
2046 NS_IMPL_CYCLE_COLLECTION_UNLINK(mRegistry
)
2047 NS_IMPL_CYCLE_COLLECTION_UNLINK(mMasterDocument
)
2048 NS_IMPL_CYCLE_COLLECTION_UNLINK(mImportManager
)
2050 tmp
->mParentDocument
= nullptr;
2052 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPreloadingImages
)
2055 if (tmp
->mBoxObjectTable
) {
2056 tmp
->mBoxObjectTable
->EnumerateRead(ClearAllBoxObjects
, nullptr);
2057 delete tmp
->mBoxObjectTable
;
2058 tmp
->mBoxObjectTable
= nullptr;
2061 if (tmp
->mListenerManager
) {
2062 tmp
->mListenerManager
->Disconnect();
2063 tmp
->UnsetFlags(NODE_HAS_LISTENERMANAGER
);
2064 tmp
->mListenerManager
= nullptr;
2067 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets
)
2069 if (tmp
->mStyleSheetSetList
) {
2070 tmp
->mStyleSheetSetList
->Disconnect();
2071 tmp
->mStyleSheetSetList
= nullptr;
2074 if (tmp
->mSubDocuments
) {
2075 PL_DHashTableDestroy(tmp
->mSubDocuments
);
2076 tmp
->mSubDocuments
= nullptr;
2079 tmp
->mFrameRequestCallbacks
.Clear();
2081 tmp
->mRadioGroups
.Clear();
2083 // nsDocument has a pretty complex destructor, so we're going to
2084 // assume that *most* cycles you actually want to break somewhere
2085 // else, and not unlink an awful lot here.
2087 tmp
->mIdentifierMap
.Clear();
2088 tmp
->mExpandoAndGeneration
.Unlink();
2090 if (tmp
->mAnimationController
) {
2091 tmp
->mAnimationController
->Unlink();
2094 tmp
->mPendingTitleChangeEvent
.Revoke();
2096 if (tmp
->mCSSLoader
) {
2097 tmp
->mCSSLoader
->DropDocumentReference();
2098 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCSSLoader
)
2101 for (uint32_t i
= 0; i
< tmp
->mHostObjectURIs
.Length(); ++i
) {
2102 nsHostObjectProtocolHandler::RemoveDataEntry(tmp
->mHostObjectURIs
[i
]);
2105 tmp
->mInUnlinkOrDeletion
= false;
2106 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
2108 static bool sPrefsInitialized
= false;
2109 static uint32_t sOnloadDecodeLimit
= 0;
2114 if (mCSSLoader
|| mStyleImageLoader
|| mNodeInfoManager
|| mScriptLoader
) {
2115 return NS_ERROR_ALREADY_INITIALIZED
;
2118 if (!sPrefsInitialized
) {
2119 sPrefsInitialized
= true;
2120 Preferences::AddUintVarCache(&sOnloadDecodeLimit
, "image.onload.decode.limit", 0);
2123 // Force initialization.
2124 nsINode::nsSlots
* slots
= Slots();
2126 // Prepend self as mutation-observer whether we need it or not (some
2127 // subclasses currently do, other don't). This is because the code in
2128 // nsNodeUtils always notifies the first observer first, expecting the
2129 // first observer to be the document.
2130 NS_ENSURE_TRUE(slots
->mMutationObservers
.PrependElementUnlessExists(static_cast<nsIMutationObserver
*>(this)),
2131 NS_ERROR_OUT_OF_MEMORY
);
2134 mOnloadBlocker
= new nsOnloadBlocker();
2135 mCSSLoader
= new mozilla::css::Loader(this);
2136 // Assume we're not quirky, until we know otherwise
2137 mCSSLoader
->SetCompatibilityMode(eCompatibility_FullStandards
);
2139 mStyleImageLoader
= new mozilla::css::ImageLoader(this);
2141 mNodeInfoManager
= new nsNodeInfoManager();
2142 nsresult rv
= mNodeInfoManager
->Init(this);
2143 NS_ENSURE_SUCCESS(rv
, rv
);
2145 // mNodeInfo keeps NodeInfoManager alive!
2146 mNodeInfo
= mNodeInfoManager
->GetDocumentNodeInfo();
2147 NS_ENSURE_TRUE(mNodeInfo
, NS_ERROR_OUT_OF_MEMORY
);
2148 NS_ABORT_IF_FALSE(mNodeInfo
->NodeType() == nsIDOMNode::DOCUMENT_NODE
,
2149 "Bad NodeType in aNodeInfo");
2151 NS_ASSERTION(OwnerDoc() == this, "Our nodeinfo is busted!");
2153 // If after creation the owner js global is not set for a document
2154 // we use the default compartment for this document, instead of creating
2155 // wrapper in some random compartment when the document is exposed to js
2157 nsCOMPtr
<nsIGlobalObject
> global
= xpc::GetNativeForGlobal(xpc::PrivilegedJunkScope());
2158 NS_ENSURE_TRUE(global
, NS_ERROR_FAILURE
);
2159 mScopeObject
= do_GetWeakReference(global
);
2160 MOZ_ASSERT(mScopeObject
);
2162 mScriptLoader
= new nsScriptLoader(this);
2164 mozilla::HoldJSObjects(this);
2170 nsIDocument::DeleteAllProperties()
2172 for (uint32_t i
= 0; i
< GetPropertyTableCount(); ++i
) {
2173 PropertyTable(i
)->DeleteAllProperties();
2178 nsIDocument::DeleteAllPropertiesFor(nsINode
* aNode
)
2180 for (uint32_t i
= 0; i
< GetPropertyTableCount(); ++i
) {
2181 PropertyTable(i
)->DeleteAllPropertiesFor(aNode
);
2186 nsIDocument::GetExtraPropertyTable(uint16_t aCategory
)
2188 NS_ASSERTION(aCategory
> 0, "Category 0 should have already been handled");
2189 while (aCategory
>= mExtraPropertyTables
.Length() + 1) {
2190 mExtraPropertyTables
.AppendElement(new nsPropertyTable());
2192 return mExtraPropertyTables
[aCategory
- 1];
2196 nsIDocument::IsVisibleConsideringAncestors() const
2198 const nsIDocument
*parent
= this;
2200 if (!parent
->IsVisible()) {
2203 } while ((parent
= parent
->GetParentDocument()));
2209 nsDocument::Reset(nsIChannel
* aChannel
, nsILoadGroup
* aLoadGroup
)
2211 nsCOMPtr
<nsIURI
> uri
;
2212 nsCOMPtr
<nsIPrincipal
> principal
;
2214 // Note: this code is duplicated in XULDocument::StartDocumentLoad and
2215 // nsScriptSecurityManager::GetChannelPrincipal.
2216 // Note: this should match nsDocShell::OnLoadingSite
2217 NS_GetFinalChannelURI(aChannel
, getter_AddRefs(uri
));
2219 nsIScriptSecurityManager
*securityManager
=
2220 nsContentUtils::GetSecurityManager();
2221 if (securityManager
) {
2222 securityManager
->GetChannelPrincipal(aChannel
,
2223 getter_AddRefs(principal
));
2227 ResetToURI(uri
, aLoadGroup
, principal
);
2229 nsCOMPtr
<nsIPropertyBag2
> bag
= do_QueryInterface(aChannel
);
2231 nsCOMPtr
<nsIURI
> baseURI
;
2232 bag
->GetPropertyAsInterface(NS_LITERAL_STRING("baseURI"),
2233 NS_GET_IID(nsIURI
), getter_AddRefs(baseURI
));
2235 mDocumentBaseURI
= baseURI
;
2236 mChromeXHRDocBaseURI
= baseURI
;
2240 mChannel
= aChannel
;
2244 nsDocument::ResetToURI(nsIURI
*aURI
, nsILoadGroup
*aLoadGroup
,
2245 nsIPrincipal
* aPrincipal
)
2247 NS_PRECONDITION(aURI
, "Null URI passed to ResetToURI");
2250 if (gDocumentLeakPRLog
&& PR_LOG_TEST(gDocumentLeakPRLog
, PR_LOG_DEBUG
)) {
2252 aURI
->GetSpec(spec
);
2253 PR_LogPrint("DOCUMENT %p ResetToURI %s", this, spec
.get());
2257 mSecurityInfo
= nullptr;
2259 mDocumentLoadGroup
= nullptr;
2261 // Delete references to sub-documents and kill the subdocument map,
2262 // if any. It holds strong references
2263 if (mSubDocuments
) {
2264 PL_DHashTableDestroy(mSubDocuments
);
2266 mSubDocuments
= nullptr;
2269 // Destroy link map now so we don't waste time removing
2271 DestroyElementMaps();
2273 bool oldVal
= mInUnlinkOrDeletion
;
2274 mInUnlinkOrDeletion
= true;
2275 uint32_t count
= mChildren
.ChildCount();
2276 { // Scope for update
2277 MOZ_AUTO_DOC_UPDATE(this, UPDATE_CONTENT_MODEL
, true);
2278 for (int32_t i
= int32_t(count
) - 1; i
>= 0; i
--) {
2279 nsCOMPtr
<nsIContent
> content
= mChildren
.ChildAt(i
);
2281 nsIContent
* previousSibling
= content
->GetPreviousSibling();
2283 if (nsINode::GetFirstChild() == content
) {
2284 mFirstChild
= content
->GetNextSibling();
2286 mChildren
.RemoveChildAt(i
);
2287 nsNodeUtils::ContentRemoved(this, content
, i
, previousSibling
);
2288 content
->UnbindFromTree();
2290 mCachedRootElement
= nullptr;
2292 mInUnlinkOrDeletion
= oldVal
;
2294 mRegistry
= nullptr;
2296 // Reset our stylesheets
2297 ResetStylesheetsToURI(aURI
);
2299 // Release the listener manager
2300 if (mListenerManager
) {
2301 mListenerManager
->Disconnect();
2302 mListenerManager
= nullptr;
2305 // Release the stylesheets list.
2306 mDOMStyleSheets
= nullptr;
2308 // Release our principal after tearing down the document, rather than before.
2309 // This ensures that, during teardown, the document and the dying window (which
2310 // already nulled out its document pointer and cached the principal) have
2311 // matching principals.
2312 SetPrincipal(nullptr);
2314 // Clear the original URI so SetDocumentURI sets it.
2315 mOriginalURI
= nullptr;
2317 SetDocumentURI(aURI
);
2318 mChromeXHRDocURI
= aURI
;
2319 // If mDocumentBaseURI is null, nsIDocument::GetBaseURI() returns
2321 mDocumentBaseURI
= nullptr;
2322 mChromeXHRDocBaseURI
= nullptr;
2325 mDocumentLoadGroup
= do_GetWeakReference(aLoadGroup
);
2326 // there was an assertion here that aLoadGroup was not null. This
2327 // is no longer valid: nsDocShell::SetDocument does not create a
2328 // load group, and it works just fine
2330 // XXXbz what does "just fine" mean exactly? And given that there
2331 // is no nsDocShell::SetDocument, what is this talking about?
2334 mLastModified
.Truncate();
2335 // XXXbz I guess we're assuming that the caller will either pass in
2336 // a channel with a useful type or call SetContentType?
2337 SetContentTypeInternal(EmptyCString());
2338 mContentLanguage
.Truncate();
2339 mBaseTarget
.Truncate();
2340 mReferrer
.Truncate();
2342 mXMLDeclarationBits
= 0;
2344 // Now get our new principal
2346 SetPrincipal(aPrincipal
);
2348 nsIScriptSecurityManager
*securityManager
=
2349 nsContentUtils::GetSecurityManager();
2350 if (securityManager
) {
2351 nsCOMPtr
<nsILoadContext
> loadContext(mDocumentContainer
);
2353 if (!loadContext
&& aLoadGroup
) {
2354 nsCOMPtr
<nsIInterfaceRequestor
> cbs
;
2355 aLoadGroup
->GetNotificationCallbacks(getter_AddRefs(cbs
));
2356 loadContext
= do_GetInterface(cbs
);
2359 MOZ_ASSERT(loadContext
,
2360 "must have a load context or pass in an explicit principal");
2362 nsCOMPtr
<nsIPrincipal
> principal
;
2363 nsresult rv
= securityManager
->
2364 GetLoadContextCodebasePrincipal(mDocumentURI
, loadContext
,
2365 getter_AddRefs(principal
));
2366 if (NS_SUCCEEDED(rv
)) {
2367 SetPrincipal(principal
);
2372 // Refresh the principal on the compartment.
2373 nsPIDOMWindow
* win
= GetInnerWindow();
2375 win
->RefreshCompartmentPrincipal();
2380 nsDocument::RemoveDocStyleSheetsFromStyleSets()
2382 // The stylesheets should forget us
2383 int32_t indx
= mStyleSheets
.Count();
2384 while (--indx
>= 0) {
2385 nsIStyleSheet
* sheet
= mStyleSheets
[indx
];
2386 sheet
->SetOwningDocument(nullptr);
2388 if (sheet
->IsApplicable()) {
2389 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
2391 shell
->StyleSet()->RemoveDocStyleSheet(sheet
);
2394 // XXX Tell observers?
2399 nsDocument::RemoveStyleSheetsFromStyleSets(nsCOMArray
<nsIStyleSheet
>& aSheets
, nsStyleSet::sheetType aType
)
2401 // The stylesheets should forget us
2402 int32_t indx
= aSheets
.Count();
2403 while (--indx
>= 0) {
2404 nsIStyleSheet
* sheet
= aSheets
[indx
];
2405 sheet
->SetOwningDocument(nullptr);
2407 if (sheet
->IsApplicable()) {
2408 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
2410 shell
->StyleSet()->RemoveStyleSheet(aType
, sheet
);
2414 // XXX Tell observers?
2420 nsDocument::ResetStylesheetsToURI(nsIURI
* aURI
)
2424 mozAutoDocUpdate
upd(this, UPDATE_STYLE
, true);
2425 RemoveDocStyleSheetsFromStyleSets();
2426 RemoveStyleSheetsFromStyleSets(mOnDemandBuiltInUASheets
, nsStyleSet::eAgentSheet
);
2427 RemoveStyleSheetsFromStyleSets(mAdditionalSheets
[eAgentSheet
], nsStyleSet::eAgentSheet
);
2428 RemoveStyleSheetsFromStyleSets(mAdditionalSheets
[eUserSheet
], nsStyleSet::eUserSheet
);
2429 RemoveStyleSheetsFromStyleSets(mAdditionalSheets
[eAuthorSheet
], nsStyleSet::eDocSheet
);
2431 // Release all the sheets
2432 mStyleSheets
.Clear();
2433 mOnDemandBuiltInUASheets
.Clear();
2434 for (uint32_t i
= 0; i
< SheetTypeCount
; ++i
)
2435 mAdditionalSheets
[i
].Clear();
2437 // NOTE: We don't release the catalog sheets. It doesn't really matter
2438 // now, but it could in the future -- in which case not releasing them
2439 // is probably the right thing to do.
2441 // Now reset our inline style and attribute sheets.
2442 if (mAttrStyleSheet
) {
2443 mAttrStyleSheet
->Reset();
2444 mAttrStyleSheet
->SetOwningDocument(this);
2446 mAttrStyleSheet
= new nsHTMLStyleSheet(this);
2449 if (!mStyleAttrStyleSheet
) {
2450 mStyleAttrStyleSheet
= new nsHTMLCSSStyleSheet();
2453 // Now set up our style sets
2454 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
2456 FillStyleSet(shell
->StyleSet());
2461 AppendAuthorSheet(nsIStyleSheet
*aSheet
, void *aData
)
2463 nsStyleSet
*styleSet
= static_cast<nsStyleSet
*>(aData
);
2464 styleSet
->AppendStyleSheet(nsStyleSet::eDocSheet
, aSheet
);
2469 AppendSheetsToStyleSet(nsStyleSet
* aStyleSet
,
2470 const nsCOMArray
<nsIStyleSheet
>& aSheets
,
2471 nsStyleSet::sheetType aType
)
2473 for (int32_t i
= aSheets
.Count() - 1; i
>= 0; --i
) {
2474 aStyleSet
->AppendStyleSheet(aType
, aSheets
[i
]);
2480 nsDocument::FillStyleSet(nsStyleSet
* aStyleSet
)
2482 NS_PRECONDITION(aStyleSet
, "Must have a style set");
2483 NS_PRECONDITION(aStyleSet
->SheetCount(nsStyleSet::eDocSheet
) == 0,
2484 "Style set already has document sheets?");
2486 // We could consider moving this to nsStyleSet::Init, to match its
2487 // handling of the eAnimationSheet and eTransitionSheet levels.
2488 aStyleSet
->DirtyRuleProcessors(nsStyleSet::ePresHintSheet
);
2489 aStyleSet
->DirtyRuleProcessors(nsStyleSet::eStyleAttrSheet
);
2492 for (i
= mStyleSheets
.Count() - 1; i
>= 0; --i
) {
2493 nsIStyleSheet
* sheet
= mStyleSheets
[i
];
2494 if (sheet
->IsApplicable()) {
2495 aStyleSet
->AddDocStyleSheet(sheet
, this);
2499 nsStyleSheetService
*sheetService
= nsStyleSheetService::GetInstance();
2501 sheetService
->AuthorStyleSheets()->EnumerateForwards(AppendAuthorSheet
,
2505 // Iterate backwards to maintain order
2506 for (i
= mOnDemandBuiltInUASheets
.Count() - 1; i
>= 0; --i
) {
2507 nsIStyleSheet
* sheet
= mOnDemandBuiltInUASheets
[i
];
2508 if (sheet
->IsApplicable()) {
2509 aStyleSet
->PrependStyleSheet(nsStyleSet::eAgentSheet
, sheet
);
2513 AppendSheetsToStyleSet(aStyleSet
, mAdditionalSheets
[eAgentSheet
],
2514 nsStyleSet::eAgentSheet
);
2515 AppendSheetsToStyleSet(aStyleSet
, mAdditionalSheets
[eUserSheet
],
2516 nsStyleSet::eUserSheet
);
2517 AppendSheetsToStyleSet(aStyleSet
, mAdditionalSheets
[eAuthorSheet
],
2518 nsStyleSet::eDocSheet
);
2522 nsDocument::StartDocumentLoad(const char* aCommand
, nsIChannel
* aChannel
,
2523 nsILoadGroup
* aLoadGroup
,
2524 nsISupports
* aContainer
,
2525 nsIStreamListener
**aDocListener
,
2526 bool aReset
, nsIContentSink
* aSink
)
2529 if (gDocumentLeakPRLog
&& PR_LOG_TEST(gDocumentLeakPRLog
, PR_LOG_DEBUG
)) {
2530 nsCOMPtr
<nsIURI
> uri
;
2531 aChannel
->GetURI(getter_AddRefs(uri
));
2535 PR_LogPrint("DOCUMENT %p StartDocumentLoad %s", this, spec
.get());
2542 nsresult rv
= NodePrincipal()->GetAppId(&appId
);
2543 NS_ENSURE_SUCCESS(rv
, rv
);
2544 MOZ_ASSERT(appId
!= nsIScriptSecurityManager::UNKNOWN_APP_ID
,
2545 "Document should never have UNKNOWN_APP_ID");
2549 MOZ_ASSERT(GetReadyStateEnum() == nsIDocument::READYSTATE_UNINITIALIZED
,
2551 SetReadyStateInternal(READYSTATE_LOADING
);
2553 if (nsCRT::strcmp(kLoadAsData
, aCommand
) == 0) {
2554 mLoadedAsData
= true;
2555 // We need to disable script & style loading in this case.
2556 // We leave them disabled even in EndLoad(), and let anyone
2557 // who puts the document on display to worry about enabling.
2559 // Do not load/process scripts when loading as data
2560 ScriptLoader()->SetEnabled(false);
2563 CSSLoader()->SetEnabled(false); // Do not load/process styles when loading as data
2564 } else if (nsCRT::strcmp("external-resource", aCommand
) == 0) {
2565 // Allow CSS, but not scripts
2566 ScriptLoader()->SetEnabled(false);
2569 mMayStartLayout
= false;
2571 mHaveInputEncoding
= true;
2574 Reset(aChannel
, aLoadGroup
);
2577 nsAutoCString contentType
;
2578 nsCOMPtr
<nsIPropertyBag2
> bag
= do_QueryInterface(aChannel
);
2579 if ((bag
&& NS_SUCCEEDED(bag
->GetPropertyAsACString(
2580 NS_LITERAL_STRING("contentType"), contentType
))) ||
2581 NS_SUCCEEDED(aChannel
->GetContentType(contentType
))) {
2582 // XXX this is only necessary for viewsource:
2583 nsACString::const_iterator start
, end
, semicolon
;
2584 contentType
.BeginReading(start
);
2585 contentType
.EndReading(end
);
2587 FindCharInReadable(';', semicolon
, end
);
2588 SetContentTypeInternal(Substring(start
, semicolon
));
2591 RetrieveRelevantHeaders(aChannel
);
2593 mChannel
= aChannel
;
2594 nsCOMPtr
<nsIInputStreamChannel
> inStrmChan
= do_QueryInterface(mChannel
);
2596 bool isSrcdocChannel
;
2597 inStrmChan
->GetIsSrcdocChannel(&isSrcdocChannel
);
2598 if (isSrcdocChannel
) {
2599 mIsSrcdocDocument
= true;
2603 // If this document is being loaded by a docshell, copy its sandbox flags
2604 // to the document. These are immutable after being set here.
2605 nsCOMPtr
<nsIDocShell
> docShell
= do_QueryInterface(aContainer
);
2608 nsresult rv
= docShell
->GetSandboxFlags(&mSandboxFlags
);
2609 NS_ENSURE_SUCCESS(rv
, rv
);
2612 // If this is not a data document, set CSP.
2613 if (!mLoadedAsData
) {
2614 nsresult rv
= InitCSP(aChannel
);
2615 NS_ENSURE_SUCCESS(rv
, rv
);
2622 CSPErrorQueue::Add(const char* aMessageName
)
2624 mErrors
.AppendElement(aMessageName
);
2628 CSPErrorQueue::Flush(nsIDocument
* aDocument
)
2630 for (uint32_t i
= 0; i
< mErrors
.Length(); i
++) {
2631 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag
,
2632 NS_LITERAL_CSTRING("CSP"), aDocument
,
2633 nsContentUtils::eSECURITY_PROPERTIES
,
2640 nsDocument::SendToConsole(nsCOMArray
<nsISecurityConsoleMessage
>& aMessages
)
2642 for (uint32_t i
= 0; i
< aMessages
.Length(); ++i
) {
2643 nsAutoString messageTag
;
2644 aMessages
[i
]->GetTag(messageTag
);
2646 nsAutoString category
;
2647 aMessages
[i
]->GetCategory(category
);
2649 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag
,
2650 NS_ConvertUTF16toUTF8(category
),
2651 this, nsContentUtils::eSECURITY_PROPERTIES
,
2652 NS_ConvertUTF16toUTF8(messageTag
).get());
2657 AppendCSPFromHeader(nsIContentSecurityPolicy
* csp
,
2658 const nsAString
& aHeaderValue
,
2661 // Need to tokenize the header value since multiple headers could be
2662 // concatenated into one comma-separated list of policies.
2663 // See RFC2616 section 4.2 (last paragraph)
2664 nsresult rv
= NS_OK
;
2665 nsCharSeparatedTokenizer
tokenizer(aHeaderValue
, ',');
2666 while (tokenizer
.hasMoreTokens()) {
2667 const nsSubstring
& policy
= tokenizer
.nextToken();
2668 rv
= csp
->AppendPolicy(policy
, aReportOnly
);
2669 NS_ENSURE_SUCCESS(rv
, rv
);
2672 PR_LOG(gCspPRLog
, PR_LOG_DEBUG
,
2673 ("CSP refined with policy: \"%s\"",
2674 NS_ConvertUTF16toUTF8(policy
).get()));
2682 nsDocument::IsLoopDocument(nsIChannel
*aChannel
)
2684 nsCOMPtr
<nsIURI
> chanURI
;
2685 nsresult rv
= aChannel
->GetOriginalURI(getter_AddRefs(chanURI
));
2686 NS_ENSURE_SUCCESS(rv
, false);
2688 bool isAbout
= false;
2689 bool isLoop
= false;
2690 rv
= chanURI
->SchemeIs("about", &isAbout
);
2691 NS_ENSURE_SUCCESS(rv
, false);
2693 nsCOMPtr
<nsIURI
> loopURI
;
2694 rv
= NS_NewURI(getter_AddRefs(loopURI
), "about:loopconversation");
2695 NS_ENSURE_SUCCESS(rv
, false);
2696 rv
= chanURI
->EqualsExceptRef(loopURI
, &isLoop
);
2697 NS_ENSURE_SUCCESS(rv
, false);
2699 rv
= NS_NewURI(getter_AddRefs(loopURI
), "about:looppanel");
2700 NS_ENSURE_SUCCESS(rv
, false);
2701 rv
= chanURI
->EqualsExceptRef(loopURI
, &isLoop
);
2702 NS_ENSURE_SUCCESS(rv
, false);
2709 nsDocument::InitCSP(nsIChannel
* aChannel
)
2711 nsCOMPtr
<nsIContentSecurityPolicy
> csp
;
2712 if (!CSPService::sCSPEnabled
) {
2714 PR_LOG(gCspPRLog
, PR_LOG_DEBUG
,
2715 ("CSP is disabled, skipping CSP init for document %p", this));
2720 nsAutoCString tCspHeaderValue
, tCspROHeaderValue
;
2722 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(aChannel
);
2724 httpChannel
->GetResponseHeader(
2725 NS_LITERAL_CSTRING("content-security-policy"),
2728 httpChannel
->GetResponseHeader(
2729 NS_LITERAL_CSTRING("content-security-policy-report-only"),
2732 NS_ConvertASCIItoUTF16
cspHeaderValue(tCspHeaderValue
);
2733 NS_ConvertASCIItoUTF16
cspROHeaderValue(tCspROHeaderValue
);
2735 // Figure out if we need to apply an app default CSP or a CSP from an app manifest
2736 nsIPrincipal
* principal
= NodePrincipal();
2738 uint16_t appStatus
= principal
->GetAppStatus();
2739 bool applyAppDefaultCSP
= false;
2740 bool applyAppManifestCSP
= false;
2742 nsAutoString appManifestCSP
;
2743 nsAutoString appDefaultCSP
;
2744 if (appStatus
!= nsIPrincipal::APP_STATUS_NOT_INSTALLED
) {
2745 nsCOMPtr
<nsIAppsService
> appsService
= do_GetService(APPS_SERVICE_CONTRACTID
);
2748 if (NS_SUCCEEDED(principal
->GetAppId(&appId
))) {
2749 appsService
->GetManifestCSPByLocalId(appId
, appManifestCSP
);
2750 if (!appManifestCSP
.IsEmpty()) {
2751 applyAppManifestCSP
= true;
2753 appsService
->GetDefaultCSPByLocalId(appId
, appDefaultCSP
);
2754 if (!appDefaultCSP
.IsEmpty()) {
2755 applyAppDefaultCSP
= true;
2761 // Check if this is part of the Loop/Hello service
2762 bool applyLoopCSP
= IsLoopDocument(aChannel
);
2764 // If there's no CSP to apply, go ahead and return early
2765 if (!applyAppDefaultCSP
&&
2766 !applyAppManifestCSP
&&
2768 cspHeaderValue
.IsEmpty() &&
2769 cspROHeaderValue
.IsEmpty()) {
2771 nsCOMPtr
<nsIURI
> chanURI
;
2772 aChannel
->GetURI(getter_AddRefs(chanURI
));
2773 nsAutoCString aspec
;
2774 chanURI
->GetAsciiSpec(aspec
);
2775 PR_LOG(gCspPRLog
, PR_LOG_DEBUG
,
2776 ("no CSP for document, %s, %s",
2778 applyAppDefaultCSP
? "is app" : "not an app"));
2784 PR_LOG(gCspPRLog
, PR_LOG_DEBUG
, ("Document is an app or CSP header specified %p", this));
2789 // If Document is an app check to see if we already set CSP and return early
2790 // if that is indeed the case.
2792 // In general (see bug 947831), we should not be setting CSP on a principal
2793 // that aliases another document. For non-app code this is not a problem
2794 // since we only share the underlying principal with nested browsing
2795 // contexts for which a header cannot be set (e.g., about:blank and
2796 // about:srcodoc iframes) and thus won't try to set the CSP again. This
2797 // check ensures that we do not try to set CSP for an app.
2798 if (applyAppDefaultCSP
|| applyAppManifestCSP
) {
2799 nsCOMPtr
<nsIContentSecurityPolicy
> csp
;
2800 rv
= principal
->GetCsp(getter_AddRefs(csp
));
2801 NS_ENSURE_SUCCESS(rv
, rv
);
2805 PR_LOG(gCspPRLog
, PR_LOG_DEBUG
, ("%s %s %s",
2806 "This document is sharing principal with another document.",
2807 "Since the document is an app, CSP was already set.",
2808 "Skipping attempt to set CSP."));
2814 csp
= do_CreateInstance("@mozilla.org/cspcontext;1", &rv
);
2816 if (NS_FAILED(rv
)) {
2818 PR_LOG(gCspPRLog
, PR_LOG_DEBUG
, ("Failed to create CSP object: %x", rv
));
2823 // used as a "self" identifier for the CSP.
2824 nsCOMPtr
<nsIURI
> selfURI
;
2825 aChannel
->GetURI(getter_AddRefs(selfURI
));
2827 // Store the request context for violation reports
2828 csp
->SetRequestContext(nullptr, nullptr, aChannel
);
2830 // ----- if the doc is an app and we want a default CSP, apply it.
2831 if (applyAppDefaultCSP
) {
2832 csp
->AppendPolicy(appDefaultCSP
, false);
2835 // ----- if the doc is an app and specifies a CSP in its manifest, apply it.
2836 if (applyAppManifestCSP
) {
2837 csp
->AppendPolicy(appManifestCSP
, false);
2840 // ----- if the doc is part of Loop, apply the loop CSP
2842 nsAdoptingString loopCSP
;
2843 loopCSP
= Preferences::GetString("loop.CSP");
2844 NS_ASSERTION(loopCSP
, "Missing loop.CSP preference");
2845 // If the pref has been removed, we continue without setting a CSP
2847 csp
->AppendPolicy(loopCSP
, false);
2851 // ----- if there's a full-strength CSP header, apply it.
2852 if (!cspHeaderValue
.IsEmpty()) {
2853 rv
= AppendCSPFromHeader(csp
, cspHeaderValue
, false);
2854 NS_ENSURE_SUCCESS(rv
, rv
);
2857 // ----- if there's a report-only CSP header, apply it.
2858 if (!cspROHeaderValue
.IsEmpty()) {
2859 rv
= AppendCSPFromHeader(csp
, cspROHeaderValue
, true);
2860 NS_ENSURE_SUCCESS(rv
, rv
);
2863 // ----- Enforce frame-ancestor policy on any applied policies
2864 nsCOMPtr
<nsIDocShell
> docShell(mDocumentContainer
);
2866 bool safeAncestry
= false;
2868 // PermitsAncestry sends violation reports when necessary
2869 rv
= csp
->PermitsAncestry(docShell
, &safeAncestry
);
2871 if (NS_FAILED(rv
) || !safeAncestry
) {
2873 PR_LOG(gCspPRLog
, PR_LOG_DEBUG
,
2874 ("CSP doesn't like frame's ancestry, not loading."));
2876 // stop! ERROR page!
2877 aChannel
->Cancel(NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION
);
2881 rv
= principal
->SetCsp(csp
);
2882 NS_ENSURE_SUCCESS(rv
, rv
);
2884 PR_LOG(gCspPRLog
, PR_LOG_DEBUG
,
2885 ("Inserted CSP into principal %p", principal
));
2892 nsDocument::StopDocumentLoad()
2895 mParserAborted
= true;
2896 mParser
->Terminate();
2901 nsDocument::SetDocumentURI(nsIURI
* aURI
)
2903 nsCOMPtr
<nsIURI
> oldBase
= GetDocBaseURI();
2904 mDocumentURI
= NS_TryToMakeImmutable(aURI
);
2905 nsIURI
* newBase
= GetDocBaseURI();
2907 bool equalBases
= false;
2908 // Changing just the ref of a URI does not change how relative URIs would
2909 // resolve wrt to it, so we can treat the bases as equal as long as they're
2910 // equal ignoring the ref.
2911 if (oldBase
&& newBase
) {
2912 oldBase
->EqualsExceptRef(newBase
, &equalBases
);
2915 equalBases
= !oldBase
&& !newBase
;
2918 // If this is the first time we're setting the document's URI, set the
2919 // document's original URI.
2921 mOriginalURI
= mDocumentURI
;
2923 // If changing the document's URI changed the base URI of the document, we
2924 // need to refresh the hrefs of all the links on the page.
2931 nsDocument::SetChromeXHRDocURI(nsIURI
* aURI
)
2933 mChromeXHRDocURI
= aURI
;
2937 nsDocument::SetChromeXHRDocBaseURI(nsIURI
* aURI
)
2939 mChromeXHRDocBaseURI
= aURI
;
2943 nsDocument::GetLastModified(nsAString
& aLastModified
)
2945 nsIDocument::GetLastModified(aLastModified
);
2950 nsIDocument::GetLastModified(nsAString
& aLastModified
) const
2952 if (!mLastModified
.IsEmpty()) {
2953 aLastModified
.Assign(mLastModified
);
2955 // If we for whatever reason failed to find the last modified time
2956 // (or even the current time), fall back to what NS4.x returned.
2957 aLastModified
.AssignLiteral(MOZ_UTF16("01/01/1970 00:00:00"));
2962 nsDocument::AddToNameTable(Element
*aElement
, nsIAtom
* aName
)
2964 MOZ_ASSERT(nsGenericHTMLElement::ShouldExposeNameAsHTMLDocumentProperty(aElement
),
2965 "Only put elements that need to be exposed as document['name'] in "
2966 "the named table.");
2968 nsIdentifierMapEntry
*entry
=
2969 mIdentifierMap
.PutEntry(nsDependentAtomString(aName
));
2971 // Null for out-of-memory
2973 if (!entry
->HasNameElement() &&
2974 !entry
->HasIdElementExposedAsHTMLDocumentProperty()) {
2975 ++mExpandoAndGeneration
.generation
;
2977 entry
->AddNameElement(this, aElement
);
2982 nsDocument::RemoveFromNameTable(Element
*aElement
, nsIAtom
* aName
)
2984 // Speed up document teardown
2985 if (mIdentifierMap
.Count() == 0)
2988 nsIdentifierMapEntry
*entry
=
2989 mIdentifierMap
.GetEntry(nsDependentAtomString(aName
));
2990 if (!entry
) // Could be false if the element was anonymous, hence never added
2993 entry
->RemoveNameElement(aElement
);
2994 if (!entry
->HasNameElement() &&
2995 !entry
->HasIdElementExposedAsHTMLDocumentProperty()) {
2996 ++mExpandoAndGeneration
.generation
;
3001 nsDocument::AddToIdTable(Element
*aElement
, nsIAtom
* aId
)
3003 nsIdentifierMapEntry
*entry
=
3004 mIdentifierMap
.PutEntry(nsDependentAtomString(aId
));
3006 if (entry
) { /* True except on OOM */
3007 if (nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(aElement
) &&
3008 !entry
->HasNameElement() &&
3009 !entry
->HasIdElementExposedAsHTMLDocumentProperty()) {
3010 ++mExpandoAndGeneration
.generation
;
3012 entry
->AddIdElement(aElement
);
3017 nsDocument::RemoveFromIdTable(Element
*aElement
, nsIAtom
* aId
)
3019 NS_ASSERTION(aId
, "huhwhatnow?");
3021 // Speed up document teardown
3022 if (mIdentifierMap
.Count() == 0) {
3026 nsIdentifierMapEntry
*entry
=
3027 mIdentifierMap
.GetEntry(nsDependentAtomString(aId
));
3028 if (!entry
) // Can be null for XML elements with changing ids.
3031 entry
->RemoveIdElement(aElement
);
3032 if (nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(aElement
) &&
3033 !entry
->HasNameElement() &&
3034 !entry
->HasIdElementExposedAsHTMLDocumentProperty()) {
3035 ++mExpandoAndGeneration
.generation
;
3037 if (entry
->IsEmpty()) {
3038 mIdentifierMap
.RawRemoveEntry(entry
);
3043 nsDocument::GetPrincipal()
3045 return NodePrincipal();
3048 extern bool sDisablePrefetchHTTPSPref
;
3051 nsDocument::SetPrincipal(nsIPrincipal
*aNewPrincipal
)
3053 if (aNewPrincipal
&& mAllowDNSPrefetch
&& sDisablePrefetchHTTPSPref
) {
3054 nsCOMPtr
<nsIURI
> uri
;
3055 aNewPrincipal
->GetURI(getter_AddRefs(uri
));
3057 if (!uri
|| NS_FAILED(uri
->SchemeIs("https", &isHTTPS
)) ||
3059 mAllowDNSPrefetch
= false;
3062 mNodeInfoManager
->SetDocumentPrincipal(aNewPrincipal
);
3066 nsDocument::GetApplicationCache(nsIApplicationCache
**aApplicationCache
)
3068 NS_IF_ADDREF(*aApplicationCache
= mApplicationCache
);
3074 nsDocument::SetApplicationCache(nsIApplicationCache
*aApplicationCache
)
3076 mApplicationCache
= aApplicationCache
;
3082 nsDocument::GetContentType(nsAString
& aContentType
)
3084 CopyUTF8toUTF16(GetContentTypeInternal(), aContentType
);
3090 nsDocument::SetContentType(const nsAString
& aContentType
)
3092 NS_ASSERTION(GetContentTypeInternal().IsEmpty() ||
3093 GetContentTypeInternal().Equals(NS_ConvertUTF16toUTF8(aContentType
)),
3094 "Do you really want to change the content-type?");
3096 SetContentTypeInternal(NS_ConvertUTF16toUTF8(aContentType
));
3100 nsDocument::GetAllowPlugins(bool * aAllowPlugins
)
3102 // First, we ask our docshell if it allows plugins.
3103 nsCOMPtr
<nsIDocShell
> docShell(mDocumentContainer
);
3106 docShell
->GetAllowPlugins(aAllowPlugins
);
3108 // If the docshell allows plugins, we check whether
3109 // we are sandboxed and plugins should not be allowed.
3111 *aAllowPlugins
= !(mSandboxFlags
& SANDBOXED_PLUGINS
);
3117 already_AddRefed
<UndoManager
>
3118 nsDocument::GetUndoManager()
3120 Element
* rootElement
= GetRootElement();
3125 if (!mUndoManager
) {
3126 mUndoManager
= new UndoManager(rootElement
);
3129 nsRefPtr
<UndoManager
> undoManager
= mUndoManager
;
3130 return undoManager
.forget();
3134 nsDocument::Timeline()
3136 if (!mAnimationTimeline
) {
3137 mAnimationTimeline
= new AnimationTimeline(this);
3140 return mAnimationTimeline
;
3143 /* Return true if the document is in the focused top-level window, and is an
3144 * ancestor of the focused DOMWindow. */
3146 nsDocument::HasFocus(bool* aResult
)
3149 *aResult
= nsIDocument::HasFocus(rv
);
3150 return rv
.ErrorCode();
3154 nsIDocument::HasFocus(ErrorResult
& rv
) const
3156 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
3158 rv
.Throw(NS_ERROR_NOT_AVAILABLE
);
3162 // Is there a focused DOMWindow?
3163 nsCOMPtr
<nsIDOMWindow
> focusedWindow
;
3164 fm
->GetFocusedWindow(getter_AddRefs(focusedWindow
));
3165 if (!focusedWindow
) {
3169 // Are we an ancestor of the focused DOMWindow?
3170 nsCOMPtr
<nsIDOMDocument
> domDocument
;
3171 focusedWindow
->GetDocument(getter_AddRefs(domDocument
));
3172 nsCOMPtr
<nsIDocument
> document
= do_QueryInterface(domDocument
);
3174 for (nsIDocument
* currentDoc
= document
; currentDoc
;
3175 currentDoc
= currentDoc
->GetParentDocument()) {
3176 if (currentDoc
== this) {
3177 // Yes, we are an ancestor
3186 nsDocument::GetReferrer(nsAString
& aReferrer
)
3188 nsIDocument::GetReferrer(aReferrer
);
3193 nsIDocument::GetReferrer(nsAString
& aReferrer
) const
3195 if (mIsSrcdocDocument
&& mParentDocument
)
3196 mParentDocument
->GetReferrer(aReferrer
);
3198 CopyUTF8toUTF16(mReferrer
, aReferrer
);
3202 nsIDocument::GetSrcdocData(nsAString
&aSrcdocData
)
3204 if (mIsSrcdocDocument
) {
3205 nsCOMPtr
<nsIInputStreamChannel
> inStrmChan
= do_QueryInterface(mChannel
);
3207 return inStrmChan
->GetSrcdocData(aSrcdocData
);
3210 aSrcdocData
= NullString();
3215 nsDocument::GetActiveElement(nsIDOMElement
**aElement
)
3217 nsCOMPtr
<nsIDOMElement
> el(do_QueryInterface(nsIDocument::GetActiveElement()));
3218 el
.forget(aElement
);
3223 nsIDocument::GetActiveElement()
3225 // Get the focused element.
3226 nsCOMPtr
<nsPIDOMWindow
> window
= GetWindow();
3228 nsCOMPtr
<nsPIDOMWindow
> focusedWindow
;
3229 nsIContent
* focusedContent
=
3230 nsFocusManager::GetFocusedDescendant(window
, false,
3231 getter_AddRefs(focusedWindow
));
3232 // be safe and make sure the element is from this document
3233 if (focusedContent
&& focusedContent
->OwnerDoc() == this) {
3234 if (focusedContent
->ChromeOnlyAccess()) {
3235 focusedContent
= focusedContent
->FindFirstNonChromeOnlyAccessContent();
3237 if (focusedContent
) {
3238 return focusedContent
->AsElement();
3243 // No focused element anywhere in this document. Try to get the BODY.
3244 nsRefPtr
<nsHTMLDocument
> htmlDoc
= AsHTMLDocument();
3246 // Because of IE compatibility, return null when html document doesn't have
3248 return htmlDoc
->GetBody();
3251 // If we couldn't get a BODY, return the root element.
3252 return GetDocumentElement();
3256 nsDocument::GetCurrentScript(nsIDOMElement
**aElement
)
3258 nsCOMPtr
<nsIDOMElement
> el(do_QueryInterface(nsIDocument::GetCurrentScript()));
3259 el
.forget(aElement
);
3264 nsIDocument::GetCurrentScript()
3266 nsCOMPtr
<Element
> el(do_QueryInterface(ScriptLoader()->GetCurrentScript()));
3271 nsDocument::ElementFromPoint(float aX
, float aY
, nsIDOMElement
** aReturn
)
3273 Element
* el
= nsIDocument::ElementFromPoint(aX
, aY
);
3274 nsCOMPtr
<nsIDOMElement
> retval
= do_QueryInterface(el
);
3275 retval
.forget(aReturn
);
3280 nsIDocument::ElementFromPoint(float aX
, float aY
)
3282 return ElementFromPointHelper(aX
, aY
, false, true);
3286 nsDocument::ElementFromPointHelper(float aX
, float aY
,
3287 bool aIgnoreRootScrollFrame
,
3290 // As per the the spec, we return null if either coord is negative
3291 if (!aIgnoreRootScrollFrame
&& (aX
< 0 || aY
< 0)) {
3295 nscoord x
= nsPresContext::CSSPixelsToAppUnits(aX
);
3296 nscoord y
= nsPresContext::CSSPixelsToAppUnits(aY
);
3299 // Make sure the layout information we get is up-to-date, and
3300 // ensure we get a root frame (for everything but XUL)
3302 FlushPendingNotifications(Flush_Layout
);
3304 nsIPresShell
*ps
= GetShell();
3308 nsIFrame
*rootFrame
= ps
->GetRootFrame();
3310 // XUL docs, unlike HTML, have no frame tree until everything's done loading
3312 return nullptr; // return null to premature XUL callers as a reminder to wait
3315 nsIFrame
*ptFrame
= nsLayoutUtils::GetFrameForPoint(rootFrame
, pt
,
3316 nsLayoutUtils::IGNORE_PAINT_SUPPRESSION
| nsLayoutUtils::IGNORE_CROSS_DOC
|
3317 (aIgnoreRootScrollFrame
? nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME
: 0));
3322 nsIContent
* elem
= GetContentInThisDocument(ptFrame
);
3323 if (elem
&& !elem
->IsElement()) {
3324 elem
= elem
->GetParent();
3326 return elem
? elem
->AsElement() : nullptr;
3330 nsDocument::NodesFromRectHelper(float aX
, float aY
,
3331 float aTopSize
, float aRightSize
,
3332 float aBottomSize
, float aLeftSize
,
3333 bool aIgnoreRootScrollFrame
,
3335 nsIDOMNodeList
** aReturn
)
3337 NS_ENSURE_ARG_POINTER(aReturn
);
3339 nsSimpleContentList
* elements
= new nsSimpleContentList(this);
3340 NS_ADDREF(elements
);
3341 *aReturn
= elements
;
3343 // Following the same behavior of elementFromPoint,
3344 // we don't return anything if either coord is negative
3345 if (!aIgnoreRootScrollFrame
&& (aX
< 0 || aY
< 0))
3348 nscoord x
= nsPresContext::CSSPixelsToAppUnits(aX
- aLeftSize
);
3349 nscoord y
= nsPresContext::CSSPixelsToAppUnits(aY
- aTopSize
);
3350 nscoord w
= nsPresContext::CSSPixelsToAppUnits(aLeftSize
+ aRightSize
) + 1;
3351 nscoord h
= nsPresContext::CSSPixelsToAppUnits(aTopSize
+ aBottomSize
) + 1;
3353 nsRect
rect(x
, y
, w
, h
);
3355 // Make sure the layout information we get is up-to-date, and
3356 // ensure we get a root frame (for everything but XUL)
3358 FlushPendingNotifications(Flush_Layout
);
3361 nsIPresShell
*ps
= GetShell();
3362 NS_ENSURE_STATE(ps
);
3363 nsIFrame
*rootFrame
= ps
->GetRootFrame();
3365 // XUL docs, unlike HTML, have no frame tree until everything's done loading
3367 return NS_OK
; // return nothing to premature XUL callers as a reminder to wait
3369 nsAutoTArray
<nsIFrame
*,8> outFrames
;
3370 nsLayoutUtils::GetFramesForArea(rootFrame
, rect
, outFrames
,
3371 nsLayoutUtils::IGNORE_PAINT_SUPPRESSION
| nsLayoutUtils::IGNORE_CROSS_DOC
|
3372 (aIgnoreRootScrollFrame
? nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME
: 0));
3374 // Used to filter out repeated elements in sequence.
3375 nsIContent
* lastAdded
= nullptr;
3377 for (uint32_t i
= 0; i
< outFrames
.Length(); i
++) {
3378 nsIContent
* node
= GetContentInThisDocument(outFrames
[i
]);
3380 if (node
&& !node
->IsElement() && !node
->IsNodeOfType(nsINode::eTEXT
)) {
3381 // We have a node that isn't an element or a text node,
3382 // use its parent content instead.
3383 node
= node
->GetParent();
3385 if (node
&& node
!= lastAdded
) {
3386 elements
->AppendElement(node
);
3395 nsDocument::GetElementsByClassName(const nsAString
& aClasses
,
3396 nsIDOMNodeList
** aReturn
)
3398 *aReturn
= nsIDocument::GetElementsByClassName(aClasses
).take();
3402 already_AddRefed
<nsContentList
>
3403 nsIDocument::GetElementsByClassName(const nsAString
& aClasses
)
3405 return nsContentUtils::GetElementsByClassName(this, aClasses
);
3409 nsDocument::ReleaseCapture()
3411 nsIDocument::ReleaseCapture();
3416 nsIDocument::ReleaseCapture() const
3418 // only release the capture if the caller can access it. This prevents a
3419 // page from stopping a scrollbar grab for example.
3420 nsCOMPtr
<nsINode
> node
= nsIPresShell::GetCapturingContent();
3421 if (node
&& nsContentUtils::CanCallerAccess(node
)) {
3422 nsIPresShell::SetCapturingContent(nullptr, 0);
3426 already_AddRefed
<nsIURI
>
3427 nsIDocument::GetBaseURI(bool aTryUseXHRDocBaseURI
) const
3429 nsCOMPtr
<nsIURI
> uri
;
3430 if (aTryUseXHRDocBaseURI
&& mChromeXHRDocBaseURI
) {
3431 uri
= mChromeXHRDocBaseURI
;
3433 uri
= GetDocBaseURI();
3436 return uri
.forget();
3440 nsDocument::SetBaseURI(nsIURI
* aURI
)
3442 if (!aURI
&& !mDocumentBaseURI
) {
3446 // Don't do anything if the URI wasn't actually changed.
3447 if (aURI
&& mDocumentBaseURI
) {
3448 bool equalBases
= false;
3449 mDocumentBaseURI
->Equals(aURI
, &equalBases
);
3456 mDocumentBaseURI
= NS_TryToMakeImmutable(aURI
);
3458 mDocumentBaseURI
= nullptr;
3466 nsDocument::GetBaseTarget(nsAString
&aBaseTarget
)
3468 aBaseTarget
= mBaseTarget
;
3472 nsDocument::SetDocumentCharacterSet(const nsACString
& aCharSetID
)
3474 // XXX it would be a good idea to assert the sanity of the argument,
3475 // but before we figure out what to do about non-Encoding Standard
3476 // encodings in the charset menu and in mailnews, assertions are futile.
3477 if (!mCharacterSet
.Equals(aCharSetID
)) {
3478 mCharacterSet
= aCharSetID
;
3480 int32_t n
= mCharSetObservers
.Length();
3482 for (int32_t i
= 0; i
< n
; i
++) {
3483 nsIObserver
* observer
= mCharSetObservers
.ElementAt(i
);
3485 observer
->Observe(static_cast<nsIDocument
*>(this), "charset",
3486 NS_ConvertASCIItoUTF16(aCharSetID
).get());
3492 nsDocument::AddCharSetObserver(nsIObserver
* aObserver
)
3494 NS_ENSURE_ARG_POINTER(aObserver
);
3496 NS_ENSURE_TRUE(mCharSetObservers
.AppendElement(aObserver
), NS_ERROR_FAILURE
);
3502 nsDocument::RemoveCharSetObserver(nsIObserver
* aObserver
)
3504 mCharSetObservers
.RemoveElement(aObserver
);
3508 nsDocument::GetHeaderData(nsIAtom
* aHeaderField
, nsAString
& aData
) const
3511 const nsDocHeaderData
* data
= mHeaderData
;
3513 if (data
->mField
== aHeaderField
) {
3514 aData
= data
->mData
;
3523 nsDocument::SetHeaderData(nsIAtom
* aHeaderField
, const nsAString
& aData
)
3525 if (!aHeaderField
) {
3526 NS_ERROR("null headerField");
3531 if (!aData
.IsEmpty()) { // don't bother storing empty string
3532 mHeaderData
= new nsDocHeaderData(aHeaderField
, aData
);
3536 nsDocHeaderData
* data
= mHeaderData
;
3537 nsDocHeaderData
** lastPtr
= &mHeaderData
;
3539 do { // look for existing and replace
3540 if (data
->mField
== aHeaderField
) {
3541 if (!aData
.IsEmpty()) {
3542 data
->mData
.Assign(aData
);
3544 else { // don't store empty string
3545 *lastPtr
= data
->mNext
;
3546 data
->mNext
= nullptr;
3553 lastPtr
= &(data
->mNext
);
3557 if (!aData
.IsEmpty() && !found
) {
3558 // didn't find, append
3559 *lastPtr
= new nsDocHeaderData(aHeaderField
, aData
);
3563 if (aHeaderField
== nsGkAtoms::headerContentLanguage
) {
3564 CopyUTF16toUTF8(aData
, mContentLanguage
);
3567 if (aHeaderField
== nsGkAtoms::headerDefaultStyle
) {
3568 // Only mess with our stylesheets if we don't have a lastStyleSheetSet, per
3570 if (DOMStringIsNull(mLastStyleSheetSet
)) {
3571 // Calling EnableStyleSheetsForSetInternal, not SetSelectedStyleSheetSet,
3572 // per spec. The idea here is that we're changing our preferred set and
3573 // that shouldn't change the value of lastStyleSheetSet. Also, we're
3574 // using the Internal version so we can update the CSSLoader and not have
3575 // to worry about null strings.
3576 EnableStyleSheetsForSetInternal(aData
, true);
3580 if (aHeaderField
== nsGkAtoms::refresh
) {
3581 // We get into this code before we have a script global yet, so get to
3582 // our container via mDocumentContainer.
3583 nsCOMPtr
<nsIRefreshURI
> refresher(mDocumentContainer
);
3585 // Note: using mDocumentURI instead of mBaseURI here, for consistency
3586 // (used to just use the current URI of our webnavigation, but that
3587 // should really be the same thing). Note that this code can run
3588 // before the current URI of the webnavigation has been updated, so we
3589 // can't assert equality here.
3590 refresher
->SetupRefreshURIFromHeader(mDocumentURI
, NodePrincipal(),
3591 NS_ConvertUTF16toUTF8(aData
));
3595 if (aHeaderField
== nsGkAtoms::headerDNSPrefetchControl
&&
3596 mAllowDNSPrefetch
) {
3597 // Chromium treats any value other than 'on' (case insensitive) as 'off'.
3598 mAllowDNSPrefetch
= aData
.IsEmpty() || aData
.LowerCaseEqualsLiteral("on");
3601 if (aHeaderField
== nsGkAtoms::viewport
||
3602 aHeaderField
== nsGkAtoms::handheldFriendly
||
3603 aHeaderField
== nsGkAtoms::viewport_minimum_scale
||
3604 aHeaderField
== nsGkAtoms::viewport_maximum_scale
||
3605 aHeaderField
== nsGkAtoms::viewport_initial_scale
||
3606 aHeaderField
== nsGkAtoms::viewport_height
||
3607 aHeaderField
== nsGkAtoms::viewport_width
||
3608 aHeaderField
== nsGkAtoms::viewport_user_scalable
) {
3609 mViewportType
= Unknown
;
3614 nsDocument::TryChannelCharset(nsIChannel
*aChannel
,
3615 int32_t& aCharsetSource
,
3616 nsACString
& aCharset
,
3617 nsHtml5TreeOpExecutor
* aExecutor
)
3620 nsAutoCString charsetVal
;
3621 nsresult rv
= aChannel
->GetContentCharset(charsetVal
);
3622 if (NS_SUCCEEDED(rv
)) {
3623 nsAutoCString preferred
;
3624 if(EncodingUtils::FindEncodingForLabel(charsetVal
, preferred
)) {
3625 aCharset
= preferred
;
3626 aCharsetSource
= kCharsetFromChannel
;
3628 } else if (aExecutor
&& !charsetVal
.IsEmpty()) {
3629 aExecutor
->ComplainAboutBogusProtocolCharset(this);
3635 already_AddRefed
<nsIPresShell
>
3636 nsDocument::CreateShell(nsPresContext
* aContext
, nsViewManager
* aViewManager
,
3637 nsStyleSet
* aStyleSet
)
3639 // Don't add anything here. Add it to |doCreateShell| instead.
3640 // This exists so that subclasses can pass other values for the 4th
3641 // parameter some of the time.
3642 return doCreateShell(aContext
, aViewManager
, aStyleSet
,
3643 eCompatibility_FullStandards
);
3646 already_AddRefed
<nsIPresShell
>
3647 nsDocument::doCreateShell(nsPresContext
* aContext
,
3648 nsViewManager
* aViewManager
, nsStyleSet
* aStyleSet
,
3649 nsCompatibility aCompatMode
)
3651 NS_ASSERTION(!mPresShell
, "We have a presshell already!");
3653 NS_ENSURE_FALSE(GetBFCacheEntry(), nullptr);
3655 FillStyleSet(aStyleSet
);
3657 nsRefPtr
<PresShell
> shell
= new PresShell
;
3658 shell
->Init(this, aContext
, aViewManager
, aStyleSet
, aCompatMode
);
3660 // Note: we don't hold a ref to the shell (it holds a ref to us)
3663 // Make sure to never paint if we belong to an invisible DocShell.
3664 nsCOMPtr
<nsIDocShell
> docShell(mDocumentContainer
);
3665 if (docShell
&& docShell
->IsInvisible())
3666 shell
->SetNeverPainting(true);
3668 mExternalResourceMap
.ShowViewers();
3670 MaybeRescheduleAnimationFrameNotifications();
3672 return shell
.forget();
3676 nsDocument::MaybeRescheduleAnimationFrameNotifications()
3678 if (!mPresShell
|| !IsEventHandlingEnabled()) {
3679 // bail out for now, until one of those conditions changes
3683 nsRefreshDriver
* rd
= mPresShell
->GetPresContext()->RefreshDriver();
3684 if (!mFrameRequestCallbacks
.IsEmpty()) {
3685 rd
->ScheduleFrameRequestCallbacks(this);
3690 nsIDocument::TakeFrameRequestCallbacks(FrameRequestCallbackList
& aCallbacks
)
3692 aCallbacks
.AppendElements(mFrameRequestCallbacks
);
3693 mFrameRequestCallbacks
.Clear();
3696 PLDHashOperator
RequestDiscardEnumerator(imgIRequest
* aKey
,
3700 aKey
->RequestDiscard();
3701 return PL_DHASH_NEXT
;
3705 nsDocument::DeleteShell()
3707 mExternalResourceMap
.HideViewers();
3708 if (IsEventHandlingEnabled()) {
3709 RevokeAnimationFrameNotifications();
3712 // When our shell goes away, request that all our images be immediately
3713 // discarded, so we don't carry around decoded image data for a document we
3714 // no longer intend to paint.
3715 mImageTracker
.EnumerateRead(RequestDiscardEnumerator
, nullptr);
3717 mPresShell
= nullptr;
3721 nsDocument::RevokeAnimationFrameNotifications()
3723 if (!mFrameRequestCallbacks
.IsEmpty()) {
3724 mPresShell
->GetPresContext()->RefreshDriver()->
3725 RevokeFrameRequestCallbacks(this);
3730 SubDocClearEntry(PLDHashTable
*table
, PLDHashEntryHdr
*entry
)
3732 SubDocMapEntry
*e
= static_cast<SubDocMapEntry
*>(entry
);
3734 NS_RELEASE(e
->mKey
);
3735 if (e
->mSubDocument
) {
3736 e
->mSubDocument
->SetParentDocument(nullptr);
3737 NS_RELEASE(e
->mSubDocument
);
3742 SubDocInitEntry(PLDHashTable
*table
, PLDHashEntryHdr
*entry
, const void *key
)
3745 const_cast<SubDocMapEntry
*>
3746 (static_cast<const SubDocMapEntry
*>(entry
));
3748 e
->mKey
= const_cast<Element
*>(static_cast<const Element
*>(key
));
3751 e
->mSubDocument
= nullptr;
3756 nsDocument::SetSubDocumentFor(Element
* aElement
, nsIDocument
* aSubDoc
)
3758 NS_ENSURE_TRUE(aElement
, NS_ERROR_UNEXPECTED
);
3761 // aSubDoc is nullptr, remove the mapping
3763 if (mSubDocuments
) {
3764 SubDocMapEntry
*entry
=
3765 static_cast<SubDocMapEntry
*>
3766 (PL_DHashTableOperate(mSubDocuments
, aElement
,
3769 if (PL_DHASH_ENTRY_IS_BUSY(entry
)) {
3770 PL_DHashTableRawRemove(mSubDocuments
, entry
);
3774 if (!mSubDocuments
) {
3775 // Create a new hashtable
3777 static const PLDHashTableOps hash_table_ops
=
3781 PL_DHashVoidPtrKeyStub
,
3782 PL_DHashMatchEntryStub
,
3783 PL_DHashMoveEntryStub
,
3785 PL_DHashFinalizeStub
,
3789 mSubDocuments
= PL_NewDHashTable(&hash_table_ops
, nullptr,
3790 sizeof(SubDocMapEntry
));
3791 if (!mSubDocuments
) {
3792 return NS_ERROR_OUT_OF_MEMORY
;
3796 // Add a mapping to the hash table
3797 SubDocMapEntry
*entry
=
3798 static_cast<SubDocMapEntry
*>
3799 (PL_DHashTableOperate(mSubDocuments
, aElement
,
3803 return NS_ERROR_OUT_OF_MEMORY
;
3806 if (entry
->mSubDocument
) {
3807 entry
->mSubDocument
->SetParentDocument(nullptr);
3809 // Release the old sub document
3810 NS_RELEASE(entry
->mSubDocument
);
3813 entry
->mSubDocument
= aSubDoc
;
3814 NS_ADDREF(entry
->mSubDocument
);
3816 aSubDoc
->SetParentDocument(this);
3823 nsDocument::GetSubDocumentFor(nsIContent
*aContent
) const
3825 if (mSubDocuments
&& aContent
->IsElement()) {
3826 SubDocMapEntry
*entry
=
3827 static_cast<SubDocMapEntry
*>
3828 (PL_DHashTableOperate(mSubDocuments
, aContent
->AsElement(),
3831 if (PL_DHASH_ENTRY_IS_BUSY(entry
)) {
3832 return entry
->mSubDocument
;
3839 static PLDHashOperator
3840 FindContentEnumerator(PLDHashTable
*table
, PLDHashEntryHdr
*hdr
,
3841 uint32_t number
, void *arg
)
3843 SubDocMapEntry
*entry
= static_cast<SubDocMapEntry
*>(hdr
);
3844 FindContentData
*data
= static_cast<FindContentData
*>(arg
);
3846 if (entry
->mSubDocument
== data
->mSubDocument
) {
3847 data
->mResult
= entry
->mKey
;
3849 return PL_DHASH_STOP
;
3852 return PL_DHASH_NEXT
;
3856 nsDocument::FindContentForSubDocument(nsIDocument
*aDocument
) const
3858 NS_ENSURE_TRUE(aDocument
, nullptr);
3860 if (!mSubDocuments
) {
3864 FindContentData
data(aDocument
);
3865 PL_DHashTableEnumerate(mSubDocuments
, FindContentEnumerator
, &data
);
3867 return data
.mResult
;
3871 nsDocument::IsNodeOfType(uint32_t aFlags
) const
3873 return !(aFlags
& ~eDOCUMENT
);
3877 nsIDocument::GetRootElement() const
3879 return (mCachedRootElement
&& mCachedRootElement
->GetParentNode() == this) ?
3880 mCachedRootElement
: GetRootElementInternal();
3884 nsDocument::GetRootElementInternal() const
3886 // Loop backwards because any non-elements, such as doctypes and PIs
3887 // are likely to appear before the root element.
3889 for (i
= mChildren
.ChildCount(); i
> 0; --i
) {
3890 nsIContent
* child
= mChildren
.ChildAt(i
- 1);
3891 if (child
->IsElement()) {
3892 const_cast<nsDocument
*>(this)->mCachedRootElement
= child
->AsElement();
3893 return child
->AsElement();
3897 const_cast<nsDocument
*>(this)->mCachedRootElement
= nullptr;
3902 nsDocument::GetChildAt(uint32_t aIndex
) const
3904 return mChildren
.GetSafeChildAt(aIndex
);
3908 nsDocument::IndexOf(const nsINode
* aPossibleChild
) const
3910 return mChildren
.IndexOfChild(aPossibleChild
);
3914 nsDocument::GetChildCount() const
3916 return mChildren
.ChildCount();
3919 nsIContent
* const *
3920 nsDocument::GetChildArray(uint32_t* aChildCount
) const
3922 return mChildren
.GetChildArray(aChildCount
);
3927 nsDocument::InsertChildAt(nsIContent
* aKid
, uint32_t aIndex
,
3930 if (aKid
->IsElement() && GetRootElement()) {
3931 NS_WARNING("Inserting root element when we already have one");
3932 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
;
3935 return doInsertChildAt(aKid
, aIndex
, aNotify
, mChildren
);
3939 nsDocument::RemoveChildAt(uint32_t aIndex
, bool aNotify
)
3941 nsCOMPtr
<nsIContent
> oldKid
= GetChildAt(aIndex
);
3946 if (oldKid
->IsElement()) {
3947 // Destroy the link map up front before we mess with the child list.
3948 DestroyElementMaps();
3951 doRemoveChildAt(aIndex
, aNotify
, oldKid
, mChildren
);
3952 mCachedRootElement
= nullptr;
3956 nsDocument::EnsureOnDemandBuiltInUASheet(CSSStyleSheet
* aSheet
)
3958 // Contains() takes nsISupport*, so annoyingly we have to cast here
3959 if (mOnDemandBuiltInUASheets
.Contains(static_cast<nsIStyleSheet
*>(aSheet
))) {
3962 BeginUpdate(UPDATE_STYLE
);
3963 AddOnDemandBuiltInUASheet(aSheet
);
3964 EndUpdate(UPDATE_STYLE
);
3968 nsDocument::AddOnDemandBuiltInUASheet(CSSStyleSheet
* aSheet
)
3970 // Contains() takes nsISupport*, so annoyingly we have to cast here
3971 MOZ_ASSERT(!mOnDemandBuiltInUASheets
.Contains(static_cast<nsIStyleSheet
*>(aSheet
)));
3973 // Prepend here so that we store the sheets in mOnDemandBuiltInUASheets in
3974 // the same order that they should end up in the style set.
3975 mOnDemandBuiltInUASheets
.InsertElementAt(0, aSheet
);
3977 if (aSheet
->IsApplicable()) {
3978 // This is like |AddStyleSheetToStyleSets|, but for an agent sheet.
3979 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
3981 // Note that prepending here is necessary to make sure that html.css etc.
3982 // do not override Firefox OS/Mobile's content.css sheet. Maybe we should
3983 // have an insertion point to match the order of
3984 // nsDocumentViewer::CreateStyleSet though?
3985 shell
->StyleSet()->PrependStyleSheet(nsStyleSet::eAgentSheet
, aSheet
);
3989 NotifyStyleSheetAdded(aSheet
, false);
3993 nsDocument::GetNumberOfStyleSheets() const
3995 return mStyleSheets
.Count();
3999 nsDocument::GetStyleSheetAt(int32_t aIndex
) const
4001 NS_ENSURE_TRUE(0 <= aIndex
&& aIndex
< mStyleSheets
.Count(), nullptr);
4002 return mStyleSheets
[aIndex
];
4006 nsDocument::GetIndexOfStyleSheet(nsIStyleSheet
* aSheet
) const
4008 return mStyleSheets
.IndexOf(aSheet
);
4012 nsDocument::AddStyleSheetToStyleSets(nsIStyleSheet
* aSheet
)
4014 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
4016 shell
->StyleSet()->AddDocStyleSheet(aSheet
, this);
4020 #define DO_STYLESHEET_NOTIFICATION(className, type, memberName, argName) \
4022 nsRefPtr<CSSStyleSheet> cssSheet = do_QueryObject(aSheet); \
4027 className##Init init; \
4028 init.mBubbles = true; \
4029 init.mCancelable = true; \
4030 init.mStylesheet = cssSheet; \
4031 init.memberName = argName; \
4033 nsRefPtr<className> event = \
4034 className::Constructor(this, NS_LITERAL_STRING(type), init); \
4035 event->SetTrusted(true); \
4036 event->SetTarget(this); \
4037 nsRefPtr<AsyncEventDispatcher> asyncDispatcher = \
4038 new AsyncEventDispatcher(this, event); \
4039 asyncDispatcher->mDispatchChromeOnly = true; \
4040 asyncDispatcher->PostDOMEvent(); \
4044 nsDocument::NotifyStyleSheetAdded(nsIStyleSheet
* aSheet
, bool aDocumentSheet
)
4046 NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded
, (this, aSheet
, aDocumentSheet
));
4048 if (StyleSheetChangeEventsEnabled()) {
4049 DO_STYLESHEET_NOTIFICATION(StyleSheetChangeEvent
,
4057 nsDocument::NotifyStyleSheetRemoved(nsIStyleSheet
* aSheet
, bool aDocumentSheet
)
4059 NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetRemoved
, (this, aSheet
, aDocumentSheet
));
4061 if (StyleSheetChangeEventsEnabled()) {
4062 DO_STYLESHEET_NOTIFICATION(StyleSheetChangeEvent
,
4063 "StyleSheetRemoved",
4070 nsDocument::AddStyleSheet(nsIStyleSheet
* aSheet
)
4072 NS_PRECONDITION(aSheet
, "null arg");
4073 mStyleSheets
.AppendObject(aSheet
);
4074 aSheet
->SetOwningDocument(this);
4076 if (aSheet
->IsApplicable()) {
4077 AddStyleSheetToStyleSets(aSheet
);
4080 NotifyStyleSheetAdded(aSheet
, true);
4084 nsDocument::RemoveStyleSheetFromStyleSets(nsIStyleSheet
* aSheet
)
4086 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
4088 shell
->StyleSet()->RemoveDocStyleSheet(aSheet
);
4093 nsDocument::RemoveStyleSheet(nsIStyleSheet
* aSheet
)
4095 NS_PRECONDITION(aSheet
, "null arg");
4096 nsCOMPtr
<nsIStyleSheet
> sheet
= aSheet
; // hold ref so it won't die too soon
4098 if (!mStyleSheets
.RemoveObject(aSheet
)) {
4099 NS_ASSERTION(mInUnlinkOrDeletion
, "stylesheet not found");
4103 if (!mIsGoingAway
) {
4104 if (aSheet
->IsApplicable()) {
4105 RemoveStyleSheetFromStyleSets(aSheet
);
4108 NotifyStyleSheetRemoved(aSheet
, true);
4111 aSheet
->SetOwningDocument(nullptr);
4115 nsDocument::UpdateStyleSheets(nsCOMArray
<nsIStyleSheet
>& aOldSheets
,
4116 nsCOMArray
<nsIStyleSheet
>& aNewSheets
)
4118 BeginUpdate(UPDATE_STYLE
);
4120 // XXX Need to set the sheet on the ownernode, if any
4121 NS_PRECONDITION(aOldSheets
.Count() == aNewSheets
.Count(),
4122 "The lists must be the same length!");
4123 int32_t count
= aOldSheets
.Count();
4125 nsCOMPtr
<nsIStyleSheet
> oldSheet
;
4127 for (i
= 0; i
< count
; ++i
) {
4128 oldSheet
= aOldSheets
[i
];
4130 // First remove the old sheet.
4131 NS_ASSERTION(oldSheet
, "None of the old sheets should be null");
4132 int32_t oldIndex
= mStyleSheets
.IndexOf(oldSheet
);
4133 RemoveStyleSheet(oldSheet
); // This does the right notifications
4135 // Now put the new one in its place. If it's null, just ignore it.
4136 nsIStyleSheet
* newSheet
= aNewSheets
[i
];
4138 mStyleSheets
.InsertObjectAt(newSheet
, oldIndex
);
4139 newSheet
->SetOwningDocument(this);
4140 if (newSheet
->IsApplicable()) {
4141 AddStyleSheetToStyleSets(newSheet
);
4144 NotifyStyleSheetAdded(newSheet
, true);
4148 EndUpdate(UPDATE_STYLE
);
4152 nsDocument::InsertStyleSheetAt(nsIStyleSheet
* aSheet
, int32_t aIndex
)
4154 NS_PRECONDITION(aSheet
, "null ptr");
4155 mStyleSheets
.InsertObjectAt(aSheet
, aIndex
);
4157 aSheet
->SetOwningDocument(this);
4159 if (aSheet
->IsApplicable()) {
4160 AddStyleSheetToStyleSets(aSheet
);
4163 NotifyStyleSheetAdded(aSheet
, true);
4168 nsDocument::SetStyleSheetApplicableState(nsIStyleSheet
* aSheet
,
4171 NS_PRECONDITION(aSheet
, "null arg");
4173 // If we're actually in the document style sheet list
4174 if (-1 != mStyleSheets
.IndexOf(aSheet
)) {
4176 AddStyleSheetToStyleSets(aSheet
);
4178 RemoveStyleSheetFromStyleSets(aSheet
);
4182 // We have to always notify, since this will be called for sheets
4183 // that are children of sheets in our style set, as well as some
4184 // sheets for nsHTMLEditor.
4186 NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetApplicableStateChanged
,
4187 (this, aSheet
, aApplicable
));
4189 if (StyleSheetChangeEventsEnabled()) {
4190 DO_STYLESHEET_NOTIFICATION(StyleSheetApplicableStateChangeEvent
,
4191 "StyleSheetApplicableStateChanged",
4196 if (!mSSApplicableStateNotificationPending
) {
4197 nsRefPtr
<nsIRunnable
> notification
= NS_NewRunnableMethod(this,
4198 &nsDocument::NotifyStyleSheetApplicableStateChanged
);
4199 mSSApplicableStateNotificationPending
=
4200 NS_SUCCEEDED(NS_DispatchToCurrentThread(notification
));
4205 nsDocument::NotifyStyleSheetApplicableStateChanged()
4207 mSSApplicableStateNotificationPending
= false;
4208 nsCOMPtr
<nsIObserverService
> observerService
=
4209 mozilla::services::GetObserverService();
4210 if (observerService
) {
4211 observerService
->NotifyObservers(static_cast<nsIDocument
*>(this),
4212 "style-sheet-applicable-state-changed",
4217 static nsStyleSet::sheetType
4218 ConvertAdditionalSheetType(nsIDocument::additionalSheetType aType
)
4221 case nsIDocument::eAgentSheet
:
4222 return nsStyleSet::eAgentSheet
;
4223 case nsIDocument::eUserSheet
:
4224 return nsStyleSet::eUserSheet
;
4225 case nsIDocument::eAuthorSheet
:
4226 return nsStyleSet::eDocSheet
;
4228 NS_ASSERTION(false, "wrong type");
4229 // we must return something although this should never happen
4230 return nsStyleSet::eSheetTypeCount
;
4235 FindSheet(const nsCOMArray
<nsIStyleSheet
>& aSheets
, nsIURI
* aSheetURI
)
4237 for (int32_t i
= aSheets
.Count() - 1; i
>= 0; i
-- ) {
4239 nsIURI
* uri
= aSheets
[i
]->GetSheetURI();
4241 if (uri
&& NS_SUCCEEDED(uri
->Equals(aSheetURI
, &bEqual
)) && bEqual
)
4249 nsDocument::LoadAdditionalStyleSheet(additionalSheetType aType
, nsIURI
* aSheetURI
)
4251 NS_PRECONDITION(aSheetURI
, "null arg");
4253 // Checking if we have loaded this one already.
4254 if (FindSheet(mAdditionalSheets
[aType
], aSheetURI
) >= 0)
4255 return NS_ERROR_INVALID_ARG
;
4257 // Loading the sheet sync.
4258 nsRefPtr
<mozilla::css::Loader
> loader
= new mozilla::css::Loader();
4260 nsRefPtr
<CSSStyleSheet
> sheet
;
4261 nsresult rv
= loader
->LoadSheetSync(aSheetURI
, aType
== eAgentSheet
,
4262 true, getter_AddRefs(sheet
));
4263 NS_ENSURE_SUCCESS(rv
, rv
);
4265 sheet
->SetOwningDocument(this);
4266 MOZ_ASSERT(sheet
->IsApplicable());
4268 return AddAdditionalStyleSheet(aType
, sheet
);
4272 nsDocument::AddAdditionalStyleSheet(additionalSheetType aType
, nsIStyleSheet
* aSheet
)
4274 if (mAdditionalSheets
[aType
].Contains(aSheet
))
4275 return NS_ERROR_INVALID_ARG
;
4277 if (!aSheet
->IsApplicable())
4278 return NS_ERROR_INVALID_ARG
;
4280 mAdditionalSheets
[aType
].AppendObject(aSheet
);
4282 BeginUpdate(UPDATE_STYLE
);
4283 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
4285 nsStyleSet::sheetType type
= ConvertAdditionalSheetType(aType
);
4286 shell
->StyleSet()->AppendStyleSheet(type
, aSheet
);
4289 // Passing false, so documet.styleSheets.length will not be affected by
4290 // these additional sheets.
4291 NotifyStyleSheetAdded(aSheet
, false);
4292 EndUpdate(UPDATE_STYLE
);
4297 nsDocument::RemoveAdditionalStyleSheet(additionalSheetType aType
, nsIURI
* aSheetURI
)
4299 MOZ_ASSERT(aSheetURI
);
4301 nsCOMArray
<nsIStyleSheet
>& sheets
= mAdditionalSheets
[aType
];
4303 int32_t i
= FindSheet(mAdditionalSheets
[aType
], aSheetURI
);
4305 nsCOMPtr
<nsIStyleSheet
> sheetRef
= sheets
[i
];
4306 sheets
.RemoveObjectAt(i
);
4308 BeginUpdate(UPDATE_STYLE
);
4309 if (!mIsGoingAway
) {
4310 MOZ_ASSERT(sheetRef
->IsApplicable());
4311 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
4313 nsStyleSet::sheetType type
= ConvertAdditionalSheetType(aType
);
4314 shell
->StyleSet()->RemoveStyleSheet(type
, sheetRef
);
4318 // Passing false, so documet.styleSheets.length will not be affected by
4319 // these additional sheets.
4320 NotifyStyleSheetRemoved(sheetRef
, false);
4321 EndUpdate(UPDATE_STYLE
);
4323 sheetRef
->SetOwningDocument(nullptr);
4328 nsDocument::FirstAdditionalAuthorSheet()
4330 return mAdditionalSheets
[eAuthorSheet
].SafeObjectAt(0);
4334 nsDocument::GetScopeObject() const
4336 nsCOMPtr
<nsIGlobalObject
> scope(do_QueryReferent(mScopeObject
));
4341 nsDocument::SetScopeObject(nsIGlobalObject
* aGlobal
)
4343 mScopeObject
= do_GetWeakReference(aGlobal
);
4345 mHasHadScriptHandlingObject
= true;
4351 CheckIfContainsEMEContent(nsISupports
* aSupports
, void* aContainsEME
)
4353 nsCOMPtr
<nsIDOMHTMLMediaElement
> domMediaElem(do_QueryInterface(aSupports
));
4355 nsCOMPtr
<nsIContent
> content(do_QueryInterface(domMediaElem
));
4356 MOZ_ASSERT(content
, "aSupports is not a content");
4357 HTMLMediaElement
* mediaElem
= static_cast<HTMLMediaElement
*>(content
.get());
4358 bool* contains
= static_cast<bool*>(aContainsEME
);
4359 if (mediaElem
->GetMediaKeys()) {
4366 nsDocument::ContainsEMEContent()
4368 bool containsEME
= false;
4369 EnumerateActivityObservers(CheckIfContainsEMEContent
,
4370 static_cast<void*>(&containsEME
));
4376 NotifyActivityChanged(nsISupports
*aSupports
, void *aUnused
)
4378 nsCOMPtr
<nsIDOMHTMLMediaElement
> domMediaElem(do_QueryInterface(aSupports
));
4380 nsCOMPtr
<nsIContent
> content(do_QueryInterface(domMediaElem
));
4381 MOZ_ASSERT(content
, "aSupports is not a content");
4382 HTMLMediaElement
* mediaElem
= static_cast<HTMLMediaElement
*>(content
.get());
4383 mediaElem
->NotifyOwnerDocumentActivityChanged();
4385 nsCOMPtr
<nsIObjectLoadingContent
> objectLoadingContent(do_QueryInterface(aSupports
));
4386 if (objectLoadingContent
) {
4387 nsObjectLoadingContent
* olc
= static_cast<nsObjectLoadingContent
*>(objectLoadingContent
.get());
4388 olc
->NotifyOwnerDocumentActivityChanged();
4390 nsCOMPtr
<nsIDocumentActivity
> objectDocumentActivity(do_QueryInterface(aSupports
));
4391 if (objectDocumentActivity
) {
4392 objectDocumentActivity
->NotifyOwnerDocumentActivityChanged();
4397 nsIDocument::SetContainer(nsDocShell
* aContainer
)
4400 mDocumentContainer
= aContainer
;
4402 mDocumentContainer
= WeakPtr
<nsDocShell
>();
4405 EnumerateActivityObservers(NotifyActivityChanged
, nullptr);
4411 if (aContainer
->ItemType() == nsIDocShellTreeItem::typeContent
) {
4412 // check if same type root
4413 nsCOMPtr
<nsIDocShellTreeItem
> sameTypeRoot
;
4414 aContainer
->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot
));
4415 NS_ASSERTION(sameTypeRoot
, "No document shell root tree item from document shell tree item!");
4417 if (sameTypeRoot
== aContainer
) {
4418 static_cast<nsDocument
*>(this)->SetIsTopLevelContentDocument(true);
4424 nsIDocument::GetContainer() const
4426 return static_cast<nsIDocShell
*>(mDocumentContainer
);
4430 nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject
*aScriptGlobalObject
)
4434 nsCOMPtr
<nsPIDOMWindow
> win(do_QueryInterface(aScriptGlobalObject
));
4436 NS_ASSERTION(!win
|| win
->IsInnerWindow(),
4437 "Script global object must be an inner window!");
4440 NS_ABORT_IF_FALSE(aScriptGlobalObject
|| !mAnimationController
||
4441 mAnimationController
->IsPausedByType(
4442 nsSMILTimeContainer::PAUSE_PAGEHIDE
|
4443 nsSMILTimeContainer::PAUSE_BEGIN
),
4444 "Clearing window pointer while animations are unpaused");
4446 if (mScriptGlobalObject
&& !aScriptGlobalObject
) {
4447 // We're detaching from the window. We need to grab a pointer to
4448 // our layout history state now.
4449 mLayoutHistoryState
= GetLayoutHistoryState();
4451 if (mPresShell
&& !EventHandlingSuppressed()) {
4452 RevokeAnimationFrameNotifications();
4455 // Also make sure to remove our onload blocker now if we haven't done it yet
4456 if (mOnloadBlockCount
!= 0) {
4457 nsCOMPtr
<nsILoadGroup
> loadGroup
= GetDocumentLoadGroup();
4459 loadGroup
->RemoveRequest(mOnloadBlocker
, nullptr, NS_OK
);
4464 mScriptGlobalObject
= aScriptGlobalObject
;
4466 if (aScriptGlobalObject
) {
4467 mHasHadScriptHandlingObject
= true;
4468 mHasHadDefaultView
= true;
4469 // Go back to using the docshell for the layout history state
4470 mLayoutHistoryState
= nullptr;
4471 mScopeObject
= do_GetWeakReference(aScriptGlobalObject
);
4473 if (!mWillReparent
) {
4474 // We really shouldn't have a wrapper here but if we do we need to make sure
4475 // it has the correct parent.
4476 JSObject
*obj
= GetWrapperPreserveColor();
4478 JSObject
*newScope
= aScriptGlobalObject
->GetGlobalJSObject();
4479 NS_ASSERTION(js::GetGlobalForObjectCrossCompartment(obj
) == newScope
,
4480 "Wrong scope, this is really bad!");
4485 if (mAllowDNSPrefetch
) {
4486 nsCOMPtr
<nsIDocShell
> docShell(mDocumentContainer
);
4489 nsCOMPtr
<nsIWebNavigation
> webNav
=
4490 do_GetInterface(aScriptGlobalObject
);
4491 NS_ASSERTION(SameCOMIdentity(webNav
, docShell
),
4492 "Unexpected container or script global?");
4494 bool allowDNSPrefetch
;
4495 docShell
->GetAllowDNSPrefetch(&allowDNSPrefetch
);
4496 mAllowDNSPrefetch
= allowDNSPrefetch
;
4500 MaybeRescheduleAnimationFrameNotifications();
4501 mRegistry
= new Registry();
4504 // Remember the pointer to our window (or lack there of), to avoid
4505 // having to QI every time it's asked for.
4506 nsCOMPtr
<nsPIDOMWindow
> window
= do_QueryInterface(mScriptGlobalObject
);
4509 // Now that we know what our window is, we can flush the CSP errors to the
4510 // Web Console. We are flushing all messages that occured and were stored
4511 // in the queue prior to this point.
4512 FlushCSPWebConsoleErrorQueue();
4513 nsCOMPtr
<nsIHttpChannelInternal
> internalChannel
=
4514 do_QueryInterface(GetChannel());
4515 if (internalChannel
) {
4516 nsCOMArray
<nsISecurityConsoleMessage
> messages
;
4517 internalChannel
->TakeAllSecurityMessages(messages
);
4518 SendToConsole(messages
);
4521 // Set our visibility state, but do not fire the event. This is correct
4522 // because either we're coming out of bfcache (in which case IsVisible() will
4523 // still test false at this point and no state change will happen) or we're
4524 // doing the initial document load and don't want to fire the event for this
4526 mVisibilityState
= GetVisibilityState();
4528 // The global in the template contents owner document should be the same.
4529 if (mTemplateContentsOwner
&& mTemplateContentsOwner
!= this) {
4530 mTemplateContentsOwner
->SetScriptGlobalObject(aScriptGlobalObject
);
4533 nsCOMPtr
<nsIChannel
> channel
= GetChannel();
4534 if (!mMaybeServiceWorkerControlled
&& channel
) {
4535 nsLoadFlags loadFlags
= 0;
4536 channel
->GetLoadFlags(&loadFlags
);
4537 // If we are shift-reloaded, don't associate with a ServiceWorker.
4538 // FIXME(nsm): Bug 1041339.
4539 if (loadFlags
& nsIRequest::LOAD_BYPASS_CACHE
) {
4540 NS_WARNING("Page was shift reloaded, skipping ServiceWorker control");
4544 nsCOMPtr
<nsIServiceWorkerManager
> swm
= mozilla::services::GetServiceWorkerManager();
4546 swm
->MaybeStartControlling(this);
4547 mMaybeServiceWorkerControlled
= true;
4552 nsIScriptGlobalObject
*
4553 nsDocument::GetScriptHandlingObjectInternal() const
4555 MOZ_ASSERT(!mScriptGlobalObject
,
4556 "Do not call this when mScriptGlobalObject is set!");
4557 if (mHasHadDefaultView
) {
4561 nsCOMPtr
<nsIScriptGlobalObject
> scriptHandlingObject
=
4562 do_QueryReferent(mScopeObject
);
4563 nsCOMPtr
<nsPIDOMWindow
> win
= do_QueryInterface(scriptHandlingObject
);
4565 NS_ASSERTION(win
->IsInnerWindow(), "Should have inner window here!");
4566 nsPIDOMWindow
* outer
= win
->GetOuterWindow();
4567 if (!outer
|| outer
->GetCurrentInnerWindow() != win
) {
4568 NS_WARNING("Wrong inner/outer window combination!");
4572 return scriptHandlingObject
;
4575 nsDocument::SetScriptHandlingObject(nsIScriptGlobalObject
* aScriptObject
)
4577 NS_ASSERTION(!mScriptGlobalObject
||
4578 mScriptGlobalObject
== aScriptObject
,
4579 "Wrong script object!");
4580 nsCOMPtr
<nsPIDOMWindow
> win
= do_QueryInterface(aScriptObject
);
4581 NS_ASSERTION(!win
|| win
->IsInnerWindow(), "Should have inner window here!");
4582 if (aScriptObject
) {
4583 mScopeObject
= do_GetWeakReference(aScriptObject
);
4584 mHasHadScriptHandlingObject
= true;
4585 mHasHadDefaultView
= false;
4590 nsDocument::IsTopLevelContentDocument()
4592 return mIsTopLevelContentDocument
;
4596 nsDocument::SetIsTopLevelContentDocument(bool aIsTopLevelContentDocument
)
4598 mIsTopLevelContentDocument
= aIsTopLevelContentDocument
;
4602 nsDocument::GetWindowInternal() const
4604 MOZ_ASSERT(!mWindow
, "This should not be called when mWindow is not null!");
4605 // Let's use mScriptGlobalObject. Even if the document is already removed from
4606 // the docshell, the outer window might be still obtainable from the it.
4607 nsCOMPtr
<nsPIDOMWindow
> win
;
4608 if (mRemovedFromDocShell
) {
4609 // The docshell returns the outer window we are done.
4610 nsCOMPtr
<nsIDocShell
> kungfuDeathGrip(mDocumentContainer
);
4611 if (mDocumentContainer
) {
4612 win
= mDocumentContainer
->GetWindow();
4615 win
= do_QueryInterface(mScriptGlobalObject
);
4617 // mScriptGlobalObject is always the inner window, let's get the outer.
4618 win
= win
->GetOuterWindow();
4619 } else if (mMasterDocument
) {
4620 // For script execution in the imported document we need the window of
4621 // the master document.
4622 win
= mMasterDocument
->GetWindow();
4630 nsDocument::ScriptLoader()
4632 return mScriptLoader
;
4636 nsDocument::InternalAllowXULXBL()
4638 if (nsContentUtils::AllowXULXBLForPrincipal(NodePrincipal())) {
4639 mAllowXULXBL
= eTriTrue
;
4643 mAllowXULXBL
= eTriFalse
;
4647 // Note: We don't hold a reference to the document observer; we assume
4648 // that it has a live reference to the document.
4650 nsDocument::AddObserver(nsIDocumentObserver
* aObserver
)
4652 NS_ASSERTION(mObservers
.IndexOf(aObserver
) == nsTArray
<int>::NoIndex
,
4653 "Observer already in the list");
4654 mObservers
.AppendElement(aObserver
);
4655 AddMutationObserver(aObserver
);
4659 nsDocument::RemoveObserver(nsIDocumentObserver
* aObserver
)
4661 // If we're in the process of destroying the document (and we're
4662 // informing the observers of the destruction), don't remove the
4663 // observers from the list. This is not a big deal, since we
4664 // don't hold a live reference to the observers.
4665 if (!mInDestructor
) {
4666 RemoveMutationObserver(aObserver
);
4667 return mObservers
.RemoveElement(aObserver
);
4670 return mObservers
.Contains(aObserver
);
4674 nsDocument::MaybeEndOutermostXBLUpdate()
4676 // Only call BindingManager()->EndOutermostUpdate() when
4677 // we're not in an update and it is safe to run scripts.
4678 if (mUpdateNestLevel
== 0 && mInXBLUpdate
) {
4679 if (nsContentUtils::IsSafeToRunScript()) {
4680 mInXBLUpdate
= false;
4681 BindingManager()->EndOutermostUpdate();
4682 } else if (!mInDestructor
) {
4683 nsContentUtils::AddScriptRunner(
4684 NS_NewRunnableMethod(this, &nsDocument::MaybeEndOutermostXBLUpdate
));
4690 nsDocument::BeginUpdate(nsUpdateType aUpdateType
)
4692 if (mUpdateNestLevel
== 0 && !mInXBLUpdate
) {
4693 mInXBLUpdate
= true;
4694 BindingManager()->BeginOutermostUpdate();
4698 nsContentUtils::AddScriptBlocker();
4699 NS_DOCUMENT_NOTIFY_OBSERVERS(BeginUpdate
, (this, aUpdateType
));
4703 nsDocument::EndUpdate(nsUpdateType aUpdateType
)
4705 NS_DOCUMENT_NOTIFY_OBSERVERS(EndUpdate
, (this, aUpdateType
));
4707 nsContentUtils::RemoveScriptBlocker();
4711 // This set of updates may have created XBL bindings. Let the
4712 // binding manager know we're done.
4713 MaybeEndOutermostXBLUpdate();
4715 MaybeInitializeFinalizeFrameLoaders();
4719 nsDocument::BeginLoad()
4721 // Block onload here to prevent having to deal with blocking and
4722 // unblocking it while we know the document is loading.
4724 mDidFireDOMContentLoaded
= false;
4725 BlockDOMContentLoaded();
4727 if (mScriptLoader
) {
4728 mScriptLoader
->BeginDeferringScripts();
4731 NS_DOCUMENT_NOTIFY_OBSERVERS(BeginLoad
, (this));
4735 nsDocument::ReportEmptyGetElementByIdArg()
4737 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag
,
4738 NS_LITERAL_CSTRING("DOM"), this,
4739 nsContentUtils::eDOM_PROPERTIES
,
4740 "EmptyGetElementByIdParam");
4744 nsDocument::GetElementById(const nsAString
& aElementId
)
4746 if (!CheckGetElementByIdArg(aElementId
)) {
4750 nsIdentifierMapEntry
*entry
= mIdentifierMap
.GetEntry(aElementId
);
4751 return entry
? entry
->GetIdElement() : nullptr;
4754 const nsSmallVoidArray
*
4755 nsDocument::GetAllElementsForId(const nsAString
& aElementId
) const
4757 if (aElementId
.IsEmpty()) {
4761 nsIdentifierMapEntry
*entry
= mIdentifierMap
.GetEntry(aElementId
);
4762 return entry
? entry
->GetIdElements() : nullptr;
4766 nsDocument::GetElementById(const nsAString
& aId
, nsIDOMElement
** aReturn
)
4768 Element
*content
= GetElementById(aId
);
4770 return CallQueryInterface(content
, aReturn
);
4779 nsDocument::AddIDTargetObserver(nsIAtom
* aID
, IDTargetObserver aObserver
,
4780 void* aData
, bool aForImage
)
4782 nsDependentAtomString
id(aID
);
4784 if (!CheckGetElementByIdArg(id
))
4787 nsIdentifierMapEntry
*entry
= mIdentifierMap
.PutEntry(id
);
4788 NS_ENSURE_TRUE(entry
, nullptr);
4790 entry
->AddContentChangeCallback(aObserver
, aData
, aForImage
);
4791 return aForImage
? entry
->GetImageIdElement() : entry
->GetIdElement();
4795 nsDocument::RemoveIDTargetObserver(nsIAtom
* aID
, IDTargetObserver aObserver
,
4796 void* aData
, bool aForImage
)
4798 nsDependentAtomString
id(aID
);
4800 if (!CheckGetElementByIdArg(id
))
4803 nsIdentifierMapEntry
*entry
= mIdentifierMap
.GetEntry(id
);
4808 entry
->RemoveContentChangeCallback(aObserver
, aData
, aForImage
);
4812 nsDocument::MozSetImageElement(const nsAString
& aImageElementId
,
4813 nsIDOMElement
* aImageElement
)
4815 nsCOMPtr
<Element
> el
= do_QueryInterface(aImageElement
);
4816 MozSetImageElement(aImageElementId
, el
);
4821 nsDocument::MozSetImageElement(const nsAString
& aImageElementId
,
4824 if (aImageElementId
.IsEmpty())
4827 // Hold a script blocker while calling SetImageElement since that can call
4828 // out to id-observers
4829 nsAutoScriptBlocker scriptBlocker
;
4831 nsIdentifierMapEntry
*entry
= mIdentifierMap
.PutEntry(aImageElementId
);
4833 entry
->SetImageElement(aElement
);
4834 if (entry
->IsEmpty()) {
4835 mIdentifierMap
.RemoveEntry(aImageElementId
);
4841 nsDocument::LookupImageElement(const nsAString
& aId
)
4846 nsIdentifierMapEntry
*entry
= mIdentifierMap
.GetEntry(aId
);
4847 return entry
? entry
->GetImageIdElement() : nullptr;
4851 nsDocument::DispatchContentLoadedEvents()
4853 // If you add early returns from this method, make sure you're
4854 // calling UnblockOnload properly.
4856 // Unpin references to preloaded images
4857 mPreloadingImages
.Clear();
4860 mTiming
->NotifyDOMContentLoadedStart(nsIDocument::GetDocumentURI());
4863 // Dispatch observer notification to notify observers document is interactive.
4864 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
4865 nsIPrincipal
*principal
= GetPrincipal();
4866 os
->NotifyObservers(static_cast<nsIDocument
*>(this),
4867 nsContentUtils::IsSystemPrincipal(principal
) ?
4868 "chrome-document-interactive" :
4869 "content-document-interactive",
4872 // Fire a DOM event notifying listeners that this document has been
4873 // loaded (excluding images and other loads initiated by this
4875 nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument
*>(this),
4876 NS_LITERAL_STRING("DOMContentLoaded"),
4880 mTiming
->NotifyDOMContentLoadedEnd(nsIDocument::GetDocumentURI());
4883 // If this document is a [i]frame, fire a DOMFrameContentLoaded
4884 // event on all parent documents notifying that the HTML (excluding
4885 // other external files such as images and stylesheets) in a frame
4886 // has finished loading.
4888 // target_frame is the [i]frame element that will be used as the
4889 // target for the event. It's the [i]frame whose content is done
4891 nsCOMPtr
<EventTarget
> target_frame
;
4893 if (mParentDocument
) {
4894 target_frame
= mParentDocument
->FindContentForSubDocument(this);
4898 nsCOMPtr
<nsIDocument
> parent
= mParentDocument
;
4900 nsCOMPtr
<nsIDOMDocument
> domDoc
= do_QueryInterface(parent
);
4902 nsCOMPtr
<nsIDOMEvent
> event
;
4904 domDoc
->CreateEvent(NS_LITERAL_STRING("Events"),
4905 getter_AddRefs(event
));
4910 event
->InitEvent(NS_LITERAL_STRING("DOMFrameContentLoaded"), true,
4913 event
->SetTarget(target_frame
);
4914 event
->SetTrusted(true);
4916 // To dispatch this event we must manually call
4917 // EventDispatcher::Dispatch() on the ancestor document since the
4918 // target is not in the same document, so the event would never reach
4919 // the ancestor document if we used the normal event
4920 // dispatching code.
4922 WidgetEvent
* innerEvent
= event
->GetInternalNSEvent();
4924 nsEventStatus status
= nsEventStatus_eIgnore
;
4926 nsIPresShell
*shell
= parent
->GetShell();
4928 nsRefPtr
<nsPresContext
> context
= shell
->GetPresContext();
4931 EventDispatcher::Dispatch(parent
, context
, innerEvent
, event
,
4938 parent
= parent
->GetParentDocument();
4942 // If the document has a manifest attribute, fire a MozApplicationManifest
4944 Element
* root
= GetRootElement();
4945 if (root
&& root
->HasAttr(kNameSpaceID_None
, nsGkAtoms::manifest
)) {
4946 nsContentUtils::DispatchChromeEvent(this, static_cast<nsIDocument
*>(this),
4947 NS_LITERAL_STRING("MozApplicationManifest"),
4951 UnblockOnload(true);
4955 nsDocument::EndLoad()
4957 // Drop the ref to our parser, if any, but keep hold of the sink so that we
4958 // can flush it from FlushPendingNotifications as needed. We might have to
4959 // do that to get a StartLayout() to happen.
4961 mWeakSink
= do_GetWeakReference(mParser
->GetContentSink());
4965 NS_DOCUMENT_NOTIFY_OBSERVERS(EndLoad
, (this));
4967 UnblockDOMContentLoaded();
4971 nsDocument::UnblockDOMContentLoaded()
4973 MOZ_ASSERT(mBlockDOMContentLoaded
);
4974 if (--mBlockDOMContentLoaded
!= 0 || mDidFireDOMContentLoaded
) {
4977 mDidFireDOMContentLoaded
= true;
4979 MOZ_ASSERT(mReadyState
== READYSTATE_INTERACTIVE
);
4980 if (!mSynchronousDOMContentLoaded
) {
4981 nsRefPtr
<nsIRunnable
> ev
=
4982 NS_NewRunnableMethod(this, &nsDocument::DispatchContentLoadedEvents
);
4983 NS_DispatchToCurrentThread(ev
);
4985 DispatchContentLoadedEvents();
4990 nsDocument::ContentStateChanged(nsIContent
* aContent
, EventStates aStateMask
)
4992 NS_PRECONDITION(!nsContentUtils::IsSafeToRunScript(),
4993 "Someone forgot a scriptblocker");
4994 NS_DOCUMENT_NOTIFY_OBSERVERS(ContentStateChanged
,
4995 (this, aContent
, aStateMask
));
4999 nsDocument::DocumentStatesChanged(EventStates aStateMask
)
5001 // Invalidate our cached state.
5002 mGotDocumentState
&= ~aStateMask
;
5003 mDocumentState
&= ~aStateMask
;
5005 NS_DOCUMENT_NOTIFY_OBSERVERS(DocumentStatesChanged
, (this, aStateMask
));
5009 nsDocument::StyleRuleChanged(nsIStyleSheet
* aSheet
,
5010 nsIStyleRule
* aOldStyleRule
,
5011 nsIStyleRule
* aNewStyleRule
)
5013 NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleChanged
,
5015 aOldStyleRule
, aNewStyleRule
));
5017 if (StyleSheetChangeEventsEnabled()) {
5018 nsCOMPtr
<css::Rule
> rule
= do_QueryInterface(aNewStyleRule
);
5019 DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent
,
5022 rule
? rule
->GetDOMRule() : nullptr);
5027 nsDocument::StyleRuleAdded(nsIStyleSheet
* aSheet
,
5028 nsIStyleRule
* aStyleRule
)
5030 NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleAdded
,
5031 (this, aSheet
, aStyleRule
));
5033 if (StyleSheetChangeEventsEnabled()) {
5034 nsCOMPtr
<css::Rule
> rule
= do_QueryInterface(aStyleRule
);
5035 DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent
,
5038 rule
? rule
->GetDOMRule() : nullptr);
5043 nsDocument::StyleRuleRemoved(nsIStyleSheet
* aSheet
,
5044 nsIStyleRule
* aStyleRule
)
5046 NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleRemoved
,
5047 (this, aSheet
, aStyleRule
));
5049 if (StyleSheetChangeEventsEnabled()) {
5050 nsCOMPtr
<css::Rule
> rule
= do_QueryInterface(aStyleRule
);
5051 DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent
,
5054 rule
? rule
->GetDOMRule() : nullptr);
5058 #undef DO_STYLESHEET_NOTIFICATION
5062 // nsIDOMDocument interface
5065 nsIDocument::GetDoctype() const
5067 for (nsIContent
* child
= GetFirstChild();
5069 child
= child
->GetNextSibling()) {
5070 if (child
->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE
) {
5071 return static_cast<DocumentType
*>(child
);
5078 nsDocument::GetDoctype(nsIDOMDocumentType
** aDoctype
)
5080 MOZ_ASSERT(aDoctype
);
5081 nsCOMPtr
<nsIDOMDocumentType
> doctype
= nsIDocument::GetDoctype();
5082 doctype
.forget(aDoctype
);
5087 nsDocument::GetImplementation(nsIDOMDOMImplementation
** aImplementation
)
5090 *aImplementation
= GetImplementation(rv
);
5092 MOZ_ASSERT(!*aImplementation
);
5093 return rv
.ErrorCode();
5095 NS_ADDREF(*aImplementation
);
5100 nsDocument::GetImplementation(ErrorResult
& rv
)
5102 if (!mDOMImplementation
) {
5103 nsCOMPtr
<nsIURI
> uri
;
5104 NS_NewURI(getter_AddRefs(uri
), "about:blank");
5106 rv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
5109 bool hasHadScriptObject
= true;
5110 nsIScriptGlobalObject
* scriptObject
=
5111 GetScriptHandlingObject(hasHadScriptObject
);
5112 if (!scriptObject
&& hasHadScriptObject
) {
5113 rv
.Throw(NS_ERROR_UNEXPECTED
);
5116 mDOMImplementation
= new DOMImplementation(this,
5117 scriptObject
? scriptObject
: GetScopeObject(), uri
, uri
);
5120 return mDOMImplementation
;
5124 nsDocument::GetDocumentElement(nsIDOMElement
** aDocumentElement
)
5126 NS_ENSURE_ARG_POINTER(aDocumentElement
);
5128 Element
* root
= GetRootElement();
5130 return CallQueryInterface(root
, aDocumentElement
);
5133 *aDocumentElement
= nullptr;
5139 nsDocument::CreateElement(const nsAString
& aTagName
,
5140 nsIDOMElement
** aReturn
)
5144 nsCOMPtr
<Element
> element
= nsIDocument::CreateElement(aTagName
, rv
);
5145 NS_ENSURE_FALSE(rv
.Failed(), rv
.ErrorCode());
5146 return CallQueryInterface(element
, aReturn
);
5149 bool IsLowercaseASCII(const nsAString
& aValue
)
5151 int32_t len
= aValue
.Length();
5152 for (int32_t i
= 0; i
< len
; ++i
) {
5153 char16_t c
= aValue
[i
];
5154 if (!(0x0061 <= (c
) && ((c
) <= 0x007a))) {
5161 already_AddRefed
<Element
>
5162 nsIDocument::CreateElement(const nsAString
& aTagName
, ErrorResult
& rv
)
5164 rv
= nsContentUtils::CheckQName(aTagName
, false);
5169 bool needsLowercase
= IsHTML() && !IsLowercaseASCII(aTagName
);
5170 nsAutoString lcTagName
;
5171 if (needsLowercase
) {
5172 nsContentUtils::ASCIIToLower(aTagName
, lcTagName
);
5175 nsCOMPtr
<nsIContent
> content
;
5176 rv
= CreateElem(needsLowercase
? lcTagName
: aTagName
,
5177 nullptr, mDefaultElementType
, getter_AddRefs(content
));
5181 return dont_AddRef(content
.forget().take()->AsElement());
5185 nsDocument::SwizzleCustomElement(Element
* aElement
,
5186 const nsAString
& aTypeExtension
,
5187 uint32_t aNamespaceID
,
5190 nsCOMPtr
<nsIAtom
> typeAtom(do_GetAtom(aTypeExtension
));
5191 nsCOMPtr
<nsIAtom
> tagAtom
= aElement
->Tag();
5192 if (!mRegistry
|| tagAtom
== typeAtom
) {
5196 CustomElementDefinition
* data
;
5197 CustomElementHashKey
key(aNamespaceID
, typeAtom
);
5198 if (!mRegistry
->mCustomDefinitions
.Get(&key
, &data
)) {
5199 // The type extension doesn't exist in the registry,
5200 // thus we don't need to swizzle, but it is possibly
5201 // an upgrade candidate.
5202 RegisterUnresolvedElement(aElement
, typeAtom
);
5206 if (data
->mLocalName
!= tagAtom
) {
5207 // The element doesn't match the local name for the
5208 // definition, thus the element isn't a custom element
5209 // and we don't need to do anything more.
5213 if (!aElement
->HasAttr(kNameSpaceID_None
, nsGkAtoms::is
)) {
5214 // Swizzling in the parser happens after the "is" attribute is added.
5215 aElement
->SetAttr(kNameSpaceID_None
, nsGkAtoms::is
, aTypeExtension
, true);
5218 // Enqueuing the created callback will set the CustomElementData on the
5219 // element, causing prototype swizzling to occur in Element::WrapObject.
5220 EnqueueLifecycleCallback(nsIDocument::eCreated
, aElement
, nullptr, data
);
5223 already_AddRefed
<Element
>
5224 nsDocument::CreateElement(const nsAString
& aTagName
,
5225 const nsAString
& aTypeExtension
,
5228 nsRefPtr
<Element
> elem
= nsIDocument::CreateElement(aTagName
, rv
);
5233 SwizzleCustomElement(elem
, aTypeExtension
,
5234 GetDefaultNamespaceID(), rv
);
5239 return elem
.forget();
5243 nsDocument::CreateElementNS(const nsAString
& aNamespaceURI
,
5244 const nsAString
& aQualifiedName
,
5245 nsIDOMElement
** aReturn
)
5249 nsCOMPtr
<Element
> element
=
5250 nsIDocument::CreateElementNS(aNamespaceURI
, aQualifiedName
, rv
);
5251 NS_ENSURE_FALSE(rv
.Failed(), rv
.ErrorCode());
5252 return CallQueryInterface(element
, aReturn
);
5255 already_AddRefed
<Element
>
5256 nsIDocument::CreateElementNS(const nsAString
& aNamespaceURI
,
5257 const nsAString
& aQualifiedName
,
5260 nsRefPtr
<mozilla::dom::NodeInfo
> nodeInfo
;
5261 rv
= nsContentUtils::GetNodeInfoFromQName(aNamespaceURI
,
5264 nsIDOMNode::ELEMENT_NODE
,
5265 getter_AddRefs(nodeInfo
));
5270 nsCOMPtr
<Element
> element
;
5271 rv
= NS_NewElement(getter_AddRefs(element
), nodeInfo
.forget(),
5276 return element
.forget();
5279 already_AddRefed
<Element
>
5280 nsDocument::CreateElementNS(const nsAString
& aNamespaceURI
,
5281 const nsAString
& aQualifiedName
,
5282 const nsAString
& aTypeExtension
,
5285 nsRefPtr
<Element
> elem
= nsIDocument::CreateElementNS(aNamespaceURI
,
5292 int32_t nameSpaceId
= kNameSpaceID_Wildcard
;
5293 if (!aNamespaceURI
.EqualsLiteral("*")) {
5294 rv
= nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI
,
5301 SwizzleCustomElement(elem
, aTypeExtension
, nameSpaceId
, rv
);
5306 return elem
.forget();
5310 nsDocument::CreateTextNode(const nsAString
& aData
, nsIDOMText
** aReturn
)
5312 *aReturn
= nsIDocument::CreateTextNode(aData
).take();
5316 already_AddRefed
<nsTextNode
>
5317 nsIDocument::CreateTextNode(const nsAString
& aData
) const
5319 nsRefPtr
<nsTextNode
> text
= new nsTextNode(mNodeInfoManager
);
5320 // Don't notify; this node is still being created.
5321 text
->SetText(aData
, false);
5322 return text
.forget();
5326 nsDocument::CreateDocumentFragment(nsIDOMDocumentFragment
** aReturn
)
5328 *aReturn
= nsIDocument::CreateDocumentFragment().take();
5332 already_AddRefed
<DocumentFragment
>
5333 nsIDocument::CreateDocumentFragment() const
5335 nsRefPtr
<DocumentFragment
> frag
= new DocumentFragment(mNodeInfoManager
);
5336 return frag
.forget();
5340 nsDocument::CreateComment(const nsAString
& aData
, nsIDOMComment
** aReturn
)
5342 *aReturn
= nsIDocument::CreateComment(aData
).take();
5346 // Unfortunately, bareword "Comment" is ambiguous with some Mac system headers.
5347 already_AddRefed
<dom::Comment
>
5348 nsIDocument::CreateComment(const nsAString
& aData
) const
5350 nsRefPtr
<dom::Comment
> comment
= new dom::Comment(mNodeInfoManager
);
5352 // Don't notify; this node is still being created.
5353 comment
->SetText(aData
, false);
5354 return comment
.forget();
5358 nsDocument::CreateCDATASection(const nsAString
& aData
,
5359 nsIDOMCDATASection
** aReturn
)
5361 NS_ENSURE_ARG_POINTER(aReturn
);
5363 *aReturn
= nsIDocument::CreateCDATASection(aData
, rv
).take();
5364 return rv
.ErrorCode();
5367 already_AddRefed
<CDATASection
>
5368 nsIDocument::CreateCDATASection(const nsAString
& aData
,
5372 rv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
5376 if (FindInReadable(NS_LITERAL_STRING("]]>"), aData
)) {
5377 rv
.Throw(NS_ERROR_DOM_INVALID_CHARACTER_ERR
);
5381 nsRefPtr
<CDATASection
> cdata
= new CDATASection(mNodeInfoManager
);
5383 // Don't notify; this node is still being created.
5384 cdata
->SetText(aData
, false);
5386 return cdata
.forget();
5390 nsDocument::CreateProcessingInstruction(const nsAString
& aTarget
,
5391 const nsAString
& aData
,
5392 nsIDOMProcessingInstruction
** aReturn
)
5396 nsIDocument::CreateProcessingInstruction(aTarget
, aData
, rv
).take();
5397 return rv
.ErrorCode();
5400 already_AddRefed
<ProcessingInstruction
>
5401 nsIDocument::CreateProcessingInstruction(const nsAString
& aTarget
,
5402 const nsAString
& aData
,
5403 ErrorResult
& rv
) const
5405 nsresult res
= nsContentUtils::CheckQName(aTarget
, false);
5406 if (NS_FAILED(res
)) {
5411 if (FindInReadable(NS_LITERAL_STRING("?>"), aData
)) {
5412 rv
.Throw(NS_ERROR_DOM_INVALID_CHARACTER_ERR
);
5416 nsRefPtr
<ProcessingInstruction
> pi
=
5417 NS_NewXMLProcessingInstruction(mNodeInfoManager
, aTarget
, aData
);
5423 nsDocument::CreateAttribute(const nsAString
& aName
,
5424 nsIDOMAttr
** aReturn
)
5427 *aReturn
= nsIDocument::CreateAttribute(aName
, rv
).take();
5428 return rv
.ErrorCode();
5431 already_AddRefed
<Attr
>
5432 nsIDocument::CreateAttribute(const nsAString
& aName
, ErrorResult
& rv
)
5434 WarnOnceAbout(eCreateAttribute
);
5436 if (!mNodeInfoManager
) {
5437 rv
.Throw(NS_ERROR_NOT_INITIALIZED
);
5441 nsresult res
= nsContentUtils::CheckQName(aName
, false);
5442 if (NS_FAILED(res
)) {
5447 nsRefPtr
<mozilla::dom::NodeInfo
> nodeInfo
;
5448 res
= mNodeInfoManager
->GetNodeInfo(aName
, nullptr, kNameSpaceID_None
,
5449 nsIDOMNode::ATTRIBUTE_NODE
,
5450 getter_AddRefs(nodeInfo
));
5451 if (NS_FAILED(res
)) {
5456 nsRefPtr
<Attr
> attribute
= new Attr(nullptr, nodeInfo
.forget(),
5457 EmptyString(), false);
5458 return attribute
.forget();
5462 nsDocument::CreateAttributeNS(const nsAString
& aNamespaceURI
,
5463 const nsAString
& aQualifiedName
,
5464 nsIDOMAttr
**aResult
)
5468 nsIDocument::CreateAttributeNS(aNamespaceURI
, aQualifiedName
, rv
).take();
5469 return rv
.ErrorCode();
5472 already_AddRefed
<Attr
>
5473 nsIDocument::CreateAttributeNS(const nsAString
& aNamespaceURI
,
5474 const nsAString
& aQualifiedName
,
5477 WarnOnceAbout(eCreateAttributeNS
);
5479 nsRefPtr
<mozilla::dom::NodeInfo
> nodeInfo
;
5480 rv
= nsContentUtils::GetNodeInfoFromQName(aNamespaceURI
,
5483 nsIDOMNode::ATTRIBUTE_NODE
,
5484 getter_AddRefs(nodeInfo
));
5489 nsRefPtr
<Attr
> attribute
= new Attr(nullptr, nodeInfo
.forget(),
5490 EmptyString(), true);
5491 return attribute
.forget();
5495 nsDocument::CustomElementConstructor(JSContext
* aCx
, unsigned aArgc
, JS::Value
* aVp
)
5497 JS::CallArgs args
= JS::CallArgsFromVp(aArgc
, aVp
);
5499 JS::Rooted
<JSObject
*> global(aCx
,
5500 JS_GetGlobalForObject(aCx
, &args
.callee()));
5501 nsCOMPtr
<nsPIDOMWindow
> window
= do_QueryWrapper(aCx
, global
);
5502 MOZ_ASSERT(window
, "Should have a non-null window");
5504 nsDocument
* document
= static_cast<nsDocument
*>(window
->GetDoc());
5506 // Function name is the type of the custom element.
5507 JSString
* jsFunName
=
5508 JS_GetFunctionId(JS_ValueToFunction(aCx
, args
.calleev()));
5509 nsAutoJSString elemName
;
5510 if (!elemName
.init(aCx
, jsFunName
)) {
5514 nsCOMPtr
<nsIAtom
> typeAtom(do_GetAtom(elemName
));
5515 CustomElementHashKey
key(kNameSpaceID_Unknown
, typeAtom
);
5516 CustomElementDefinition
* definition
;
5517 if (!document
->mRegistry
||
5518 !document
->mRegistry
->mCustomDefinitions
.Get(&key
, &definition
)) {
5522 nsDependentAtomString
localName(definition
->mLocalName
);
5524 nsCOMPtr
<nsIContent
> newElement
;
5525 nsresult rv
= document
->CreateElem(localName
, nullptr,
5526 definition
->mNamespaceID
,
5527 getter_AddRefs(newElement
));
5528 NS_ENSURE_SUCCESS(rv
, true);
5530 ErrorResult errorResult
;
5531 nsCOMPtr
<Element
> element
= do_QueryInterface(newElement
);
5532 document
->SwizzleCustomElement(element
, elemName
, definition
->mNamespaceID
,
5534 if (errorResult
.Failed()) {
5538 rv
= nsContentUtils::WrapNative(aCx
, newElement
, newElement
, args
.rval());
5539 NS_ENSURE_SUCCESS(rv
, true);
5545 nsDocument::IsWebComponentsEnabled(JSContext
* aCx
, JSObject
* aObject
)
5547 JS::Rooted
<JSObject
*> obj(aCx
, aObject
);
5548 return Preferences::GetBool("dom.webcomponents.enabled") ||
5549 IsInCertifiedApp(aCx
, obj
);
5553 nsDocument::RegisterUnresolvedElement(Element
* aElement
, nsIAtom
* aTypeName
)
5559 mozilla::dom::NodeInfo
* info
= aElement
->NodeInfo();
5561 // Candidate may be a custom element through extension,
5562 // in which case the custom element type name will not
5563 // match the element tag name. e.g. <button is="x-button">.
5564 nsCOMPtr
<nsIAtom
> typeName
= aTypeName
;
5566 typeName
= info
->NameAtom();
5569 CustomElementHashKey
key(info
->NamespaceID(), typeName
);
5570 if (mRegistry
->mCustomDefinitions
.Get(&key
)) {
5574 nsTArray
<nsRefPtr
<Element
>>* unresolved
;
5575 mRegistry
->mCandidatesMap
.Get(&key
, &unresolved
);
5577 unresolved
= new nsTArray
<nsRefPtr
<Element
>>();
5578 // Ownership of unresolved is taken by mCandidatesMap.
5579 mRegistry
->mCandidatesMap
.Put(&key
, unresolved
);
5582 nsRefPtr
<Element
>* elem
= unresolved
->AppendElement();
5590 class ProcessStackRunner MOZ_FINAL
: public nsIRunnable
5592 ~ProcessStackRunner() {}
5594 explicit ProcessStackRunner(bool aIsBaseQueue
= false)
5595 : mIsBaseQueue(aIsBaseQueue
)
5599 NS_IMETHOD
Run() MOZ_OVERRIDE
5601 nsDocument::ProcessTopElementQueue(mIsBaseQueue
);
5607 NS_IMPL_ISUPPORTS(ProcessStackRunner
, nsIRunnable
);
5609 } // anonymous namespace
5612 nsDocument::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType
,
5613 Element
* aCustomElement
,
5614 LifecycleCallbackArgs
* aArgs
,
5615 CustomElementDefinition
* aDefinition
)
5618 // The element might not belong to a document that
5619 // has a browsing context, and thus no registry.
5623 CustomElementData
* elementData
= aCustomElement
->GetCustomElementData();
5625 // Let DEFINITION be ELEMENT's definition
5626 CustomElementDefinition
* definition
= aDefinition
;
5628 mozilla::dom::NodeInfo
* info
= aCustomElement
->NodeInfo();
5630 // Make sure we get the correct definition in case the element
5631 // is a extended custom element e.g. <button is="x-button">.
5632 nsCOMPtr
<nsIAtom
> typeAtom
= elementData
?
5633 elementData
->mType
.get() : info
->NameAtom();
5635 CustomElementHashKey
key(info
->NamespaceID(), typeAtom
);
5636 if (!mRegistry
->mCustomDefinitions
.Get(&key
, &definition
) ||
5637 definition
->mLocalName
!= info
->NameAtom()) {
5638 // Trying to enqueue a callback for an element that is not
5639 // a custom element. We are done, nothing to do.
5645 // Create the custom element data the first time
5646 // that we try to enqueue a callback.
5647 elementData
= new CustomElementData(definition
->mType
);
5648 // aCustomElement takes ownership of elementData
5649 aCustomElement
->SetCustomElementData(elementData
);
5650 MOZ_ASSERT(aType
== nsIDocument::eCreated
,
5651 "First callback should be the created callback");
5654 // Let CALLBACK be the callback associated with the key NAME in CALLBACKS.
5655 CallbackFunction
* func
= nullptr;
5657 case nsIDocument::eCreated
:
5658 if (definition
->mCallbacks
->mCreatedCallback
.WasPassed()) {
5659 func
= definition
->mCallbacks
->mCreatedCallback
.Value();
5663 case nsIDocument::eAttached
:
5664 if (definition
->mCallbacks
->mAttachedCallback
.WasPassed()) {
5665 func
= definition
->mCallbacks
->mAttachedCallback
.Value();
5669 case nsIDocument::eDetached
:
5670 if (definition
->mCallbacks
->mDetachedCallback
.WasPassed()) {
5671 func
= definition
->mCallbacks
->mDetachedCallback
.Value();
5675 case nsIDocument::eAttributeChanged
:
5676 if (definition
->mCallbacks
->mAttributeChangedCallback
.WasPassed()) {
5677 func
= definition
->mCallbacks
->mAttributeChangedCallback
.Value();
5682 // If there is no such callback, stop.
5687 if (aType
== nsIDocument::eCreated
) {
5688 elementData
->mCreatedCallbackInvoked
= false;
5689 } else if (!elementData
->mCreatedCallbackInvoked
) {
5690 // Callbacks other than created callback must not be enqueued
5691 // until after the created callback has been invoked.
5695 // Add CALLBACK to ELEMENT's callback queue.
5696 CustomElementCallback
* callback
= new CustomElementCallback(aCustomElement
,
5700 // Ownership of callback is taken by mCallbackQueue.
5701 elementData
->mCallbackQueue
.AppendElement(callback
);
5703 callback
->SetArgs(*aArgs
);
5706 if (!elementData
->mElementIsBeingCreated
) {
5707 CustomElementData
* lastData
=
5708 sProcessingStack
->SafeLastElement(nullptr);
5710 // A new element queue needs to be pushed if the queue at the
5711 // top of the stack is associated with another microtask level.
5712 // Don't push a queue for the level 0 microtask (base element queue)
5713 // because we don't want to process the queue until the
5714 // microtask checkpoint.
5715 bool shouldPushElementQueue
= nsContentUtils::MicroTaskLevel() > 0 &&
5716 (!lastData
|| lastData
->mAssociatedMicroTask
<
5717 static_cast<int32_t>(nsContentUtils::MicroTaskLevel()));
5719 // Push a new element queue onto the processing stack when appropriate
5720 // (when we enter a new microtask).
5721 if (shouldPushElementQueue
) {
5722 // Push a sentinel value on the processing stack to mark the
5723 // boundary between the element queues.
5724 sProcessingStack
->AppendElement((CustomElementData
*) nullptr);
5727 sProcessingStack
->AppendElement(elementData
);
5728 elementData
->mAssociatedMicroTask
=
5729 static_cast<int32_t>(nsContentUtils::MicroTaskLevel());
5731 // Add a script runner to pop and process the element queue at
5732 // the top of the processing stack.
5733 if (shouldPushElementQueue
) {
5734 // Lifecycle callbacks enqueued by user agent implementation
5735 // should be invoked prior to returning control back to script.
5736 // Create a script runner to process the top of the processing
5737 // stack as soon as it is safe to run script.
5738 nsContentUtils::AddScriptRunner(new ProcessStackRunner());
5745 nsDocument::ProcessBaseElementQueue()
5747 // Prevent re-entrance. Also, if a microtask checkpoint is reached
5748 // and there is no processing stack to process, then we are done.
5749 if (sProcessingBaseElementQueue
|| !sProcessingStack
) {
5753 MOZ_ASSERT(nsContentUtils::MicroTaskLevel() == 0);
5754 sProcessingBaseElementQueue
= true;
5755 nsContentUtils::AddScriptRunner(new ProcessStackRunner(true));
5760 nsDocument::ProcessTopElementQueue(bool aIsBaseQueue
)
5762 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
5764 nsTArray
<nsRefPtr
<CustomElementData
>>& stack
= *sProcessingStack
;
5765 uint32_t firstQueue
= stack
.LastIndexOf((CustomElementData
*) nullptr);
5767 if (aIsBaseQueue
&& firstQueue
!= 0) {
5771 for (uint32_t i
= firstQueue
+ 1; i
< stack
.Length(); ++i
) {
5772 // Callback queue may have already been processed in an earlier
5773 // element queue or in an element queue that was popped
5774 // off more recently.
5775 if (stack
[i
]->mAssociatedMicroTask
!= -1) {
5776 stack
[i
]->RunCallbackQueue();
5777 stack
[i
]->mAssociatedMicroTask
= -1;
5781 // If this was actually the base element queue, don't bother trying to pop
5782 // the first "queue" marker (sentinel).
5783 if (firstQueue
!= 0) {
5784 stack
.SetLength(firstQueue
);
5786 // Don't pop sentinel for base element queue.
5788 sProcessingBaseElementQueue
= false;
5793 nsDocument::RegisterEnabled()
5795 static bool sPrefValue
=
5796 Preferences::GetBool("dom.webcomponents.enabled", false);
5801 Maybe
<nsTArray
<nsRefPtr
<mozilla::dom::CustomElementData
>>>
5802 nsDocument::sProcessingStack
;
5806 nsDocument::sProcessingBaseElementQueue
;
5809 nsDocument::RegisterElement(JSContext
* aCx
, const nsAString
& aType
,
5810 const ElementRegistrationOptions
& aOptions
,
5811 JS::MutableHandle
<JSObject
*> aRetval
,
5815 rv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
5819 Registry::DefinitionMap
& definitions
= mRegistry
->mCustomDefinitions
;
5821 // Unconditionally convert TYPE to lowercase.
5822 nsAutoString lcType
;
5823 nsContentUtils::ASCIIToLower(aType
, lcType
);
5825 // Only convert NAME to lowercase in HTML documents. Note that NAME is
5827 nsAutoString lcName
;
5829 nsContentUtils::ASCIIToLower(aOptions
.mExtends
, lcName
);
5831 lcName
.Assign(aOptions
.mExtends
);
5834 nsCOMPtr
<nsIAtom
> typeAtom(do_GetAtom(lcType
));
5835 if (!nsContentUtils::IsCustomElementName(typeAtom
)) {
5836 rv
.Throw(NS_ERROR_DOM_SYNTAX_ERR
);
5840 // If there already exists a definition with the same TYPE, set ERROR to
5841 // DuplicateDefinition and stop.
5842 // Note that we need to find existing custom elements from either namespace.
5843 CustomElementHashKey
duplicateFinder(kNameSpaceID_Unknown
, typeAtom
);
5844 if (definitions
.Get(&duplicateFinder
)) {
5845 rv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
5849 nsIGlobalObject
* sgo
= GetScopeObject();
5851 rv
.Throw(NS_ERROR_UNEXPECTED
);
5854 JS::Rooted
<JSObject
*> global(aCx
, sgo
->GetGlobalJSObject());
5856 JSAutoCompartment
ac(aCx
, global
);
5858 JS::Handle
<JSObject
*> htmlProto(
5859 HTMLElementBinding::GetProtoObject(aCx
, global
));
5861 rv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
5865 int32_t namespaceID
= kNameSpaceID_XHTML
;
5866 JS::Rooted
<JSObject
*> protoObject(aCx
);
5867 if (!aOptions
.mPrototype
) {
5868 protoObject
= JS_NewObject(aCx
, nullptr, htmlProto
, JS::NullPtr());
5870 rv
.Throw(NS_ERROR_UNEXPECTED
);
5874 // If a prototype is provided, we must check to ensure that it is from the
5875 // same browsing context as us.
5876 protoObject
= aOptions
.mPrototype
;
5877 if (JS_GetGlobalForObject(aCx
, protoObject
) != global
) {
5878 rv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
5882 // If PROTOTYPE is already an interface prototype object for any interface
5883 // object or PROTOTYPE has a non-configurable property named constructor,
5884 // throw a NotSupportedError and stop.
5885 const js::Class
* clasp
= js::GetObjectClass(protoObject
);
5886 if (IsDOMIfaceAndProtoClass(clasp
)) {
5887 rv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
5891 JS::Rooted
<JSPropertyDescriptor
> descRoot(aCx
);
5892 JS::MutableHandle
<JSPropertyDescriptor
> desc(&descRoot
);
5893 if (!JS_GetPropertyDescriptor(aCx
, protoObject
, "constructor", desc
)) {
5894 rv
.Throw(NS_ERROR_UNEXPECTED
);
5898 // Check if non-configurable
5899 if (desc
.isPermanent()) {
5900 rv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
5904 JS::Handle
<JSObject
*> svgProto(
5905 SVGElementBinding::GetProtoObject(aCx
, global
));
5907 rv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
5911 JS::Rooted
<JSObject
*> protoProto(aCx
, protoObject
);
5913 // If PROTOTYPE's interface inherits from SVGElement, set NAMESPACE to SVG
5915 while (protoProto
) {
5916 if (protoProto
== htmlProto
) {
5920 if (protoProto
== svgProto
) {
5921 namespaceID
= kNameSpaceID_SVG
;
5925 if (!JS_GetPrototype(aCx
, protoProto
, &protoProto
)) {
5926 rv
.Throw(NS_ERROR_UNEXPECTED
);
5932 // If name was provided and not null...
5933 nsCOMPtr
<nsIAtom
> nameAtom
;
5934 if (!lcName
.IsEmpty()) {
5935 // Let BASE be the element interface for NAME and NAMESPACE.
5937 nameAtom
= do_GetAtom(lcName
);
5938 if (namespaceID
== kNameSpaceID_XHTML
) {
5939 nsIParserService
* ps
= nsContentUtils::GetParserService();
5941 rv
.Throw(NS_ERROR_UNEXPECTED
);
5946 ps
->HTMLCaseSensitiveAtomTagToId(nameAtom
) != eHTMLTag_userdefined
;
5948 known
= SVGElementFactory::Exists(nameAtom
);
5951 // If BASE does not exist or is an interface for a custom element, set ERROR
5952 // to InvalidName and stop.
5953 // If BASE exists, then it cannot be an interface for a custom element.
5955 rv
.Throw(NS_ERROR_DOM_SYNTAX_ERR
);
5959 // If NAMESPACE is SVG Namespace, set ERROR to InvalidName and stop.
5960 if (namespaceID
== kNameSpaceID_SVG
) {
5961 rv
.Throw(NS_ERROR_UNEXPECTED
);
5965 nameAtom
= typeAtom
;
5968 nsAutoPtr
<LifecycleCallbacks
> callbacksHolder(new LifecycleCallbacks());
5969 JS::RootedValue
rootedv(aCx
, JS::ObjectValue(*protoObject
));
5970 if (!callbacksHolder
->Init(aCx
, rootedv
)) {
5971 rv
.Throw(NS_ERROR_FAILURE
);
5975 // Associate the definition with the custom element.
5976 CustomElementHashKey
key(namespaceID
, typeAtom
);
5977 LifecycleCallbacks
* callbacks
= callbacksHolder
.forget();
5978 CustomElementDefinition
* definition
=
5979 new CustomElementDefinition(protoObject
,
5984 0 /* TODO dependent on HTML imports. Bug 877072 */);
5985 definitions
.Put(&key
, definition
);
5987 // Do element upgrade.
5988 nsAutoPtr
<nsTArray
<nsRefPtr
<Element
>>> candidates
;
5989 mRegistry
->mCandidatesMap
.RemoveAndForget(&key
, candidates
);
5991 for (size_t i
= 0; i
< candidates
->Length(); ++i
) {
5992 Element
*elem
= candidates
->ElementAt(i
);
5994 // Make sure that the element name matches the name in the definition.
5995 // (e.g. a definition for x-button extending button should match
5996 // <button is="x-button"> but not <x-button>.
5997 if (elem
->NodeInfo()->NameAtom() != nameAtom
) {
5998 // Skip over this element because definition does not apply.
6002 nsWrapperCache
* cache
;
6003 CallQueryInterface(elem
, &cache
);
6004 MOZ_ASSERT(cache
, "Element doesn't support wrapper cache?");
6006 JS::RootedObject
wrapper(aCx
);
6007 if ((wrapper
= cache
->GetWrapper())) {
6008 if (!JS_SetPrototype(aCx
, wrapper
, protoObject
)) {
6013 EnqueueLifecycleCallback(nsIDocument::eCreated
, elem
, nullptr, definition
);
6014 if (elem
->GetCurrentDoc()) {
6015 // Normally callbacks can not be enqueued until the created
6016 // callback has been invoked, however, the attached callback
6017 // in element upgrade is an exception so pretend the created
6018 // callback has been invoked.
6019 elem
->GetCustomElementData()->mCreatedCallbackInvoked
= true;
6021 EnqueueLifecycleCallback(nsIDocument::eAttached
, elem
, nullptr, definition
);
6026 // Create constructor to return. Store the name of the custom element as the
6027 // name of the function.
6028 JSFunction
* constructor
= JS_NewFunction(aCx
, nsDocument::CustomElementConstructor
, 0,
6029 JSFUN_CONSTRUCTOR
, JS::NullPtr(),
6030 NS_ConvertUTF16toUTF8(lcType
).get());
6032 rv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
6036 aRetval
.set(JS_GetFunctionObject(constructor
));
6040 nsDocument::UseRegistryFromDocument(nsIDocument
* aDocument
)
6042 nsDocument
* doc
= static_cast<nsDocument
*>(aDocument
);
6043 MOZ_ASSERT(!mRegistry
, "There should be no existing registry.");
6044 mRegistry
= doc
->mRegistry
;
6048 nsDocument::GetElementsByTagName(const nsAString
& aTagname
,
6049 nsIDOMNodeList
** aReturn
)
6051 nsRefPtr
<nsContentList
> list
= GetElementsByTagName(aTagname
);
6052 NS_ENSURE_TRUE(list
, NS_ERROR_OUT_OF_MEMORY
);
6054 // transfer ref to aReturn
6055 list
.forget(aReturn
);
6060 nsDocument::BlockedTrackingNodeCount() const
6062 return mBlockedTrackingNodes
.Length();
6065 already_AddRefed
<nsSimpleContentList
>
6066 nsDocument::BlockedTrackingNodes() const
6068 nsRefPtr
<nsSimpleContentList
> list
= new nsSimpleContentList(nullptr);
6070 nsTArray
<nsWeakPtr
> blockedTrackingNodes
;
6071 blockedTrackingNodes
= mBlockedTrackingNodes
;
6073 for (unsigned long i
= 0; i
< blockedTrackingNodes
.Length(); i
++) {
6074 nsWeakPtr weakNode
= blockedTrackingNodes
[i
];
6075 nsCOMPtr
<nsIContent
> node
= do_QueryReferent(weakNode
);
6076 // Consider only nodes to which we have managed to get strong references.
6077 // Coping with nullptrs since it's expected for nodes to disappear when
6078 // nobody else is referring to them.
6080 list
->AppendElement(node
);
6084 return list
.forget();
6087 already_AddRefed
<nsContentList
>
6088 nsIDocument::GetElementsByTagNameNS(const nsAString
& aNamespaceURI
,
6089 const nsAString
& aLocalName
,
6090 ErrorResult
& aResult
)
6092 int32_t nameSpaceId
= kNameSpaceID_Wildcard
;
6094 if (!aNamespaceURI
.EqualsLiteral("*")) {
6096 nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI
,
6098 if (aResult
.Failed()) {
6103 NS_ASSERTION(nameSpaceId
!= kNameSpaceID_Unknown
, "Unexpected namespace ID!");
6105 return NS_GetContentList(this, nameSpaceId
, aLocalName
);
6109 nsDocument::GetElementsByTagNameNS(const nsAString
& aNamespaceURI
,
6110 const nsAString
& aLocalName
,
6111 nsIDOMNodeList
** aReturn
)
6114 nsRefPtr
<nsContentList
> list
=
6115 nsIDocument::GetElementsByTagNameNS(aNamespaceURI
, aLocalName
, rv
);
6117 return rv
.ErrorCode();
6120 // transfer ref to aReturn
6121 list
.forget(aReturn
);
6126 nsDocument::GetAsync(bool *aAsync
)
6128 NS_ERROR("nsDocument::GetAsync() should be overriden by subclass!");
6130 return NS_ERROR_NOT_IMPLEMENTED
;
6134 nsDocument::SetAsync(bool aAsync
)
6136 NS_ERROR("nsDocument::SetAsync() should be overriden by subclass!");
6138 return NS_ERROR_NOT_IMPLEMENTED
;
6142 nsDocument::Load(const nsAString
& aUrl
, bool *aReturn
)
6144 NS_ERROR("nsDocument::Load() should be overriden by subclass!");
6146 return NS_ERROR_NOT_IMPLEMENTED
;
6150 nsDocument::GetStyleSheets(nsIDOMStyleSheetList
** aStyleSheets
)
6152 NS_ADDREF(*aStyleSheets
= StyleSheets());
6157 nsDocument::StyleSheets()
6159 if (!mDOMStyleSheets
) {
6160 mDOMStyleSheets
= new nsDOMStyleSheetList(this);
6162 return mDOMStyleSheets
;
6166 nsDocument::GetMozSelectedStyleSheetSet(nsAString
& aSheetSet
)
6168 nsIDocument::GetSelectedStyleSheetSet(aSheetSet
);
6173 nsIDocument::GetSelectedStyleSheetSet(nsAString
& aSheetSet
)
6175 aSheetSet
.Truncate();
6177 // Look through our sheets, find the selected set title
6178 int32_t count
= GetNumberOfStyleSheets();
6180 for (int32_t index
= 0; index
< count
; index
++) {
6181 nsIStyleSheet
* sheet
= GetStyleSheetAt(index
);
6182 NS_ASSERTION(sheet
, "Null sheet in sheet list!");
6184 nsCOMPtr
<nsIDOMStyleSheet
> domSheet
= do_QueryInterface(sheet
);
6185 NS_ASSERTION(domSheet
, "Sheet must QI to nsIDOMStyleSheet");
6187 domSheet
->GetDisabled(&disabled
);
6189 // Disabled sheets don't affect the currently selected set
6193 sheet
->GetTitle(title
);
6195 if (aSheetSet
.IsEmpty()) {
6197 } else if (!title
.IsEmpty() && !aSheetSet
.Equals(title
)) {
6198 // Sheets from multiple sets enabled; return null string, per spec.
6199 SetDOMStringToNull(aSheetSet
);
6206 nsDocument::SetMozSelectedStyleSheetSet(const nsAString
& aSheetSet
)
6208 SetSelectedStyleSheetSet(aSheetSet
);
6213 nsDocument::SetSelectedStyleSheetSet(const nsAString
& aSheetSet
)
6215 if (DOMStringIsNull(aSheetSet
)) {
6219 // Must update mLastStyleSheetSet before doing anything else with stylesheets
6221 mLastStyleSheetSet
= aSheetSet
;
6222 EnableStyleSheetsForSetInternal(aSheetSet
, true);
6226 nsDocument::GetLastStyleSheetSet(nsAString
& aSheetSet
)
6229 GetLastStyleSheetSet(sheetSet
);
6230 aSheetSet
= sheetSet
;
6235 nsDocument::GetLastStyleSheetSet(nsString
& aSheetSet
)
6237 aSheetSet
= mLastStyleSheetSet
;
6241 nsDocument::GetPreferredStyleSheetSet(nsAString
& aSheetSet
)
6243 nsIDocument::GetPreferredStyleSheetSet(aSheetSet
);
6248 nsIDocument::GetPreferredStyleSheetSet(nsAString
& aSheetSet
)
6250 GetHeaderData(nsGkAtoms::headerDefaultStyle
, aSheetSet
);
6254 nsDocument::GetStyleSheetSets(nsISupports
** aList
)
6256 NS_ADDREF(*aList
= StyleSheetSets());
6261 nsDocument::StyleSheetSets()
6263 if (!mStyleSheetSetList
) {
6264 mStyleSheetSetList
= new nsDOMStyleSheetSetList(this);
6266 return mStyleSheetSetList
;
6270 nsDocument::MozEnableStyleSheetsForSet(const nsAString
& aSheetSet
)
6272 EnableStyleSheetsForSet(aSheetSet
);
6277 nsDocument::EnableStyleSheetsForSet(const nsAString
& aSheetSet
)
6279 // Per spec, passing in null is a no-op.
6280 if (!DOMStringIsNull(aSheetSet
)) {
6281 // Note: must make sure to not change the CSSLoader's preferred sheet --
6282 // that value should be equal to either our lastStyleSheetSet (if that's
6283 // non-null) or to our preferredStyleSheetSet. And this method doesn't
6284 // change either of those.
6285 EnableStyleSheetsForSetInternal(aSheetSet
, false);
6290 nsDocument::EnableStyleSheetsForSetInternal(const nsAString
& aSheetSet
,
6291 bool aUpdateCSSLoader
)
6293 BeginUpdate(UPDATE_STYLE
);
6294 int32_t count
= GetNumberOfStyleSheets();
6296 for (int32_t index
= 0; index
< count
; index
++) {
6297 nsIStyleSheet
* sheet
= GetStyleSheetAt(index
);
6298 NS_ASSERTION(sheet
, "Null sheet in sheet list!");
6299 sheet
->GetTitle(title
);
6300 if (!title
.IsEmpty()) {
6301 sheet
->SetEnabled(title
.Equals(aSheetSet
));
6304 if (aUpdateCSSLoader
) {
6305 CSSLoader()->SetPreferredSheet(aSheetSet
);
6307 EndUpdate(UPDATE_STYLE
);
6311 nsDocument::GetCharacterSet(nsAString
& aCharacterSet
)
6313 nsIDocument::GetCharacterSet(aCharacterSet
);
6318 nsIDocument::GetCharacterSet(nsAString
& aCharacterSet
) const
6320 CopyASCIItoUTF16(GetDocumentCharacterSet(), aCharacterSet
);
6324 nsDocument::ImportNode(nsIDOMNode
* aImportedNode
,
6327 nsIDOMNode
** aResult
)
6335 nsCOMPtr
<nsINode
> imported
= do_QueryInterface(aImportedNode
);
6336 NS_ENSURE_TRUE(imported
, NS_ERROR_UNEXPECTED
);
6339 nsCOMPtr
<nsINode
> result
= nsIDocument::ImportNode(*imported
, aDeep
, rv
);
6341 return rv
.ErrorCode();
6344 NS_ADDREF(*aResult
= result
->AsDOMNode());
6348 already_AddRefed
<nsINode
>
6349 nsIDocument::ImportNode(nsINode
& aNode
, bool aDeep
, ErrorResult
& rv
) const
6351 nsINode
* imported
= &aNode
;
6353 switch (imported
->NodeType()) {
6354 case nsIDOMNode::ATTRIBUTE_NODE
:
6355 case nsIDOMNode::DOCUMENT_FRAGMENT_NODE
:
6356 case nsIDOMNode::ELEMENT_NODE
:
6357 case nsIDOMNode::PROCESSING_INSTRUCTION_NODE
:
6358 case nsIDOMNode::TEXT_NODE
:
6359 case nsIDOMNode::CDATA_SECTION_NODE
:
6360 case nsIDOMNode::COMMENT_NODE
:
6361 case nsIDOMNode::DOCUMENT_TYPE_NODE
:
6363 nsCOMPtr
<nsINode
> newNode
;
6364 nsCOMArray
<nsINode
> nodesWithProperties
;
6365 rv
= nsNodeUtils::Clone(imported
, aDeep
, mNodeInfoManager
,
6366 nodesWithProperties
, getter_AddRefs(newNode
));
6371 nsIDocument
*ownerDoc
= imported
->OwnerDoc();
6372 rv
= nsNodeUtils::CallUserDataHandlers(nodesWithProperties
, ownerDoc
,
6373 nsIDOMUserDataHandler::NODE_IMPORTED
,
6379 return newNode
.forget();
6383 NS_WARNING("Don't know how to clone this nodetype for importNode.");
6385 rv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
6393 nsDocument::LoadBindingDocument(const nsAString
& aURI
)
6396 nsIDocument::LoadBindingDocument(aURI
, rv
);
6397 return rv
.ErrorCode();
6401 nsIDocument::LoadBindingDocument(const nsAString
& aURI
, ErrorResult
& rv
)
6403 nsCOMPtr
<nsIURI
> uri
;
6404 rv
= NS_NewURI(getter_AddRefs(uri
), aURI
,
6405 mCharacterSet
.get(),
6411 // Note - This computation of subjectPrincipal isn't necessarily sensical.
6412 // It's just designed to preserve the old semantics during a mass-conversion
6414 nsCOMPtr
<nsIPrincipal
> subjectPrincipal
=
6415 nsContentUtils::GetCurrentJSContext() ? nsContentUtils::SubjectPrincipal()
6417 BindingManager()->LoadBindingDocument(this, uri
, subjectPrincipal
);
6421 nsDocument::GetBindingParent(nsIDOMNode
* aNode
, nsIDOMElement
** aResult
)
6423 nsCOMPtr
<nsINode
> node
= do_QueryInterface(aNode
);
6424 NS_ENSURE_ARG_POINTER(node
);
6426 Element
* bindingParent
= nsIDocument::GetBindingParent(*node
);
6427 nsCOMPtr
<nsIDOMElement
> retval
= do_QueryInterface(bindingParent
);
6428 retval
.forget(aResult
);
6433 nsIDocument::GetBindingParent(nsINode
& aNode
)
6435 nsCOMPtr
<nsIContent
> content(do_QueryInterface(&aNode
));
6439 nsIContent
* bindingParent
= content
->GetBindingParent();
6440 return bindingParent
? bindingParent
->AsElement() : nullptr;
6444 GetElementByAttribute(nsIContent
* aContent
, nsIAtom
* aAttrName
,
6445 const nsAString
& aAttrValue
, bool aUniversalMatch
)
6447 if (aUniversalMatch
? aContent
->HasAttr(kNameSpaceID_None
, aAttrName
) :
6448 aContent
->AttrValueIs(kNameSpaceID_None
, aAttrName
,
6449 aAttrValue
, eCaseMatters
)) {
6450 return aContent
->AsElement();
6453 for (nsIContent
* child
= aContent
->GetFirstChild();
6455 child
= child
->GetNextSibling()) {
6457 Element
* matchedElement
=
6458 GetElementByAttribute(child
, aAttrName
, aAttrValue
, aUniversalMatch
);
6460 return matchedElement
;
6467 nsDocument::GetAnonymousElementByAttribute(nsIContent
* aElement
,
6469 const nsAString
& aAttrValue
) const
6471 nsINodeList
* nodeList
= BindingManager()->GetAnonymousNodesFor(aElement
);
6475 uint32_t length
= 0;
6476 nodeList
->GetLength(&length
);
6478 bool universalMatch
= aAttrValue
.EqualsLiteral("*");
6480 for (uint32_t i
= 0; i
< length
; ++i
) {
6481 nsIContent
* current
= nodeList
->Item(i
);
6482 Element
* matchedElm
=
6483 GetElementByAttribute(current
, aAttrName
, aAttrValue
, universalMatch
);
6492 nsDocument::GetAnonymousElementByAttribute(nsIDOMElement
* aElement
,
6493 const nsAString
& aAttrName
,
6494 const nsAString
& aAttrValue
,
6495 nsIDOMElement
** aResult
)
6497 nsCOMPtr
<Element
> element
= do_QueryInterface(aElement
);
6498 NS_ENSURE_ARG_POINTER(element
);
6501 nsIDocument::GetAnonymousElementByAttribute(*element
, aAttrName
,
6503 nsCOMPtr
<nsIDOMElement
> retval
= do_QueryInterface(anonEl
);
6504 retval
.forget(aResult
);
6509 nsIDocument::GetAnonymousElementByAttribute(Element
& aElement
,
6510 const nsAString
& aAttrName
,
6511 const nsAString
& aAttrValue
)
6513 nsCOMPtr
<nsIAtom
> attribute
= do_GetAtom(aAttrName
);
6515 return GetAnonymousElementByAttribute(&aElement
, attribute
, aAttrValue
);
6520 nsDocument::GetAnonymousNodes(nsIDOMElement
* aElement
,
6521 nsIDOMNodeList
** aResult
)
6525 nsCOMPtr
<nsIContent
> content(do_QueryInterface(aElement
));
6526 return BindingManager()->GetAnonymousNodesFor(content
, aResult
);
6530 nsIDocument::GetAnonymousNodes(Element
& aElement
)
6532 return BindingManager()->GetAnonymousNodesFor(&aElement
);
6536 nsDocument::CreateRange(nsIDOMRange
** aReturn
)
6539 *aReturn
= nsIDocument::CreateRange(rv
).take();
6540 return rv
.ErrorCode();
6543 already_AddRefed
<nsRange
>
6544 nsIDocument::CreateRange(ErrorResult
& rv
)
6546 nsRefPtr
<nsRange
> range
= new nsRange(this);
6547 nsresult res
= range
->Set(this, 0, this, 0);
6548 if (NS_FAILED(res
)) {
6553 return range
.forget();
6557 nsDocument::CreateNodeIterator(nsIDOMNode
*aRoot
,
6558 uint32_t aWhatToShow
,
6559 nsIDOMNodeFilter
*aFilter
,
6560 uint8_t aOptionalArgc
,
6561 nsIDOMNodeIterator
**_retval
)
6565 if (!aOptionalArgc
) {
6566 aWhatToShow
= nsIDOMNodeFilter::SHOW_ALL
;
6570 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
6573 nsCOMPtr
<nsINode
> root
= do_QueryInterface(aRoot
);
6574 NS_ENSURE_TRUE(root
, NS_ERROR_UNEXPECTED
);
6577 NodeFilterHolder
holder(aFilter
);
6578 *_retval
= nsIDocument::CreateNodeIterator(*root
, aWhatToShow
, holder
,
6580 return rv
.ErrorCode();
6583 already_AddRefed
<NodeIterator
>
6584 nsIDocument::CreateNodeIterator(nsINode
& aRoot
, uint32_t aWhatToShow
,
6585 NodeFilter
* aFilter
,
6586 ErrorResult
& rv
) const
6588 NodeFilterHolder
holder(aFilter
);
6589 return CreateNodeIterator(aRoot
, aWhatToShow
, holder
, rv
);
6592 already_AddRefed
<NodeIterator
>
6593 nsIDocument::CreateNodeIterator(nsINode
& aRoot
, uint32_t aWhatToShow
,
6594 const NodeFilterHolder
& aFilter
,
6595 ErrorResult
& rv
) const
6597 nsINode
* root
= &aRoot
;
6598 nsRefPtr
<NodeIterator
> iterator
= new NodeIterator(root
, aWhatToShow
,
6600 return iterator
.forget();
6604 nsDocument::CreateTreeWalker(nsIDOMNode
*aRoot
,
6605 uint32_t aWhatToShow
,
6606 nsIDOMNodeFilter
*aFilter
,
6607 uint8_t aOptionalArgc
,
6608 nsIDOMTreeWalker
**_retval
)
6612 if (!aOptionalArgc
) {
6613 aWhatToShow
= nsIDOMNodeFilter::SHOW_ALL
;
6616 nsCOMPtr
<nsINode
> root
= do_QueryInterface(aRoot
);
6617 NS_ENSURE_TRUE(root
, NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
6620 NodeFilterHolder
holder(aFilter
);
6621 *_retval
= nsIDocument::CreateTreeWalker(*root
, aWhatToShow
, holder
,
6623 return rv
.ErrorCode();
6626 already_AddRefed
<TreeWalker
>
6627 nsIDocument::CreateTreeWalker(nsINode
& aRoot
, uint32_t aWhatToShow
,
6628 NodeFilter
* aFilter
,
6629 ErrorResult
& rv
) const
6631 NodeFilterHolder
holder(aFilter
);
6632 return CreateTreeWalker(aRoot
, aWhatToShow
, holder
, rv
);
6635 already_AddRefed
<TreeWalker
>
6636 nsIDocument::CreateTreeWalker(nsINode
& aRoot
, uint32_t aWhatToShow
,
6637 const NodeFilterHolder
& aFilter
,
6638 ErrorResult
& rv
) const
6640 nsINode
* root
= &aRoot
;
6641 nsRefPtr
<TreeWalker
> walker
= new TreeWalker(root
, aWhatToShow
, aFilter
);
6642 return walker
.forget();
6647 nsDocument::GetDefaultView(nsIDOMWindow
** aDefaultView
)
6649 *aDefaultView
= nullptr;
6650 nsCOMPtr
<nsPIDOMWindow
> win
= GetWindow();
6651 win
.forget(aDefaultView
);
6656 nsDocument::GetLocation(nsIDOMLocation
**_retval
)
6658 *_retval
= nsIDocument::GetLocation().take();
6662 already_AddRefed
<nsLocation
>
6663 nsIDocument::GetLocation() const
6665 nsCOMPtr
<nsIDOMWindow
> w
= do_QueryInterface(mScriptGlobalObject
);
6671 nsCOMPtr
<nsIDOMLocation
> loc
;
6672 w
->GetLocation(getter_AddRefs(loc
));
6673 return loc
.forget().downcast
<nsLocation
>();
6677 nsIDocument::GetHtmlElement() const
6679 Element
* rootElement
= GetRootElement();
6680 if (rootElement
&& rootElement
->IsHTML(nsGkAtoms::html
))
6686 nsIDocument::GetHtmlChildElement(nsIAtom
* aTag
)
6688 Element
* html
= GetHtmlElement();
6692 // Look for the element with aTag inside html. This needs to run
6693 // forwards to find the first such element.
6694 for (nsIContent
* child
= html
->GetFirstChild();
6696 child
= child
->GetNextSibling()) {
6697 if (child
->IsHTML(aTag
))
6698 return child
->AsElement();
6704 nsDocument::GetTitleContent(uint32_t aNamespace
)
6706 // mMayHaveTitleElement will have been set to true if any HTML or SVG
6707 // <title> element has been bound to this document. So if it's false,
6708 // we know there is nothing to do here. This avoids us having to search
6709 // the whole DOM if someone calls document.title on a large document
6711 if (!mMayHaveTitleElement
)
6714 nsRefPtr
<nsContentList
> list
=
6715 NS_GetContentList(this, aNamespace
, NS_LITERAL_STRING("title"));
6717 return list
->Item(0, false);
6721 nsDocument::GetTitleFromElement(uint32_t aNamespace
, nsAString
& aTitle
)
6723 nsIContent
* title
= GetTitleContent(aNamespace
);
6726 if(!nsContentUtils::GetNodeTextContent(title
, false, aTitle
))
6727 NS_RUNTIMEABORT("OOM");
6731 nsDocument::GetTitle(nsAString
& aTitle
)
6740 nsDocument::GetTitle(nsString
& aTitle
)
6744 nsIContent
*rootElement
= GetRootElement();
6750 switch (rootElement
->GetNameSpaceID()) {
6752 case kNameSpaceID_XUL
:
6753 rootElement
->GetAttr(kNameSpaceID_None
, nsGkAtoms::title
, tmp
);
6756 case kNameSpaceID_SVG
:
6757 if (rootElement
->Tag() == nsGkAtoms::svg
) {
6758 GetTitleFromElement(kNameSpaceID_SVG
, tmp
);
6760 } // else fall through
6762 GetTitleFromElement(kNameSpaceID_XHTML
, tmp
);
6766 tmp
.CompressWhitespace();
6771 nsDocument::SetTitle(const nsAString
& aTitle
)
6773 Element
*rootElement
= GetRootElement();
6777 switch (rootElement
->GetNameSpaceID()) {
6778 case kNameSpaceID_SVG
:
6779 return NS_OK
; // SVG doesn't support setting a title
6781 case kNameSpaceID_XUL
:
6782 return rootElement
->SetAttr(kNameSpaceID_None
, nsGkAtoms::title
,
6787 // Batch updates so that mutation events don't change "the title
6788 // element" under us
6789 mozAutoDocUpdate
updateBatch(this, UPDATE_CONTENT_MODEL
, true);
6791 nsIContent
* title
= GetTitleContent(kNameSpaceID_XHTML
);
6793 Element
*head
= GetHeadElement();
6798 nsRefPtr
<mozilla::dom::NodeInfo
> titleInfo
;
6799 titleInfo
= mNodeInfoManager
->GetNodeInfo(nsGkAtoms::title
, nullptr,
6801 nsIDOMNode::ELEMENT_NODE
);
6802 title
= NS_NewHTMLTitleElement(titleInfo
.forget());
6807 head
->AppendChildTo(title
, true);
6810 return nsContentUtils::SetNodeTextContent(title
, aTitle
, false);
6814 nsDocument::SetTitle(const nsAString
& aTitle
, ErrorResult
& rv
)
6816 rv
= SetTitle(aTitle
);
6820 nsDocument::NotifyPossibleTitleChange(bool aBoundTitleElement
)
6822 NS_ASSERTION(!mInUnlinkOrDeletion
|| !aBoundTitleElement
,
6823 "Setting a title while unlinking or destroying the element?");
6824 if (mInUnlinkOrDeletion
) {
6828 if (aBoundTitleElement
) {
6829 mMayHaveTitleElement
= true;
6831 if (mPendingTitleChangeEvent
.IsPending())
6834 nsRefPtr
<nsRunnableMethod
<nsDocument
, void, false> > event
=
6835 NS_NewNonOwningRunnableMethod(this,
6836 &nsDocument::DoNotifyPossibleTitleChange
);
6837 nsresult rv
= NS_DispatchToCurrentThread(event
);
6838 if (NS_SUCCEEDED(rv
)) {
6839 mPendingTitleChangeEvent
= event
;
6844 nsDocument::DoNotifyPossibleTitleChange()
6846 mPendingTitleChangeEvent
.Forget();
6847 mHaveFiredTitleChange
= true;
6852 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
6854 nsCOMPtr
<nsISupports
> container
=
6855 shell
->GetPresContext()->GetContainerWeak();
6857 nsCOMPtr
<nsIBaseWindow
> docShellWin
= do_QueryInterface(container
);
6859 docShellWin
->SetTitle(title
.get());
6864 // Fire a DOM event for the title change.
6865 nsContentUtils::DispatchChromeEvent(this, static_cast<nsIDocument
*>(this),
6866 NS_LITERAL_STRING("DOMTitleChanged"),
6870 already_AddRefed
<nsIBoxObject
>
6871 nsDocument::GetBoxObjectFor(Element
* aElement
, ErrorResult
& aRv
)
6874 aRv
.Throw(NS_ERROR_UNEXPECTED
);
6878 nsIDocument
* doc
= aElement
->OwnerDoc();
6880 aRv
.Throw(NS_ERROR_DOM_WRONG_DOCUMENT_ERR
);
6884 if (!mHasWarnedAboutBoxObjects
&& !aElement
->IsXUL()) {
6885 mHasWarnedAboutBoxObjects
= true;
6886 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag
,
6887 NS_LITERAL_CSTRING("BoxObjects"), this,
6888 nsContentUtils::eDOM_PROPERTIES
,
6889 "UseOfGetBoxObjectForWarning");
6892 if (!mBoxObjectTable
) {
6893 mBoxObjectTable
= new nsInterfaceHashtable
<nsPtrHashKey
<nsIContent
>, nsPIBoxObject
>(6);
6895 nsCOMPtr
<nsPIBoxObject
> boxObject
= mBoxObjectTable
->Get(aElement
);
6897 return boxObject
.forget();
6901 int32_t namespaceID
;
6902 nsCOMPtr
<nsIAtom
> tag
= BindingManager()->ResolveTag(aElement
, &namespaceID
);
6904 nsAutoCString
contractID("@mozilla.org/layout/xul-boxobject");
6905 if (namespaceID
== kNameSpaceID_XUL
) {
6906 if (tag
== nsGkAtoms::browser
||
6907 tag
== nsGkAtoms::editor
||
6908 tag
== nsGkAtoms::iframe
)
6909 contractID
+= "-container";
6910 else if (tag
== nsGkAtoms::menu
)
6911 contractID
+= "-menu";
6912 else if (tag
== nsGkAtoms::popup
||
6913 tag
== nsGkAtoms::menupopup
||
6914 tag
== nsGkAtoms::panel
||
6915 tag
== nsGkAtoms::tooltip
)
6916 contractID
+= "-popup";
6917 else if (tag
== nsGkAtoms::tree
)
6918 contractID
+= "-tree";
6919 else if (tag
== nsGkAtoms::listbox
)
6920 contractID
+= "-listbox";
6921 else if (tag
== nsGkAtoms::scrollbox
)
6922 contractID
+= "-scrollbox";
6926 nsCOMPtr
<nsPIBoxObject
> boxObject(do_CreateInstance(contractID
.get()));
6928 aRv
.Throw(NS_ERROR_FAILURE
);
6932 boxObject
->Init(aElement
);
6934 if (mBoxObjectTable
) {
6935 mBoxObjectTable
->Put(aElement
, boxObject
.get());
6938 return boxObject
.forget();
6942 nsDocument::ClearBoxObjectFor(nsIContent
* aContent
)
6944 if (mBoxObjectTable
) {
6945 nsPIBoxObject
*boxObject
= mBoxObjectTable
->GetWeak(aContent
);
6948 mBoxObjectTable
->Remove(aContent
);
6954 nsDocument::FlushSkinBindings()
6956 BindingManager()->FlushSkinBindings();
6960 nsDocument::InitializeFrameLoader(nsFrameLoader
* aLoader
)
6962 mInitializableFrameLoaders
.RemoveElement(aLoader
);
6963 // Don't even try to initialize.
6964 if (mInDestructor
) {
6965 NS_WARNING("Trying to initialize a frame loader while"
6966 "document is being deleted");
6967 return NS_ERROR_FAILURE
;
6970 mInitializableFrameLoaders
.AppendElement(aLoader
);
6971 if (!mFrameLoaderRunner
) {
6972 mFrameLoaderRunner
=
6973 NS_NewRunnableMethod(this, &nsDocument::MaybeInitializeFinalizeFrameLoaders
);
6974 NS_ENSURE_TRUE(mFrameLoaderRunner
, NS_ERROR_OUT_OF_MEMORY
);
6975 nsContentUtils::AddScriptRunner(mFrameLoaderRunner
);
6981 nsDocument::FinalizeFrameLoader(nsFrameLoader
* aLoader
)
6983 mInitializableFrameLoaders
.RemoveElement(aLoader
);
6984 if (mInDestructor
) {
6985 return NS_ERROR_FAILURE
;
6988 mFinalizableFrameLoaders
.AppendElement(aLoader
);
6989 if (!mFrameLoaderRunner
) {
6990 mFrameLoaderRunner
=
6991 NS_NewRunnableMethod(this, &nsDocument::MaybeInitializeFinalizeFrameLoaders
);
6992 NS_ENSURE_TRUE(mFrameLoaderRunner
, NS_ERROR_OUT_OF_MEMORY
);
6993 nsContentUtils::AddScriptRunner(mFrameLoaderRunner
);
6999 nsDocument::MaybeInitializeFinalizeFrameLoaders()
7001 if (mDelayFrameLoaderInitialization
|| mUpdateNestLevel
!= 0) {
7002 // This method will be recalled when mUpdateNestLevel drops to 0,
7003 // or when !mDelayFrameLoaderInitialization.
7004 mFrameLoaderRunner
= nullptr;
7008 // We're not in an update, but it is not safe to run scripts, so
7009 // postpone frameloader initialization and finalization.
7010 if (!nsContentUtils::IsSafeToRunScript()) {
7011 if (!mInDestructor
&& !mFrameLoaderRunner
&&
7012 (mInitializableFrameLoaders
.Length() ||
7013 mFinalizableFrameLoaders
.Length())) {
7014 mFrameLoaderRunner
=
7015 NS_NewRunnableMethod(this, &nsDocument::MaybeInitializeFinalizeFrameLoaders
);
7016 nsContentUtils::AddScriptRunner(mFrameLoaderRunner
);
7020 mFrameLoaderRunner
= nullptr;
7022 // Don't use a temporary array for mInitializableFrameLoaders, because
7023 // loading a frame may cause some other frameloader to be removed from the
7024 // array. But be careful to keep the loader alive when starting the load!
7025 while (mInitializableFrameLoaders
.Length()) {
7026 nsRefPtr
<nsFrameLoader
> loader
= mInitializableFrameLoaders
[0];
7027 mInitializableFrameLoaders
.RemoveElementAt(0);
7028 NS_ASSERTION(loader
, "null frameloader in the array?");
7029 loader
->ReallyStartLoading();
7032 uint32_t length
= mFinalizableFrameLoaders
.Length();
7034 nsTArray
<nsRefPtr
<nsFrameLoader
> > loaders
;
7035 mFinalizableFrameLoaders
.SwapElements(loaders
);
7036 for (uint32_t i
= 0; i
< length
; ++i
) {
7037 loaders
[i
]->Finalize();
7043 nsDocument::TryCancelFrameLoaderInitialization(nsIDocShell
* aShell
)
7045 uint32_t length
= mInitializableFrameLoaders
.Length();
7046 for (uint32_t i
= 0; i
< length
; ++i
) {
7047 if (mInitializableFrameLoaders
[i
]->GetExistingDocShell() == aShell
) {
7048 mInitializableFrameLoaders
.RemoveElementAt(i
);
7055 nsDocument::FrameLoaderScheduledToBeFinalized(nsIDocShell
* aShell
)
7058 uint32_t length
= mFinalizableFrameLoaders
.Length();
7059 for (uint32_t i
= 0; i
< length
; ++i
) {
7060 if (mFinalizableFrameLoaders
[i
]->GetExistingDocShell() == aShell
) {
7069 nsDocument::RequestExternalResource(nsIURI
* aURI
,
7070 nsINode
* aRequestingNode
,
7071 ExternalResourceLoad
** aPendingLoad
)
7073 NS_PRECONDITION(aURI
, "Must have a URI");
7074 NS_PRECONDITION(aRequestingNode
, "Must have a node");
7075 if (mDisplayDocument
) {
7076 return mDisplayDocument
->RequestExternalResource(aURI
,
7081 return mExternalResourceMap
.RequestResource(aURI
, aRequestingNode
,
7082 this, aPendingLoad
);
7086 nsDocument::EnumerateExternalResources(nsSubDocEnumFunc aCallback
, void* aData
)
7088 mExternalResourceMap
.EnumerateResources(aCallback
, aData
);
7091 nsSMILAnimationController
*
7092 nsDocument::GetAnimationController()
7094 // We create the animation controller lazily because most documents won't want
7095 // one and only SVG documents and the like will call this
7096 if (mAnimationController
)
7097 return mAnimationController
;
7098 // Refuse to create an Animation Controller for data documents.
7099 if (mLoadedAsData
|| mLoadedAsInteractiveData
)
7102 mAnimationController
= new nsSMILAnimationController(this);
7104 // If there's a presContext then check the animation mode and pause if
7106 nsIPresShell
*shell
= GetShell();
7107 if (mAnimationController
&& shell
) {
7108 nsPresContext
*context
= shell
->GetPresContext();
7110 context
->ImageAnimationMode() == imgIContainer::kDontAnimMode
) {
7111 mAnimationController
->Pause(nsSMILTimeContainer::PAUSE_USERPREF
);
7115 // If we're hidden (or being hidden), notify the newly-created animation
7116 // controller. (Skip this check for SVG-as-an-image documents, though,
7117 // because they don't get OnPageShow / OnPageHide calls).
7118 if (!mIsShowing
&& !mIsBeingUsedAsImage
) {
7119 mAnimationController
->OnPageHide();
7122 return mAnimationController
;
7126 * Retrieve the "direction" property of the document.
7131 nsDocument::GetDir(nsAString
& aDirection
)
7133 nsIDocument::GetDir(aDirection
);
7138 nsIDocument::GetDir(nsAString
& aDirection
) const
7140 aDirection
.Truncate();
7141 Element
* rootElement
= GetHtmlElement();
7143 static_cast<nsGenericHTMLElement
*>(rootElement
)->GetDir(aDirection
);
7148 * Set the "direction" property of the document.
7153 nsDocument::SetDir(const nsAString
& aDirection
)
7155 nsIDocument::SetDir(aDirection
);
7160 nsIDocument::SetDir(const nsAString
& aDirection
)
7162 Element
* rootElement
= GetHtmlElement();
7164 rootElement
->SetAttr(kNameSpaceID_None
, nsGkAtoms::dir
,
7170 nsDocument::GetInputEncoding(nsAString
& aInputEncoding
)
7172 nsIDocument::GetInputEncoding(aInputEncoding
);
7177 nsIDocument::GetInputEncoding(nsAString
& aInputEncoding
)
7179 // Not const function, because WarnOnceAbout is not a const method
7180 WarnOnceAbout(eInputEncoding
);
7181 if (mHaveInputEncoding
) {
7182 return GetCharacterSet(aInputEncoding
);
7185 SetDOMStringToNull(aInputEncoding
);
7189 nsDocument::GetMozSyntheticDocument(bool *aSyntheticDocument
)
7191 *aSyntheticDocument
= mIsSyntheticDocument
;
7196 nsDocument::GetDocumentURI(nsAString
& aDocumentURI
)
7199 nsIDocument::GetDocumentURI(temp
);
7200 aDocumentURI
= temp
;
7205 nsIDocument::GetDocumentURI(nsString
& aDocumentURI
) const
7209 mDocumentURI
->GetSpec(uri
);
7210 CopyUTF8toUTF16(uri
, aDocumentURI
);
7212 aDocumentURI
.Truncate();
7218 nsDocument::GetURL(nsAString
& aURL
)
7220 return GetDocumentURI(aURL
);
7224 nsIDocument::GetURL(nsString
& aURL
) const
7226 return GetDocumentURI(aURL
);
7230 nsIDocument::GetDocumentURIFromJS(nsString
& aDocumentURI
) const
7232 if (!mChromeXHRDocURI
|| !nsContentUtils::IsCallerChrome()) {
7233 return GetDocumentURI(aDocumentURI
);
7237 mChromeXHRDocURI
->GetSpec(uri
);
7238 CopyUTF8toUTF16(uri
, aDocumentURI
);
7242 nsIDocument::GetDocumentURIObject() const
7244 if (!mChromeXHRDocURI
) {
7245 return GetDocumentURI();
7248 return mChromeXHRDocURI
;
7252 // readonly attribute DOMString compatMode;
7253 // Returns "BackCompat" if we are in quirks mode, "CSS1Compat" if we are
7254 // in almost standards or full standards mode. See bug 105640. This was
7255 // implemented to match MSIE's compatMode property.
7257 nsDocument::GetCompatMode(nsAString
& aCompatMode
)
7260 nsIDocument::GetCompatMode(temp
);
7266 nsIDocument::GetCompatMode(nsString
& aCompatMode
) const
7268 NS_ASSERTION(mCompatMode
== eCompatibility_NavQuirks
||
7269 mCompatMode
== eCompatibility_AlmostStandards
||
7270 mCompatMode
== eCompatibility_FullStandards
,
7271 "mCompatMode is neither quirks nor strict for this document");
7273 if (mCompatMode
== eCompatibility_NavQuirks
) {
7274 aCompatMode
.AssignLiteral("BackCompat");
7276 aCompatMode
.AssignLiteral("CSS1Compat");
7280 static void BlastSubtreeToPieces(nsINode
*aNode
);
7283 BlastFunc(nsAttrHashKey::KeyType aKey
, Attr
*aData
, void* aUserArg
)
7285 nsCOMPtr
<nsIAttribute
> *attr
=
7286 static_cast<nsCOMPtr
<nsIAttribute
>*>(aUserArg
);
7290 NS_ASSERTION(attr
->get(),
7291 "non-nsIAttribute somehow made it into the hashmap?!");
7293 return PL_DHASH_STOP
;
7297 BlastSubtreeToPieces(nsINode
*aNode
)
7299 if (aNode
->IsElement()) {
7300 Element
*element
= aNode
->AsElement();
7301 const nsDOMAttributeMap
*map
= element
->GetAttributeMap();
7303 nsCOMPtr
<nsIAttribute
> attr
;
7304 while (map
->Enumerate(BlastFunc
, &attr
) > 0) {
7305 BlastSubtreeToPieces(attr
);
7310 element
->UnsetAttr(attr
->NodeInfo()->NamespaceID(),
7311 attr
->NodeInfo()->NameAtom(),
7314 // XXX Should we abort here?
7315 NS_ASSERTION(NS_SUCCEEDED(rv
), "Uhoh, UnsetAttr shouldn't fail!");
7320 uint32_t count
= aNode
->GetChildCount();
7321 for (uint32_t i
= 0; i
< count
; ++i
) {
7322 BlastSubtreeToPieces(aNode
->GetFirstChild());
7323 aNode
->RemoveChildAt(0, false);
7328 class nsUserDataCaller
: public nsRunnable
7331 nsUserDataCaller(nsCOMArray
<nsINode
>& aNodesWithProperties
,
7332 nsIDocument
* aOwnerDoc
)
7333 : mNodesWithProperties(aNodesWithProperties
),
7334 mOwnerDoc(aOwnerDoc
)
7340 nsNodeUtils::CallUserDataHandlers(mNodesWithProperties
, mOwnerDoc
,
7341 nsIDOMUserDataHandler::NODE_ADOPTED
,
7347 nsCOMArray
<nsINode
> mNodesWithProperties
;
7348 nsCOMPtr
<nsIDocument
> mOwnerDoc
;
7352 nsDocument::AdoptNode(nsIDOMNode
*aAdoptedNode
, nsIDOMNode
**aResult
)
7356 nsCOMPtr
<nsINode
> adoptedNode
= do_QueryInterface(aAdoptedNode
);
7357 NS_ENSURE_TRUE(adoptedNode
, NS_ERROR_UNEXPECTED
);
7360 nsINode
* result
= nsIDocument::AdoptNode(*adoptedNode
, rv
);
7362 return rv
.ErrorCode();
7365 NS_ADDREF(*aResult
= result
->AsDOMNode());
7370 nsIDocument::AdoptNode(nsINode
& aAdoptedNode
, ErrorResult
& rv
)
7372 nsINode
* adoptedNode
= &aAdoptedNode
;
7374 // Scope firing mutation events so that we don't carry any state that
7377 nsINode
* parent
= adoptedNode
->GetParentNode();
7379 nsContentUtils::MaybeFireNodeRemoved(adoptedNode
, parent
,
7380 adoptedNode
->OwnerDoc());
7384 nsAutoScriptBlocker scriptBlocker
;
7386 switch (adoptedNode
->NodeType()) {
7387 case nsIDOMNode::ATTRIBUTE_NODE
:
7389 // Remove from ownerElement.
7390 nsRefPtr
<Attr
> adoptedAttr
= static_cast<Attr
*>(adoptedNode
);
7392 nsCOMPtr
<Element
> ownerElement
= adoptedAttr
->GetOwnerElement(rv
);
7398 nsRefPtr
<Attr
> newAttr
=
7399 ownerElement
->RemoveAttributeNode(*adoptedAttr
, rv
);
7404 newAttr
.swap(adoptedAttr
);
7409 case nsIDOMNode::DOCUMENT_FRAGMENT_NODE
:
7410 case nsIDOMNode::ELEMENT_NODE
:
7411 case nsIDOMNode::PROCESSING_INSTRUCTION_NODE
:
7412 case nsIDOMNode::TEXT_NODE
:
7413 case nsIDOMNode::CDATA_SECTION_NODE
:
7414 case nsIDOMNode::COMMENT_NODE
:
7415 case nsIDOMNode::DOCUMENT_TYPE_NODE
:
7417 // Don't allow adopting a node's anonymous subtree out from under it.
7418 if (adoptedNode
->AsContent()->IsRootOfAnonymousSubtree()) {
7419 rv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
7423 // We don't want to adopt an element into its own contentDocument or into
7424 // a descendant contentDocument, so we check if the frameElement of this
7425 // document or any of its parents is the adopted node or one of its
7427 nsIDocument
*doc
= this;
7429 nsPIDOMWindow
*win
= doc
->GetWindow();
7431 nsCOMPtr
<nsINode
> node
= win
->GetFrameElementInternal();
7433 nsContentUtils::ContentIsDescendantOf(node
, adoptedNode
)) {
7434 rv
.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
);
7438 } while ((doc
= doc
->GetParentDocument()));
7440 // Remove from parent.
7441 nsCOMPtr
<nsINode
> parent
= adoptedNode
->GetParentNode();
7443 int32_t idx
= parent
->IndexOf(adoptedNode
);
7444 MOZ_ASSERT(idx
>= 0);
7445 parent
->RemoveChildAt(idx
, true);
7447 MOZ_ASSERT(!adoptedNode
->IsInDoc());
7449 // If we're adopting a node that's not in a document, it might still
7450 // have a binding applied. Remove the binding from the element now
7451 // that it's getting adopted into a new document.
7452 // TODO Fully tear down the binding.
7453 adoptedNode
->AsContent()->SetXBLBinding(nullptr);
7458 case nsIDOMNode::DOCUMENT_NODE
:
7460 rv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
7465 NS_WARNING("Don't know how to adopt this nodetype for adoptNode.");
7467 rv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
7472 nsCOMPtr
<nsIDocument
> oldDocument
= adoptedNode
->OwnerDoc();
7473 bool sameDocument
= oldDocument
== this;
7476 JS::Rooted
<JSObject
*> newScope(cx
, nullptr);
7477 if (!sameDocument
) {
7478 newScope
= GetWrapper();
7479 if (!newScope
&& GetScopeObject() && GetScopeObject()->GetGlobalJSObject()) {
7480 // Make sure cx is in a semi-sane compartment before we call WrapNative.
7481 // It's kind of irrelevant, given that we're passing aAllowWrapping =
7482 // false, and documents should always insist on being wrapped in an
7483 // canonical scope. But we try to pass something sane anyway.
7484 JSAutoCompartment
ac(cx
, GetScopeObject()->GetGlobalJSObject());
7485 JS::Rooted
<JS::Value
> v(cx
);
7486 rv
= nsContentUtils::WrapNative(cx
, this, this, &v
,
7487 /* aAllowWrapping = */ false);
7490 newScope
= &v
.toObject();
7494 nsCOMArray
<nsINode
> nodesWithProperties
;
7495 rv
= nsNodeUtils::Adopt(adoptedNode
, sameDocument
? nullptr : mNodeInfoManager
,
7496 newScope
, nodesWithProperties
);
7498 // Disconnect all nodes from their parents, since some have the old document
7499 // as their ownerDocument and some have this as their ownerDocument.
7500 BlastSubtreeToPieces(adoptedNode
);
7502 if (!sameDocument
&& oldDocument
) {
7503 uint32_t count
= nodesWithProperties
.Count();
7504 for (uint32_t j
= 0; j
< oldDocument
->GetPropertyTableCount(); ++j
) {
7505 for (uint32_t i
= 0; i
< count
; ++i
) {
7506 // Remove all properties.
7507 oldDocument
->PropertyTable(j
)->
7508 DeleteAllPropertiesFor(nodesWithProperties
[i
]);
7516 uint32_t count
= nodesWithProperties
.Count();
7517 if (!sameDocument
&& oldDocument
) {
7518 for (uint32_t j
= 0; j
< oldDocument
->GetPropertyTableCount(); ++j
) {
7519 nsPropertyTable
*oldTable
= oldDocument
->PropertyTable(j
);
7520 nsPropertyTable
*newTable
= PropertyTable(j
);
7521 for (uint32_t i
= 0; i
< count
; ++i
) {
7522 rv
= oldTable
->TransferOrDeleteAllPropertiesFor(nodesWithProperties
[i
],
7528 // Disconnect all nodes from their parents.
7529 BlastSubtreeToPieces(adoptedNode
);
7535 if (nodesWithProperties
.Count()) {
7536 nsContentUtils::AddScriptRunner(new nsUserDataCaller(nodesWithProperties
,
7540 NS_ASSERTION(adoptedNode
->OwnerDoc() == this,
7541 "Should still be in the document we just got adopted into");
7547 nsDocument::GetViewportInfo(const ScreenIntSize
& aDisplaySize
)
7549 // Compute the CSS-to-LayoutDevice pixel scale as the product of the
7550 // widget scale and the full zoom.
7551 nsPresContext
* context
= mPresShell
->GetPresContext();
7552 float fullZoom
= context
? context
->GetFullZoom() : 1.0;
7553 fullZoom
= (fullZoom
== 0.0) ? 1.0 : fullZoom
;
7554 nsIWidget
*widget
= nsContentUtils::WidgetForDocument(this);
7555 float widgetScale
= widget
? widget
->GetDefaultScale().scale
: 1.0f
;
7556 CSSToLayoutDeviceScale
layoutDeviceScale(widgetScale
* fullZoom
);
7558 CSSToScreenScale defaultScale
= layoutDeviceScale
7559 * LayoutDeviceToScreenScale(1.0);
7561 // In cases where the width of the CSS viewport is less than or equal to the width
7562 // of the display (i.e. width <= device-width) then we disable double-tap-to-zoom
7563 // behaviour. See bug 941995 for details.
7565 switch (mViewportType
) {
7566 case DisplayWidthHeight
:
7567 return nsViewportInfo(aDisplaySize
,
7570 /*allowDoubleTapZoom*/ true);
7571 case DisplayWidthHeightNoZoom
:
7572 return nsViewportInfo(aDisplaySize
,
7574 /*allowZoom*/ false,
7575 /*allowDoubleTapZoom*/ false);
7578 nsAutoString viewport
;
7579 GetHeaderData(nsGkAtoms::viewport
, viewport
);
7580 if (viewport
.IsEmpty()) {
7581 // If the docType specifies that we are on a site optimized for mobile,
7582 // then we want to return specially crafted defaults for the viewport info.
7583 nsCOMPtr
<nsIDOMDocumentType
> docType
;
7584 nsresult rv
= GetDoctype(getter_AddRefs(docType
));
7585 if (NS_SUCCEEDED(rv
) && docType
) {
7587 rv
= docType
->GetPublicId(docId
);
7588 if (NS_SUCCEEDED(rv
)) {
7589 if ((docId
.Find("WAP") != -1) ||
7590 (docId
.Find("Mobile") != -1) ||
7591 (docId
.Find("WML") != -1))
7593 // We're making an assumption that the docType can't change here
7594 mViewportType
= DisplayWidthHeight
;
7595 return nsViewportInfo(aDisplaySize
,
7598 /*allowDoubleTapZoom*/false);
7603 nsAutoString handheldFriendly
;
7604 GetHeaderData(nsGkAtoms::handheldFriendly
, handheldFriendly
);
7605 if (handheldFriendly
.EqualsLiteral("true")) {
7606 mViewportType
= DisplayWidthHeight
;
7607 return nsViewportInfo(aDisplaySize
,
7610 /*allowDoubleTapZoom*/false);
7614 nsAutoString minScaleStr
;
7615 GetHeaderData(nsGkAtoms::viewport_minimum_scale
, minScaleStr
);
7618 mScaleMinFloat
= LayoutDeviceToScreenScale(minScaleStr
.ToFloat(&errorCode
));
7620 if (NS_FAILED(errorCode
)) {
7621 mScaleMinFloat
= kViewportMinScale
;
7624 mScaleMinFloat
= mozilla::clamped(
7625 mScaleMinFloat
, kViewportMinScale
, kViewportMaxScale
);
7627 nsAutoString maxScaleStr
;
7628 GetHeaderData(nsGkAtoms::viewport_maximum_scale
, maxScaleStr
);
7630 // We define a special error code variable for the scale and max scale,
7631 // because they are used later (see the width calculations).
7632 nsresult scaleMaxErrorCode
;
7633 mScaleMaxFloat
= LayoutDeviceToScreenScale(maxScaleStr
.ToFloat(&scaleMaxErrorCode
));
7635 if (NS_FAILED(scaleMaxErrorCode
)) {
7636 mScaleMaxFloat
= kViewportMaxScale
;
7639 mScaleMaxFloat
= mozilla::clamped(
7640 mScaleMaxFloat
, kViewportMinScale
, kViewportMaxScale
);
7642 nsAutoString scaleStr
;
7643 GetHeaderData(nsGkAtoms::viewport_initial_scale
, scaleStr
);
7645 nsresult scaleErrorCode
;
7646 mScaleFloat
= LayoutDeviceToScreenScale(scaleStr
.ToFloat(&scaleErrorCode
));
7648 nsAutoString widthStr
, heightStr
;
7650 GetHeaderData(nsGkAtoms::viewport_height
, heightStr
);
7651 GetHeaderData(nsGkAtoms::viewport_width
, widthStr
);
7655 if (widthStr
.EqualsLiteral("device-width")) {
7659 if (widthStr
.IsEmpty() &&
7660 (heightStr
.EqualsLiteral("device-height") ||
7661 (mScaleFloat
.scale
== 1.0)))
7666 nsresult widthErrorCode
, heightErrorCode
;
7667 mViewportSize
.width
= widthStr
.ToInteger(&widthErrorCode
);
7668 mViewportSize
.height
= heightStr
.ToInteger(&heightErrorCode
);
7670 // If width or height has not been set to a valid number by this point,
7671 // fall back to a default value.
7672 mValidWidth
= (!widthStr
.IsEmpty() && NS_SUCCEEDED(widthErrorCode
) && mViewportSize
.width
> 0);
7673 mValidHeight
= (!heightStr
.IsEmpty() && NS_SUCCEEDED(heightErrorCode
) && mViewportSize
.height
> 0);
7676 nsAutoString userScalable
;
7677 GetHeaderData(nsGkAtoms::viewport_user_scalable
, userScalable
);
7679 if ((userScalable
.EqualsLiteral("0")) ||
7680 (userScalable
.EqualsLiteral("no")) ||
7681 (userScalable
.EqualsLiteral("false"))) {
7684 mAllowDoubleTapZoom
= mAllowZoom
;
7686 mScaleStrEmpty
= scaleStr
.IsEmpty();
7687 mWidthStrEmpty
= widthStr
.IsEmpty();
7688 mValidScaleFloat
= !scaleStr
.IsEmpty() && NS_SUCCEEDED(scaleErrorCode
);
7689 mValidMaxScale
= !maxScaleStr
.IsEmpty() && NS_SUCCEEDED(scaleMaxErrorCode
);
7691 mViewportType
= Specified
;
7695 CSSSize size
= mViewportSize
;
7698 if (mValidHeight
&& !aDisplaySize
.IsEmpty()) {
7699 size
.width
= size
.height
* aDisplaySize
.width
/ aDisplaySize
.height
;
7701 // Stretch CSS pixel size of viewport to keep device pixel size
7702 // unchanged after full zoom applied.
7704 size
.width
= Preferences::GetInt("browser.viewport.desktopWidth",
7705 kViewportDefaultScreenWidth
) / fullZoom
;
7709 if (!mValidHeight
) {
7710 if (!aDisplaySize
.IsEmpty()) {
7711 size
.height
= size
.width
* aDisplaySize
.height
/ aDisplaySize
.width
;
7713 size
.height
= size
.width
;
7717 CSSToScreenScale scaleFloat
= mScaleFloat
* layoutDeviceScale
;
7718 CSSToScreenScale scaleMinFloat
= mScaleMinFloat
* layoutDeviceScale
;
7719 CSSToScreenScale scaleMaxFloat
= mScaleMaxFloat
* layoutDeviceScale
;
7722 // aDisplaySize is in screen pixels; convert them to CSS pixels for the viewport size.
7723 CSSToScreenScale defaultPixelScale
= layoutDeviceScale
* LayoutDeviceToScreenScale(1.0f
);
7724 size
= ScreenSize(aDisplaySize
) / defaultPixelScale
;
7727 size
.width
= clamped(size
.width
, float(kViewportMinSize
.width
), float(kViewportMaxSize
.width
));
7729 // Also recalculate the default zoom, if it wasn't specified in the metadata,
7730 // and the width is specified.
7731 if (mScaleStrEmpty
&& !mWidthStrEmpty
) {
7732 CSSToScreenScale
defaultScale(float(aDisplaySize
.width
) / size
.width
);
7733 scaleFloat
= (scaleFloat
> defaultScale
) ? scaleFloat
: defaultScale
;
7736 size
.height
= clamped(size
.height
, float(kViewportMinSize
.height
), float(kViewportMaxSize
.height
));
7738 // We need to perform a conversion, but only if the initial or maximum
7739 // scale were set explicitly by the user.
7740 if (mValidScaleFloat
) {
7741 CSSSize displaySize
= ScreenSize(aDisplaySize
) / scaleFloat
;
7742 size
.width
= std::max(size
.width
, displaySize
.width
);
7743 size
.height
= std::max(size
.height
, displaySize
.height
);
7744 } else if (mValidMaxScale
) {
7745 CSSSize displaySize
= ScreenSize(aDisplaySize
) / scaleMaxFloat
;
7746 size
.width
= std::max(size
.width
, displaySize
.width
);
7747 size
.height
= std::max(size
.height
, displaySize
.height
);
7750 return nsViewportInfo(scaleFloat
, scaleMinFloat
, scaleMaxFloat
, size
,
7751 mAutoSize
, mAllowZoom
, mAllowDoubleTapZoom
);
7755 EventListenerManager
*
7756 nsDocument::GetOrCreateListenerManager()
7758 if (!mListenerManager
) {
7760 new EventListenerManager(static_cast<EventTarget
*>(this));
7761 SetFlags(NODE_HAS_LISTENERMANAGER
);
7764 return mListenerManager
;
7767 EventListenerManager
*
7768 nsDocument::GetExistingListenerManager() const
7770 return mListenerManager
;
7774 nsDocument::PreHandleEvent(EventChainPreVisitor
& aVisitor
)
7776 aVisitor
.mCanHandle
= true;
7777 // FIXME! This is a hack to make middle mouse paste working also in Editor.
7779 aVisitor
.mForceContentDispatch
= true;
7781 // Load events must not propagate to |window| object, see bug 335251.
7782 if (aVisitor
.mEvent
->message
!= NS_LOAD
) {
7783 nsGlobalWindow
* window
= static_cast<nsGlobalWindow
*>(GetWindow());
7784 aVisitor
.mParentTarget
=
7785 window
? window
->GetTargetForEventTargetChain() : nullptr;
7791 nsDocument::CreateEvent(const nsAString
& aEventType
, nsIDOMEvent
** aReturn
)
7793 NS_ENSURE_ARG_POINTER(aReturn
);
7795 *aReturn
= nsIDocument::CreateEvent(aEventType
, rv
).take();
7796 return rv
.ErrorCode();
7799 already_AddRefed
<Event
>
7800 nsIDocument::CreateEvent(const nsAString
& aEventType
, ErrorResult
& rv
) const
7802 nsIPresShell
*shell
= GetShell();
7804 nsPresContext
*presContext
= nullptr;
7807 // Retrieve the context
7808 presContext
= shell
->GetPresContext();
7811 // Create event even without presContext.
7812 nsCOMPtr
<nsIDOMEvent
> ev
;
7813 rv
= EventDispatcher::CreateEvent(const_cast<nsIDocument
*>(this),
7814 presContext
, nullptr, aEventType
,
7815 getter_AddRefs(ev
));
7819 WidgetEvent
* e
= ev
->GetInternalNSEvent();
7820 e
->mFlags
.mBubbles
= false;
7821 e
->mFlags
.mCancelable
= false;
7822 return dont_AddRef(ev
.forget().take()->InternalDOMEvent());
7826 nsDocument::FlushPendingNotifications(mozFlushType aType
)
7828 nsDocumentOnStack
dos(this);
7830 // We need to flush the sink for non-HTML documents (because the XML
7831 // parser still does insertion with deferred notifications). We
7832 // also need to flush the sink if this is a layout-related flush, to
7833 // make sure that layout is started as needed. But we can skip that
7834 // part if we have no presshell or if it's already done an initial
7837 (aType
> Flush_ContentAndNotify
&& mPresShell
&&
7838 !mPresShell
->DidInitialize())) &&
7839 (mParser
|| mWeakSink
)) {
7840 nsCOMPtr
<nsIContentSink
> sink
;
7842 sink
= mParser
->GetContentSink();
7844 sink
= do_QueryReferent(mWeakSink
);
7846 mWeakSink
= nullptr;
7849 // Determine if it is safe to flush the sink notifications
7850 // by determining if it safe to flush all the presshells.
7851 if (sink
&& (aType
== Flush_Content
|| IsSafeToFlush())) {
7852 sink
->FlushPendingNotifications(aType
);
7856 // Should we be flushing pending binding constructors in here?
7858 if (aType
<= Flush_ContentAndNotify
) {
7859 // Nothing to do here
7863 // If we have a parent we must flush the parent too to ensure that our
7864 // container is reflowed if its size was changed. But if it's not safe to
7865 // flush ourselves, then don't flush the parent, since that can cause things
7866 // like resizes of our frame's widget, which we can't handle while flushing
7868 // Since media queries mean that a size change of our container can
7869 // affect style, we need to promote a style flush on ourself to a
7870 // layout flush on our parent, since we need our container to be the
7871 // correct size to determine the correct style.
7872 if (mParentDocument
&& IsSafeToFlush()) {
7873 mozFlushType parentType
= aType
;
7874 if (aType
>= Flush_Style
)
7875 parentType
= std::max(Flush_Layout
, aType
);
7876 mParentDocument
->FlushPendingNotifications(parentType
);
7879 // We can optimize away getting our presshell and calling
7880 // FlushPendingNotifications on it if we don't need a flush of the sort we're
7881 // looking at. The one exception is if mInFlush is true, because in that
7882 // case we might have set mNeedStyleFlush and mNeedLayoutFlush to false
7883 // already but the presshell hasn't actually done the corresponding work yet.
7884 // So if mInFlush and reentering this code, we need to flush the presshell.
7885 if (mNeedStyleFlush
||
7886 (mNeedLayoutFlush
&& aType
>= Flush_InterruptibleLayout
) ||
7887 aType
>= Flush_Display
||
7889 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
7891 mNeedStyleFlush
= false;
7892 mNeedLayoutFlush
= mNeedLayoutFlush
&& (aType
< Flush_InterruptibleLayout
);
7893 // mInFlush is a bitfield, so can't us AutoRestore here. But we
7894 // need to keep track of multi-level reentry correctly, so need
7895 // to restore the old mInFlush value.
7896 bool oldInFlush
= mInFlush
;
7898 shell
->FlushPendingNotifications(aType
);
7899 mInFlush
= oldInFlush
;
7905 Copy(nsIDocument
* aDocument
, void* aData
)
7907 nsTArray
<nsCOMPtr
<nsIDocument
> >* resources
=
7908 static_cast<nsTArray
<nsCOMPtr
<nsIDocument
> >* >(aData
);
7909 resources
->AppendElement(aDocument
);
7914 nsDocument::FlushExternalResources(mozFlushType aType
)
7916 NS_ASSERTION(aType
>= Flush_Style
,
7917 "should only need to flush for style or higher in external resources");
7918 if (GetDisplayDocument()) {
7921 nsTArray
<nsCOMPtr
<nsIDocument
> > resources
;
7922 EnumerateExternalResources(Copy
, &resources
);
7924 for (uint32_t i
= 0; i
< resources
.Length(); i
++) {
7925 resources
[i
]->FlushPendingNotifications(aType
);
7930 nsDocument::SetXMLDeclaration(const char16_t
*aVersion
,
7931 const char16_t
*aEncoding
,
7932 const int32_t aStandalone
)
7934 if (!aVersion
|| *aVersion
== '\0') {
7935 mXMLDeclarationBits
= 0;
7939 mXMLDeclarationBits
= XML_DECLARATION_BITS_DECLARATION_EXISTS
;
7941 if (aEncoding
&& *aEncoding
!= '\0') {
7942 mXMLDeclarationBits
|= XML_DECLARATION_BITS_ENCODING_EXISTS
;
7945 if (aStandalone
== 1) {
7946 mXMLDeclarationBits
|= XML_DECLARATION_BITS_STANDALONE_EXISTS
|
7947 XML_DECLARATION_BITS_STANDALONE_YES
;
7949 else if (aStandalone
== 0) {
7950 mXMLDeclarationBits
|= XML_DECLARATION_BITS_STANDALONE_EXISTS
;
7955 nsDocument::GetXMLDeclaration(nsAString
& aVersion
, nsAString
& aEncoding
,
7956 nsAString
& aStandalone
)
7958 aVersion
.Truncate();
7959 aEncoding
.Truncate();
7960 aStandalone
.Truncate();
7962 if (!(mXMLDeclarationBits
& XML_DECLARATION_BITS_DECLARATION_EXISTS
)) {
7966 // always until we start supporting 1.1 etc.
7967 aVersion
.AssignLiteral("1.0");
7969 if (mXMLDeclarationBits
& XML_DECLARATION_BITS_ENCODING_EXISTS
) {
7970 // This is what we have stored, not necessarily what was written
7972 GetCharacterSet(aEncoding
);
7975 if (mXMLDeclarationBits
& XML_DECLARATION_BITS_STANDALONE_EXISTS
) {
7976 if (mXMLDeclarationBits
& XML_DECLARATION_BITS_STANDALONE_YES
) {
7977 aStandalone
.AssignLiteral("yes");
7979 aStandalone
.AssignLiteral("no");
7985 nsDocument::IsScriptEnabled()
7987 // If this document is sandboxed without 'allow-scripts'
7988 // script is not enabled
7989 if (mSandboxFlags
& SANDBOXED_SCRIPTS
) {
7993 nsCOMPtr
<nsIScriptSecurityManager
> sm(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
));
7994 NS_ENSURE_TRUE(sm
, false);
7996 nsCOMPtr
<nsIScriptGlobalObject
> globalObject
= do_QueryInterface(GetInnerWindow());
7997 if (!globalObject
&& mMasterDocument
) {
7998 globalObject
= do_QueryInterface(mMasterDocument
->GetInnerWindow());
8000 NS_ENSURE_TRUE(globalObject
&& globalObject
->GetGlobalJSObject(), false);
8002 return sm
->ScriptAllowed(globalObject
->GetGlobalJSObject());
8006 nsDocument::GetRadioGroupInternal(const nsAString
& aName
) const
8010 nsAutoString lcName
;
8011 ToLowerCase(aName
, lcName
);
8012 MOZ_ASSERT(aName
== lcName
);
8016 nsRadioGroupStruct
* radioGroup
;
8017 if (!mRadioGroups
.Get(aName
, &radioGroup
)) {
8025 nsDocument::GetRadioGroup(const nsAString
& aName
) const
8027 nsAutoString
tmKey(aName
);
8029 ToLowerCase(tmKey
); //should case-insensitive.
8032 return GetRadioGroupInternal(tmKey
);
8036 nsDocument::GetOrCreateRadioGroup(const nsAString
& aName
)
8038 nsAutoString
tmKey(aName
);
8040 ToLowerCase(tmKey
); //should case-insensitive.
8043 if (nsRadioGroupStruct
* radioGroup
= GetRadioGroupInternal(tmKey
)) {
8047 nsAutoPtr
<nsRadioGroupStruct
> newRadioGroup(new nsRadioGroupStruct());
8048 mRadioGroups
.Put(tmKey
, newRadioGroup
);
8050 return newRadioGroup
.forget();
8054 nsDocument::SetCurrentRadioButton(const nsAString
& aName
,
8055 HTMLInputElement
* aRadio
)
8057 nsRadioGroupStruct
* radioGroup
= GetOrCreateRadioGroup(aName
);
8058 radioGroup
->mSelectedRadioButton
= aRadio
;
8062 nsDocument::GetCurrentRadioButton(const nsAString
& aName
)
8064 return GetOrCreateRadioGroup(aName
)->mSelectedRadioButton
;
8068 nsDocument::GetNextRadioButton(const nsAString
& aName
,
8069 const bool aPrevious
,
8070 HTMLInputElement
* aFocusedRadio
,
8071 HTMLInputElement
** aRadioOut
)
8073 // XXX Can we combine the HTML radio button method impls of
8074 // nsDocument and nsHTMLFormControl?
8075 // XXX Why is HTML radio button stuff in nsDocument, as
8076 // opposed to nsHTMLDocument?
8077 *aRadioOut
= nullptr;
8079 nsRadioGroupStruct
* radioGroup
= GetOrCreateRadioGroup(aName
);
8081 // Return the radio button relative to the focused radio button.
8082 // If no radio is focused, get the radio relative to the selected one.
8083 nsRefPtr
<HTMLInputElement
> currentRadio
;
8084 if (aFocusedRadio
) {
8085 currentRadio
= aFocusedRadio
;
8088 currentRadio
= radioGroup
->mSelectedRadioButton
;
8089 if (!currentRadio
) {
8090 return NS_ERROR_FAILURE
;
8093 int32_t index
= radioGroup
->mRadioButtons
.IndexOf(currentRadio
);
8095 return NS_ERROR_FAILURE
;
8098 int32_t numRadios
= radioGroup
->mRadioButtons
.Count();
8099 nsRefPtr
<HTMLInputElement
> radio
;
8103 index
= numRadios
-1;
8106 else if (++index
>= numRadios
) {
8109 NS_ASSERTION(static_cast<nsGenericHTMLFormElement
*>(radioGroup
->mRadioButtons
[index
])->IsHTML(nsGkAtoms::input
),
8110 "mRadioButtons holding a non-radio button");
8111 radio
= static_cast<HTMLInputElement
*>(radioGroup
->mRadioButtons
[index
]);
8112 } while (radio
->Disabled() && radio
!= currentRadio
);
8114 radio
.forget(aRadioOut
);
8119 nsDocument::AddToRadioGroup(const nsAString
& aName
,
8120 nsIFormControl
* aRadio
)
8122 nsRadioGroupStruct
* radioGroup
= GetOrCreateRadioGroup(aName
);
8123 radioGroup
->mRadioButtons
.AppendObject(aRadio
);
8125 nsCOMPtr
<nsIContent
> element
= do_QueryInterface(aRadio
);
8126 NS_ASSERTION(element
, "radio controls have to be content elements");
8127 if (element
->HasAttr(kNameSpaceID_None
, nsGkAtoms::required
)) {
8128 radioGroup
->mRequiredRadioCount
++;
8133 nsDocument::RemoveFromRadioGroup(const nsAString
& aName
,
8134 nsIFormControl
* aRadio
)
8136 nsRadioGroupStruct
* radioGroup
= GetOrCreateRadioGroup(aName
);
8137 radioGroup
->mRadioButtons
.RemoveObject(aRadio
);
8139 nsCOMPtr
<nsIContent
> element
= do_QueryInterface(aRadio
);
8140 NS_ASSERTION(element
, "radio controls have to be content elements");
8141 if (element
->HasAttr(kNameSpaceID_None
, nsGkAtoms::required
)) {
8142 NS_ASSERTION(radioGroup
->mRequiredRadioCount
!= 0,
8143 "mRequiredRadioCount about to wrap below 0!");
8144 radioGroup
->mRequiredRadioCount
--;
8149 nsDocument::WalkRadioGroup(const nsAString
& aName
,
8150 nsIRadioVisitor
* aVisitor
,
8153 nsRadioGroupStruct
* radioGroup
= GetOrCreateRadioGroup(aName
);
8155 for (int i
= 0; i
< radioGroup
->mRadioButtons
.Count(); i
++) {
8156 if (!aVisitor
->Visit(radioGroup
->mRadioButtons
[i
])) {
8165 nsDocument::GetRequiredRadioCount(const nsAString
& aName
) const
8167 nsRadioGroupStruct
* radioGroup
= GetRadioGroup(aName
);
8168 return radioGroup
? radioGroup
->mRequiredRadioCount
: 0;
8172 nsDocument::RadioRequiredChanged(const nsAString
& aName
, nsIFormControl
* aRadio
)
8174 nsRadioGroupStruct
* radioGroup
= GetOrCreateRadioGroup(aName
);
8176 nsCOMPtr
<nsIContent
> element
= do_QueryInterface(aRadio
);
8177 NS_ASSERTION(element
, "radio controls have to be content elements");
8178 if (element
->HasAttr(kNameSpaceID_None
, nsGkAtoms::required
)) {
8179 radioGroup
->mRequiredRadioCount
++;
8181 NS_ASSERTION(radioGroup
->mRequiredRadioCount
!= 0,
8182 "mRequiredRadioCount about to wrap below 0!");
8183 radioGroup
->mRequiredRadioCount
--;
8188 nsDocument::GetValueMissingState(const nsAString
& aName
) const
8190 nsRadioGroupStruct
* radioGroup
= GetRadioGroup(aName
);
8191 return radioGroup
&& radioGroup
->mGroupSuffersFromValueMissing
;
8195 nsDocument::SetValueMissingState(const nsAString
& aName
, bool aValue
)
8197 nsRadioGroupStruct
* radioGroup
= GetOrCreateRadioGroup(aName
);
8198 radioGroup
->mGroupSuffersFromValueMissing
= aValue
;
8202 nsDocument::RetrieveRelevantHeaders(nsIChannel
*aChannel
)
8204 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(aChannel
);
8210 rv
= httpChannel
->GetResponseHeader(NS_LITERAL_CSTRING("last-modified"),
8213 if (NS_SUCCEEDED(rv
)) {
8215 PRStatus st
= PR_ParseTimeString(tmp
.get(), true, &time
);
8216 if (st
== PR_SUCCESS
) {
8221 // The misspelled key 'referer' is as per the HTTP spec
8222 rv
= httpChannel
->GetRequestHeader(NS_LITERAL_CSTRING("referer"),
8224 if (NS_FAILED(rv
)) {
8225 mReferrer
.Truncate();
8228 static const char *const headers
[] = {
8230 "content-style-type",
8232 "content-disposition",
8234 "x-dns-prefetch-control",
8236 // add more http headers if you need
8237 // XXXbz don't add content-location support without reading bug
8238 // 238654 and its dependencies/dups first.
8242 nsAutoCString headerVal
;
8243 const char *const *name
= headers
;
8246 httpChannel
->GetResponseHeader(nsDependentCString(*name
), headerVal
);
8247 if (NS_SUCCEEDED(rv
) && !headerVal
.IsEmpty()) {
8248 nsCOMPtr
<nsIAtom
> key
= do_GetAtom(*name
);
8249 SetHeaderData(key
, NS_ConvertASCIItoUTF16(headerVal
));
8254 nsCOMPtr
<nsIFileChannel
> fileChannel
= do_QueryInterface(aChannel
);
8256 nsCOMPtr
<nsIFile
> file
;
8257 fileChannel
->GetFile(getter_AddRefs(file
));
8260 rv
= file
->GetLastModifiedTime(&msecs
);
8262 if (NS_SUCCEEDED(rv
)) {
8263 modDate
= msecs
* int64_t(PR_USEC_PER_MSEC
);
8267 nsAutoCString contentDisp
;
8268 rv
= aChannel
->GetContentDispositionHeader(contentDisp
);
8269 if (NS_SUCCEEDED(rv
)) {
8270 SetHeaderData(nsGkAtoms::headerContentDisposition
,
8271 NS_ConvertASCIItoUTF16(contentDisp
));
8277 // We got nothing from our attempt to ask nsIFileChannel and
8278 // nsIHttpChannel for the last modified time. Return the current
8283 mLastModified
.Truncate();
8285 PRExplodedTime prtime
;
8286 PR_ExplodeTime(modDate
, PR_LocalTimeParameters
, &prtime
);
8287 // "MM/DD/YYYY hh:mm:ss"
8288 char formatedTime
[24];
8289 if (PR_snprintf(formatedTime
, sizeof(formatedTime
),
8290 "%02ld/%02ld/%04hd %02ld:%02ld:%02ld",
8291 prtime
.tm_month
+ 1, prtime
.tm_mday
, prtime
.tm_year
,
8292 prtime
.tm_hour
, prtime
.tm_min
, prtime
.tm_sec
)) {
8293 CopyASCIItoUTF16(nsDependentCString(formatedTime
), mLastModified
);
8299 nsDocument::CreateElem(const nsAString
& aName
, nsIAtom
*aPrefix
, int32_t aNamespaceID
,
8300 nsIContent
**aResult
)
8305 aPrefix
->ToString(qName
);
8308 qName
.Append(aName
);
8310 // Note: "a:b:c" is a valid name in non-namespaces XML, and
8311 // nsDocument::CreateElement can call us with such a name and no prefix,
8312 // which would cause an error if we just used true here.
8313 bool nsAware
= aPrefix
!= nullptr || aNamespaceID
!= GetDefaultNamespaceID();
8314 NS_ASSERTION(NS_SUCCEEDED(nsContentUtils::CheckQName(qName
, nsAware
)),
8315 "Don't pass invalid prefixes to nsDocument::CreateElem, "
8321 nsRefPtr
<mozilla::dom::NodeInfo
> nodeInfo
;
8322 mNodeInfoManager
->GetNodeInfo(aName
, aPrefix
, aNamespaceID
,
8323 nsIDOMNode::ELEMENT_NODE
,
8324 getter_AddRefs(nodeInfo
));
8325 NS_ENSURE_TRUE(nodeInfo
, NS_ERROR_OUT_OF_MEMORY
);
8327 nsCOMPtr
<Element
> element
;
8328 nsresult rv
= NS_NewElement(getter_AddRefs(element
), nodeInfo
.forget(),
8330 element
.forget(aResult
);
8335 nsDocument::IsSafeToFlush() const
8337 nsIPresShell
* shell
= GetShell();
8341 return shell
->IsSafeToFlush();
8345 nsDocument::Sanitize()
8347 // Sanitize the document by resetting all password fields and any form
8348 // fields with autocomplete=off to their default values. We do this now,
8349 // instead of when the presentation is restored, to offer some protection
8350 // in case there is ever an exploit that allows a cached document to be
8351 // accessed from a different document.
8353 // First locate all input elements, regardless of whether they are
8354 // in a form, and reset the password and autocomplete=off elements.
8356 nsRefPtr
<nsContentList
> nodes
= GetElementsByTagName(NS_LITERAL_STRING("input"));
8358 nsCOMPtr
<nsIContent
> item
;
8361 uint32_t length
= nodes
->Length(true);
8362 for (uint32_t i
= 0; i
< length
; ++i
) {
8363 NS_ASSERTION(nodes
->Item(i
), "null item in node list!");
8365 nsRefPtr
<HTMLInputElement
> input
= HTMLInputElement::FromContentOrNull(nodes
->Item(i
));
8369 bool resetValue
= false;
8371 input
->GetAttribute(NS_LITERAL_STRING("autocomplete"), value
);
8372 if (value
.LowerCaseEqualsLiteral("off")) {
8375 input
->GetType(value
);
8376 if (value
.LowerCaseEqualsLiteral("password"))
8385 // Now locate all _form_ elements that have autocomplete=off and reset them
8386 nodes
= GetElementsByTagName(NS_LITERAL_STRING("form"));
8388 length
= nodes
->Length(true);
8389 for (uint32_t i
= 0; i
< length
; ++i
) {
8390 NS_ASSERTION(nodes
->Item(i
), "null item in nodelist");
8392 nsCOMPtr
<nsIDOMHTMLFormElement
> form
= do_QueryInterface(nodes
->Item(i
));
8396 nodes
->Item(i
)->AsElement()->GetAttr(kNameSpaceID_None
,
8397 nsGkAtoms::autocomplete
, value
);
8398 if (value
.LowerCaseEqualsLiteral("off"))
8403 struct SubDocEnumArgs
8405 nsIDocument::nsSubDocEnumFunc callback
;
8409 static PLDHashOperator
8410 SubDocHashEnum(PLDHashTable
*table
, PLDHashEntryHdr
*hdr
,
8411 uint32_t number
, void *arg
)
8413 SubDocMapEntry
*entry
= static_cast<SubDocMapEntry
*>(hdr
);
8414 SubDocEnumArgs
*args
= static_cast<SubDocEnumArgs
*>(arg
);
8416 nsIDocument
*subdoc
= entry
->mSubDocument
;
8417 bool next
= subdoc
? args
->callback(subdoc
, args
->data
) : true;
8419 return next
? PL_DHASH_NEXT
: PL_DHASH_STOP
;
8423 nsDocument::EnumerateSubDocuments(nsSubDocEnumFunc aCallback
, void *aData
)
8425 if (mSubDocuments
) {
8426 SubDocEnumArgs args
= { aCallback
, aData
};
8427 PL_DHashTableEnumerate(mSubDocuments
, SubDocHashEnum
, &args
);
8431 static PLDHashOperator
8432 CanCacheSubDocument(PLDHashTable
*table
, PLDHashEntryHdr
*hdr
,
8433 uint32_t number
, void *arg
)
8435 SubDocMapEntry
*entry
= static_cast<SubDocMapEntry
*>(hdr
);
8436 bool *canCacheArg
= static_cast<bool*>(arg
);
8438 nsIDocument
*subdoc
= entry
->mSubDocument
;
8440 // The aIgnoreRequest we were passed is only for us, so don't pass it on.
8441 bool canCache
= subdoc
? subdoc
->CanSavePresentation(nullptr) : false;
8443 *canCacheArg
= false;
8444 return PL_DHASH_STOP
;
8447 return PL_DHASH_NEXT
;
8451 #define DEBUG_PAGE_CACHE
8455 nsDocument::CanSavePresentation(nsIRequest
*aNewRequest
)
8457 if (EventHandlingSuppressed()) {
8461 nsPIDOMWindow
* win
= GetInnerWindow();
8462 if (win
&& win
->TimeoutSuspendCount()) {
8466 // Check our event listener manager for unload/beforeunload listeners.
8467 nsCOMPtr
<EventTarget
> piTarget
= do_QueryInterface(mScriptGlobalObject
);
8469 EventListenerManager
* manager
= piTarget
->GetExistingListenerManager();
8470 if (manager
&& manager
->HasUnloadListeners()) {
8475 // Check if we have pending network requests
8476 nsCOMPtr
<nsILoadGroup
> loadGroup
= GetDocumentLoadGroup();
8478 nsCOMPtr
<nsISimpleEnumerator
> requests
;
8479 loadGroup
->GetRequests(getter_AddRefs(requests
));
8481 bool hasMore
= false;
8483 // We want to bail out if we have any requests other than aNewRequest (or
8484 // in the case when aNewRequest is a part of a multipart response the base
8485 // channel the multipart response is coming in on).
8486 nsCOMPtr
<nsIChannel
> baseChannel
;
8487 nsCOMPtr
<nsIMultiPartChannel
> part(do_QueryInterface(aNewRequest
));
8489 part
->GetBaseChannel(getter_AddRefs(baseChannel
));
8492 while (NS_SUCCEEDED(requests
->HasMoreElements(&hasMore
)) && hasMore
) {
8493 nsCOMPtr
<nsISupports
> elem
;
8494 requests
->GetNext(getter_AddRefs(elem
));
8496 nsCOMPtr
<nsIRequest
> request
= do_QueryInterface(elem
);
8497 if (request
&& request
!= aNewRequest
&& request
!= baseChannel
) {
8498 #ifdef DEBUG_PAGE_CACHE
8499 nsAutoCString requestName
, docSpec
;
8500 request
->GetName(requestName
);
8502 mDocumentURI
->GetSpec(docSpec
);
8504 printf("document %s has request %s\n",
8505 docSpec
.get(), requestName
.get());
8512 // Check if we have running offline storage transactions
8513 quota::QuotaManager
* quotaManager
=
8514 win
? quota::QuotaManager::Get() : nullptr;
8515 if (quotaManager
&& quotaManager
->HasOpenTransactions(win
)) {
8519 #ifdef MOZ_MEDIA_NAVIGATOR
8520 // Check if we have active GetUserMedia use
8521 if (MediaManager::Exists() && win
&&
8522 MediaManager::Get()->IsWindowStillActive(win
->WindowID())) {
8525 #endif // MOZ_MEDIA_NAVIGATOR
8528 // Check if we have active PeerConnections
8529 nsCOMPtr
<IPeerConnectionManager
> pcManager
=
8530 do_GetService(IPEERCONNECTION_MANAGER_CONTRACTID
);
8532 if (pcManager
&& win
) {
8534 pcManager
->HasActivePeerConnection(win
->WindowID(), &active
);
8539 #endif // MOZ_WEBRTC
8542 // Don't save presentations for documents containing EME content, so that
8543 // CDMs reliably shutdown upon user navigation.
8544 if (ContainsEMEContent()) {
8549 bool canCache
= true;
8551 PL_DHashTableEnumerate(mSubDocuments
, CanCacheSubDocument
, &canCache
);
8557 nsDocument::Destroy()
8559 // The ContentViewer wants to release the document now. So, tell our content
8560 // to drop any references to the document so that it can be destroyed.
8564 mIsGoingAway
= true;
8566 RemovedFromDocShell();
8568 bool oldVal
= mInUnlinkOrDeletion
;
8569 mInUnlinkOrDeletion
= true;
8570 uint32_t i
, count
= mChildren
.ChildCount();
8571 for (i
= 0; i
< count
; ++i
) {
8572 mChildren
.ChildAt(i
)->DestroyContent();
8574 mInUnlinkOrDeletion
= oldVal
;
8576 mLayoutHistoryState
= nullptr;
8578 // Shut down our external resource map. We might not need this for
8579 // leak-fixing if we fix nsDocumentViewer to do cycle-collection, but
8580 // tearing down all those frame trees right now is the right thing to do.
8581 mExternalResourceMap
.Shutdown();
8583 mRegistry
= nullptr;
8585 nsCOMPtr
<nsIServiceWorkerManager
> swm
= mozilla::services::GetServiceWorkerManager();
8587 swm
->MaybeStopControlling(this);
8590 // XXX We really should let cycle collection do this, but that currently still
8591 // leaks (see https://bugzilla.mozilla.org/show_bug.cgi?id=406684).
8592 ReleaseWrapper(static_cast<nsINode
*>(this));
8596 nsDocument::RemovedFromDocShell()
8598 if (mRemovedFromDocShell
)
8601 mRemovedFromDocShell
= true;
8602 EnumerateActivityObservers(NotifyActivityChanged
, nullptr);
8604 uint32_t i
, count
= mChildren
.ChildCount();
8605 for (i
= 0; i
< count
; ++i
) {
8606 mChildren
.ChildAt(i
)->SaveSubtreeState();
8610 already_AddRefed
<nsILayoutHistoryState
>
8611 nsDocument::GetLayoutHistoryState() const
8613 nsCOMPtr
<nsILayoutHistoryState
> state
;
8614 if (!mScriptGlobalObject
) {
8615 state
= mLayoutHistoryState
;
8617 nsCOMPtr
<nsIDocShell
> docShell(mDocumentContainer
);
8619 docShell
->GetLayoutHistoryState(getter_AddRefs(state
));
8623 return state
.forget();
8627 nsDocument::EnsureOnloadBlocker()
8629 // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
8630 // -- it's not ours.
8631 if (mOnloadBlockCount
!= 0 && mScriptGlobalObject
) {
8632 nsCOMPtr
<nsILoadGroup
> loadGroup
= GetDocumentLoadGroup();
8634 // Check first to see if mOnloadBlocker is in the loadgroup.
8635 nsCOMPtr
<nsISimpleEnumerator
> requests
;
8636 loadGroup
->GetRequests(getter_AddRefs(requests
));
8638 bool hasMore
= false;
8639 while (NS_SUCCEEDED(requests
->HasMoreElements(&hasMore
)) && hasMore
) {
8640 nsCOMPtr
<nsISupports
> elem
;
8641 requests
->GetNext(getter_AddRefs(elem
));
8642 nsCOMPtr
<nsIRequest
> request
= do_QueryInterface(elem
);
8643 if (request
&& request
== mOnloadBlocker
) {
8648 // Not in the loadgroup, so add it.
8649 loadGroup
->AddRequest(mOnloadBlocker
, nullptr);
8655 nsDocument::AsyncBlockOnload()
8657 while (mAsyncOnloadBlockCount
) {
8658 --mAsyncOnloadBlockCount
;
8664 nsDocument::BlockOnload()
8666 if (mDisplayDocument
) {
8667 mDisplayDocument
->BlockOnload();
8671 // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
8672 // -- it's not ours.
8673 if (mOnloadBlockCount
== 0 && mScriptGlobalObject
) {
8674 if (!nsContentUtils::IsSafeToRunScript()) {
8675 // Because AddRequest may lead to OnStateChange calls in chrome,
8676 // block onload only when there are no script blockers.
8677 ++mAsyncOnloadBlockCount
;
8678 if (mAsyncOnloadBlockCount
== 1) {
8679 bool success
= nsContentUtils::AddScriptRunner(
8680 NS_NewRunnableMethod(this, &nsDocument::AsyncBlockOnload
));
8682 // The script runner shouldn't fail to add. But if somebody broke
8683 // something and it does, we'll thrash at 100% cpu forever. The best
8684 // response is just to ignore the onload blocking request. See bug 579535.
8686 NS_WARNING("Disaster! Onload blocking script runner failed to add - expect bad things!");
8687 mAsyncOnloadBlockCount
= 0;
8692 nsCOMPtr
<nsILoadGroup
> loadGroup
= GetDocumentLoadGroup();
8694 loadGroup
->AddRequest(mOnloadBlocker
, nullptr);
8697 ++mOnloadBlockCount
;
8701 nsDocument::UnblockOnload(bool aFireSync
)
8703 if (mDisplayDocument
) {
8704 mDisplayDocument
->UnblockOnload(aFireSync
);
8708 if (mOnloadBlockCount
== 0 && mAsyncOnloadBlockCount
== 0) {
8709 NS_NOTREACHED("More UnblockOnload() calls than BlockOnload() calls; dropping call");
8713 --mOnloadBlockCount
;
8715 if (mOnloadBlockCount
== 0) {
8716 if (mScriptGlobalObject
) {
8717 // Only manipulate the loadgroup in this case, because if mScriptGlobalObject
8718 // is null, it's not ours.
8719 if (aFireSync
&& mAsyncOnloadBlockCount
== 0) {
8720 // Increment mOnloadBlockCount, since DoUnblockOnload will decrement it
8721 ++mOnloadBlockCount
;
8724 PostUnblockOnloadEvent();
8726 } else if (mIsBeingUsedAsImage
) {
8727 // To correctly unblock onload for a document that contains an SVG
8728 // image, we need to know when all of the SVG document's resources are
8729 // done loading, in a way comparable to |window.onload|. We fire this
8730 // event to indicate that the SVG should be considered fully loaded.
8731 // Because scripting is disabled on SVG-as-image documents, this event
8732 // is not accessible to content authors. (See bug 837135.)
8733 nsRefPtr
<AsyncEventDispatcher
> asyncDispatcher
=
8734 new AsyncEventDispatcher(this,
8735 NS_LITERAL_STRING("MozSVGAsImageDocumentLoad"),
8738 asyncDispatcher
->PostDOMEvent();
8743 class nsUnblockOnloadEvent
: public nsRunnable
{
8745 explicit nsUnblockOnloadEvent(nsDocument
* aDoc
) : mDoc(aDoc
) {}
8747 mDoc
->DoUnblockOnload();
8751 nsRefPtr
<nsDocument
> mDoc
;
8755 nsDocument::PostUnblockOnloadEvent()
8757 nsCOMPtr
<nsIRunnable
> evt
= new nsUnblockOnloadEvent(this);
8758 nsresult rv
= NS_DispatchToCurrentThread(evt
);
8759 if (NS_SUCCEEDED(rv
)) {
8760 // Stabilize block count so we don't post more events while this one is up
8761 ++mOnloadBlockCount
;
8763 NS_WARNING("failed to dispatch nsUnblockOnloadEvent");
8768 nsDocument::DoUnblockOnload()
8770 NS_PRECONDITION(!mDisplayDocument
,
8771 "Shouldn't get here for resource document");
8772 NS_PRECONDITION(mOnloadBlockCount
!= 0,
8773 "Shouldn't have a count of zero here, since we stabilized in "
8774 "PostUnblockOnloadEvent");
8776 --mOnloadBlockCount
;
8778 if (mOnloadBlockCount
!= 0) {
8779 // We blocked again after the last unblock. Nothing to do here. We'll
8780 // post a new event when we unblock again.
8784 if (mAsyncOnloadBlockCount
!= 0) {
8785 // We need to wait until the async onload block has been handled.
8786 PostUnblockOnloadEvent();
8789 // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
8790 // -- it's not ours.
8791 if (mScriptGlobalObject
) {
8792 nsCOMPtr
<nsILoadGroup
> loadGroup
= GetDocumentLoadGroup();
8794 loadGroup
->RemoveRequest(mOnloadBlocker
, nullptr, NS_OK
);
8800 nsDocument::GetContentInThisDocument(nsIFrame
* aFrame
) const
8802 for (nsIFrame
* f
= aFrame
; f
;
8803 f
= nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f
)) {
8804 nsIContent
* content
= f
->GetContent();
8805 if (!content
|| content
->IsInAnonymousSubtree())
8808 if (content
->OwnerDoc() == this) {
8811 // We must be in a subdocument so jump directly to the root frame.
8812 // GetParentOrPlaceholderForCrossDoc gets called immediately to jump up to
8813 // the containing document.
8814 f
= f
->PresContext()->GetPresShell()->GetRootFrame();
8821 nsDocument::DispatchPageTransition(EventTarget
* aDispatchTarget
,
8822 const nsAString
& aType
,
8825 if (!aDispatchTarget
) {
8829 PageTransitionEventInit init
;
8830 init
.mBubbles
= true;
8831 init
.mCancelable
= true;
8832 init
.mPersisted
= aPersisted
;
8834 nsRefPtr
<PageTransitionEvent
> event
=
8835 PageTransitionEvent::Constructor(this, aType
, init
);
8837 event
->SetTrusted(true);
8838 event
->SetTarget(this);
8839 EventDispatcher::DispatchDOMEvent(aDispatchTarget
, nullptr, event
,
8844 NotifyPageShow(nsIDocument
* aDocument
, void* aData
)
8846 const bool* aPersistedPtr
= static_cast<const bool*>(aData
);
8847 aDocument
->OnPageShow(*aPersistedPtr
, nullptr);
8852 nsDocument::OnPageShow(bool aPersisted
,
8853 EventTarget
* aDispatchStartTarget
)
8857 EnumerateActivityObservers(NotifyActivityChanged
, nullptr);
8858 EnumerateExternalResources(NotifyPageShow
, &aPersisted
);
8860 Element
* root
= GetRootElement();
8861 if (aPersisted
&& root
) {
8862 // Send out notifications that our <link> elements are attached.
8863 nsRefPtr
<nsContentList
> links
= NS_GetContentList(root
,
8865 NS_LITERAL_STRING("link"));
8867 uint32_t linkCount
= links
->Length(true);
8868 for (uint32_t i
= 0; i
< linkCount
; ++i
) {
8869 static_cast<HTMLLinkElement
*>(links
->Item(i
, false))->LinkAdded();
8874 if (!aDispatchStartTarget
) {
8875 // Set mIsShowing before firing events, in case those event handlers
8880 if (mAnimationController
) {
8881 mAnimationController
->OnPageShow();
8885 SetImagesNeedAnimating(true);
8888 UpdateVisibilityState();
8890 nsCOMPtr
<EventTarget
> target
= aDispatchStartTarget
;
8892 target
= do_QueryInterface(GetWindow());
8895 // Dispatch observer notification to notify observers page is shown.
8896 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
8897 nsIPrincipal
*principal
= GetPrincipal();
8898 os
->NotifyObservers(static_cast<nsIDocument
*>(this),
8899 nsContentUtils::IsSystemPrincipal(principal
) ?
8900 "chrome-page-shown" :
8901 "content-page-shown",
8903 if (!mObservingAppThemeChanged
) {
8904 os
->AddObserver(this, "app-theme-changed", /* ownsWeak */ false);
8905 mObservingAppThemeChanged
= true;
8908 DispatchPageTransition(target
, NS_LITERAL_STRING("pageshow"), aPersisted
);
8912 NotifyPageHide(nsIDocument
* aDocument
, void* aData
)
8914 const bool* aPersistedPtr
= static_cast<const bool*>(aData
);
8915 aDocument
->OnPageHide(*aPersistedPtr
, nullptr);
8920 DispatchFullScreenChange(nsIDocument
* aTarget
)
8922 nsRefPtr
<AsyncEventDispatcher
> asyncDispatcher
=
8923 new AsyncEventDispatcher(aTarget
,
8924 NS_LITERAL_STRING("mozfullscreenchange"),
8927 asyncDispatcher
->PostDOMEvent();
8931 nsDocument::OnPageHide(bool aPersisted
,
8932 EventTarget
* aDispatchStartTarget
)
8934 // Send out notifications that our <link> elements are detached,
8935 // but only if this is not a full unload.
8936 Element
* root
= GetRootElement();
8937 if (aPersisted
&& root
) {
8938 nsRefPtr
<nsContentList
> links
= NS_GetContentList(root
,
8940 NS_LITERAL_STRING("link"));
8942 uint32_t linkCount
= links
->Length(true);
8943 for (uint32_t i
= 0; i
< linkCount
; ++i
) {
8944 static_cast<HTMLLinkElement
*>(links
->Item(i
, false))->LinkRemoved();
8949 if (!aDispatchStartTarget
) {
8950 // Set mIsShowing before firing events, in case those event handlers
8955 if (mAnimationController
) {
8956 mAnimationController
->OnPageHide();
8960 SetImagesNeedAnimating(false);
8963 MozExitPointerLock();
8965 // Now send out a PageHide event.
8966 nsCOMPtr
<EventTarget
> target
= aDispatchStartTarget
;
8968 target
= do_QueryInterface(GetWindow());
8971 // Dispatch observer notification to notify observers page is hidden.
8972 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
8974 nsIPrincipal
* principal
= GetPrincipal();
8975 os
->NotifyObservers(static_cast<nsIDocument
*>(this),
8976 nsContentUtils::IsSystemPrincipal(principal
) ?
8977 "chrome-page-hidden" :
8978 "content-page-hidden",
8981 os
->RemoveObserver(this, "app-theme-changed");
8982 mObservingAppThemeChanged
= false;
8985 DispatchPageTransition(target
, NS_LITERAL_STRING("pagehide"), aPersisted
);
8989 UpdateVisibilityState();
8991 EnumerateExternalResources(NotifyPageHide
, &aPersisted
);
8992 EnumerateActivityObservers(NotifyActivityChanged
, nullptr);
8994 if (IsFullScreenDoc()) {
8995 // If this document was fullscreen, we should exit fullscreen in this
8996 // doctree branch. This ensures that if the user navigates while in
8997 // fullscreen mode we don't leave its still visible ancestor documents
8998 // in fullscreen mode. So exit fullscreen in the document's fullscreen
8999 // root document, as this will exit fullscreen in all the root's
9000 // descendant documents. Note that documents are removed from the
9001 // doctree by the time OnPageHide() is called, so we must store a
9002 // reference to the root (in nsDocument::mFullscreenRoot) since we can't
9003 // just traverse the doctree to get the root.
9004 nsIDocument::ExitFullscreen(this, /* async */ false);
9006 // Since the document is removed from the doctree before OnPageHide() is
9007 // called, ExitFullscreen() can't traverse from the root down to *this*
9008 // document, so we must manually call CleanupFullscreenState() below too.
9009 // Note that CleanupFullscreenState() clears nsDocument::mFullscreenRoot,
9010 // so we *must* call it after ExitFullscreen(), not before.
9011 // OnPageHide() is called in every hidden (i.e. descendant) document,
9012 // so calling CleanupFullscreenState() here will ensure all hidden
9013 // documents have their fullscreen state reset.
9014 CleanupFullscreenState();
9016 // If anyone was listening to this document's state, advertizing the state
9017 // change would be the least of the politeness.
9018 DispatchFullScreenChange(this);
9023 nsDocument::WillDispatchMutationEvent(nsINode
* aTarget
)
9025 NS_ASSERTION(mSubtreeModifiedDepth
!= 0 ||
9026 mSubtreeModifiedTargets
.Count() == 0,
9027 "mSubtreeModifiedTargets not cleared after dispatching?");
9028 ++mSubtreeModifiedDepth
;
9030 // MayDispatchMutationEvent is often called just before this method,
9031 // so it has already appended the node to mSubtreeModifiedTargets.
9032 int32_t count
= mSubtreeModifiedTargets
.Count();
9033 if (!count
|| mSubtreeModifiedTargets
[count
- 1] != aTarget
) {
9034 mSubtreeModifiedTargets
.AppendObject(aTarget
);
9040 nsDocument::MutationEventDispatched(nsINode
* aTarget
)
9042 --mSubtreeModifiedDepth
;
9043 if (mSubtreeModifiedDepth
== 0) {
9044 int32_t count
= mSubtreeModifiedTargets
.Count();
9049 nsPIDOMWindow
* window
= GetInnerWindow();
9051 !window
->HasMutationListeners(NS_EVENT_BITS_MUTATION_SUBTREEMODIFIED
)) {
9052 mSubtreeModifiedTargets
.Clear();
9056 nsCOMArray
<nsINode
> realTargets
;
9057 for (int32_t i
= 0; i
< count
; ++i
) {
9058 nsINode
* possibleTarget
= mSubtreeModifiedTargets
[i
];
9059 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(possibleTarget
);
9060 if (content
&& content
->ChromeOnlyAccess()) {
9064 nsINode
* commonAncestor
= nullptr;
9065 int32_t realTargetCount
= realTargets
.Count();
9066 for (int32_t j
= 0; j
< realTargetCount
; ++j
) {
9068 nsContentUtils::GetCommonAncestor(possibleTarget
, realTargets
[j
]);
9069 if (commonAncestor
) {
9070 realTargets
.ReplaceObjectAt(commonAncestor
, j
);
9074 if (!commonAncestor
) {
9075 realTargets
.AppendObject(possibleTarget
);
9079 mSubtreeModifiedTargets
.Clear();
9081 int32_t realTargetCount
= realTargets
.Count();
9082 for (int32_t k
= 0; k
< realTargetCount
; ++k
) {
9083 InternalMutationEvent
mutation(true, NS_MUTATION_SUBTREEMODIFIED
);
9084 (new AsyncEventDispatcher(realTargets
[k
], mutation
))->
9085 RunDOMEventWhenSafe();
9091 nsDocument::AddStyleRelevantLink(Link
* aLink
)
9093 NS_ASSERTION(aLink
, "Passing in a null link. Expect crashes RSN!");
9095 nsPtrHashKey
<Link
>* entry
= mStyledLinks
.GetEntry(aLink
);
9096 NS_ASSERTION(!entry
, "Document already knows about this Link!");
9097 mStyledLinksCleared
= false;
9099 (void)mStyledLinks
.PutEntry(aLink
);
9103 nsDocument::ForgetLink(Link
* aLink
)
9105 NS_ASSERTION(aLink
, "Passing in a null link. Expect crashes RSN!");
9107 nsPtrHashKey
<Link
>* entry
= mStyledLinks
.GetEntry(aLink
);
9108 NS_ASSERTION(entry
|| mStyledLinksCleared
,
9109 "Document knows nothing about this Link!");
9111 (void)mStyledLinks
.RemoveEntry(aLink
);
9115 nsDocument::DestroyElementMaps()
9118 mStyledLinksCleared
= true;
9120 mStyledLinks
.Clear();
9121 mIdentifierMap
.Clear();
9122 ++mExpandoAndGeneration
.generation
;
9127 EnumerateStyledLinks(nsPtrHashKey
<Link
>* aEntry
, void* aArray
)
9129 LinkArray
* array
= static_cast<LinkArray
*>(aArray
);
9130 (void)array
->AppendElement(aEntry
->GetKey());
9131 return PL_DHASH_NEXT
;
9135 nsDocument::RefreshLinkHrefs()
9137 // Get a list of all links we know about. We will reset them, which will
9138 // remove them from the document, so we need a copy of what is in the
9140 LinkArray
linksToNotify(mStyledLinks
.Count());
9141 (void)mStyledLinks
.EnumerateEntries(EnumerateStyledLinks
, &linksToNotify
);
9143 // Reset all of our styled links.
9144 nsAutoScriptBlocker scriptBlocker
;
9145 for (LinkArray::size_type i
= 0; i
< linksToNotify
.Length(); i
++) {
9146 linksToNotify
[i
]->ResetLinkState(true, linksToNotify
[i
]->ElementHasHref());
9151 nsDocument::CloneDocHelper(nsDocument
* clone
) const
9153 clone
->mIsStaticDocument
= mCreatingStaticClone
;
9156 nsresult rv
= clone
->Init();
9157 NS_ENSURE_SUCCESS(rv
, rv
);
9159 if (mCreatingStaticClone
) {
9160 nsCOMPtr
<nsILoadGroup
> loadGroup
;
9162 // |mDocumentContainer| is the container of the document that is being
9163 // created and not the original container. See CreateStaticClone function().
9164 nsCOMPtr
<nsIDocumentLoader
> docLoader(mDocumentContainer
);
9166 docLoader
->GetLoadGroup(getter_AddRefs(loadGroup
));
9168 nsCOMPtr
<nsIChannel
> channel
= GetChannel();
9169 nsCOMPtr
<nsIURI
> uri
;
9171 NS_GetFinalChannelURI(channel
, getter_AddRefs(uri
));
9173 uri
= nsIDocument::GetDocumentURI();
9175 clone
->mChannel
= channel
;
9177 clone
->ResetToURI(uri
, loadGroup
, NodePrincipal());
9180 clone
->SetContainer(mDocumentContainer
);
9183 // Now ensure that our clone has the same URI, base URI, and principal as us.
9184 // We do this after the mCreatingStaticClone block above, because that block
9185 // can set the base URI to an incorrect value in cases when base URI
9186 // information came from the channel. So we override explicitly, and do it
9187 // for all these properties, in case ResetToURI messes with any of the rest of
9189 clone
->nsDocument::SetDocumentURI(nsIDocument::GetDocumentURI());
9190 clone
->SetChromeXHRDocURI(mChromeXHRDocURI
);
9191 clone
->SetPrincipal(NodePrincipal());
9192 clone
->mDocumentBaseURI
= mDocumentBaseURI
;
9193 clone
->SetChromeXHRDocBaseURI(mChromeXHRDocBaseURI
);
9195 // Set scripting object
9196 bool hasHadScriptObject
= true;
9197 nsIScriptGlobalObject
* scriptObject
=
9198 GetScriptHandlingObject(hasHadScriptObject
);
9199 NS_ENSURE_STATE(scriptObject
|| !hasHadScriptObject
);
9201 clone
->SetScriptHandlingObject(scriptObject
);
9203 clone
->SetScopeObject(GetScopeObject());
9205 // Make the clone a data document
9206 clone
->SetLoadedAsData(true);
9210 // State from nsIDocument
9211 clone
->mCharacterSet
= mCharacterSet
;
9212 clone
->mCharacterSetSource
= mCharacterSetSource
;
9213 clone
->mCompatMode
= mCompatMode
;
9214 clone
->mBidiOptions
= mBidiOptions
;
9215 clone
->mContentLanguage
= mContentLanguage
;
9216 clone
->SetContentTypeInternal(GetContentTypeInternal());
9217 clone
->mSecurityInfo
= mSecurityInfo
;
9219 // State from nsDocument
9220 clone
->mType
= mType
;
9221 clone
->mXMLDeclarationBits
= mXMLDeclarationBits
;
9222 clone
->mBaseTarget
= mBaseTarget
;
9227 nsDocument::SetReadyStateInternal(ReadyState rs
)
9230 if (rs
== READYSTATE_UNINITIALIZED
) {
9231 // Transition back to uninitialized happens only to keep assertions happy
9232 // right before readyState transitions to something else. Make this
9233 // transition undetectable by Web content.
9238 case READYSTATE_LOADING
:
9239 mTiming
->NotifyDOMLoading(nsIDocument::GetDocumentURI());
9241 case READYSTATE_INTERACTIVE
:
9242 mTiming
->NotifyDOMInteractive(nsIDocument::GetDocumentURI());
9244 case READYSTATE_COMPLETE
:
9245 mTiming
->NotifyDOMComplete(nsIDocument::GetDocumentURI());
9248 NS_WARNING("Unexpected ReadyState value");
9252 // At the time of loading start, we don't have timing object, record time.
9253 if (READYSTATE_LOADING
== rs
) {
9254 mLoadingTimeStamp
= mozilla::TimeStamp::Now();
9257 nsRefPtr
<AsyncEventDispatcher
> asyncDispatcher
=
9258 new AsyncEventDispatcher(this, NS_LITERAL_STRING("readystatechange"),
9260 asyncDispatcher
->RunDOMEventWhenSafe();
9264 nsDocument::GetReadyState(nsAString
& aReadyState
)
9266 nsIDocument::GetReadyState(aReadyState
);
9271 nsIDocument::GetReadyState(nsAString
& aReadyState
) const
9273 switch(mReadyState
) {
9274 case READYSTATE_LOADING
:
9275 aReadyState
.AssignLiteral(MOZ_UTF16("loading"));
9277 case READYSTATE_INTERACTIVE
:
9278 aReadyState
.AssignLiteral(MOZ_UTF16("interactive"));
9280 case READYSTATE_COMPLETE
:
9281 aReadyState
.AssignLiteral(MOZ_UTF16("complete"));
9284 aReadyState
.AssignLiteral(MOZ_UTF16("uninitialized"));
9292 nsIDocument::SuppressionType mWhat
;
9299 SuppressEventHandlingInDocument(nsIDocument
* aDocument
, void* aData
)
9301 SuppressArgs
* args
= static_cast<SuppressArgs
*>(aData
);
9302 aDocument
->SuppressEventHandling(args
->mWhat
, args
->mIncrease
);
9307 nsDocument::SuppressEventHandling(nsIDocument::SuppressionType aWhat
,
9310 if (mEventsSuppressed
== 0 && mAnimationsPaused
== 0 &&
9311 aIncrease
!= 0 && mPresShell
&& mScriptGlobalObject
) {
9312 RevokeAnimationFrameNotifications();
9315 if (aWhat
== eAnimationsOnly
) {
9316 mAnimationsPaused
+= aIncrease
;
9318 mEventsSuppressed
+= aIncrease
;
9321 SuppressArgs args
= { aWhat
, aIncrease
};
9322 EnumerateSubDocuments(SuppressEventHandlingInDocument
, &args
);
9326 FireOrClearDelayedEvents(nsTArray
<nsCOMPtr
<nsIDocument
> >& aDocuments
,
9329 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
9333 for (uint32_t i
= 0; i
< aDocuments
.Length(); ++i
) {
9334 // NB: Don't bother trying to fire delayed events on documents that were
9335 // closed before this event ran.
9336 if (!aDocuments
[i
]->EventHandlingSuppressed()) {
9337 fm
->FireDelayedEvents(aDocuments
[i
]);
9338 nsCOMPtr
<nsIPresShell
> shell
= aDocuments
[i
]->GetShell();
9340 // Only fire events for active documents.
9341 bool fire
= aFireEvents
&&
9342 aDocuments
[i
]->GetInnerWindow() &&
9343 aDocuments
[i
]->GetInnerWindow()->IsCurrentInnerWindow();
9344 shell
->FireOrClearDelayedEvents(fire
);
9351 nsDocument::MaybePreLoadImage(nsIURI
* uri
, const nsAString
&aCrossOriginAttr
)
9353 // Early exit if the img is already present in the img-cache
9354 // which indicates that the "real" load has already started and
9355 // that we shouldn't preload it.
9356 int16_t blockingStatus
;
9357 if (nsContentUtils::IsImageInCache(uri
, static_cast<nsIDocument
*>(this)) ||
9358 !nsContentUtils::CanLoadImage(uri
, static_cast<nsIDocument
*>(this),
9359 this, NodePrincipal(), &blockingStatus
)) {
9363 nsLoadFlags loadFlags
= nsIRequest::LOAD_NORMAL
;
9364 switch (Element::StringToCORSMode(aCrossOriginAttr
)) {
9368 case CORS_ANONYMOUS
:
9369 loadFlags
|= imgILoader::LOAD_CORS_ANONYMOUS
;
9371 case CORS_USE_CREDENTIALS
:
9372 loadFlags
|= imgILoader::LOAD_CORS_USE_CREDENTIALS
;
9375 MOZ_CRASH("Unknown CORS mode!");
9378 // Image not in cache - trigger preload
9379 nsRefPtr
<imgRequestProxy
> request
;
9381 nsContentUtils::LoadImage(uri
,
9384 mDocumentURI
, // uri of document used as referrer
9385 nullptr, // no observer
9387 NS_LITERAL_STRING("img"),
9388 getter_AddRefs(request
));
9390 // Pin image-reference to avoid evicting it from the img-cache before
9391 // the "real" load occurs. Unpinned in DispatchContentLoadedEvents and
9393 if (NS_SUCCEEDED(rv
)) {
9394 mPreloadingImages
.AppendObject(request
);
9399 nsDocument::GetDocumentState()
9401 if (!mGotDocumentState
.HasState(NS_DOCUMENT_STATE_RTL_LOCALE
)) {
9402 if (IsDocumentRightToLeft()) {
9403 mDocumentState
|= NS_DOCUMENT_STATE_RTL_LOCALE
;
9405 mGotDocumentState
|= NS_DOCUMENT_STATE_RTL_LOCALE
;
9407 if (!mGotDocumentState
.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE
)) {
9408 nsIPresShell
* shell
= GetShell();
9409 if (shell
&& shell
->GetPresContext() &&
9410 shell
->GetPresContext()->IsTopLevelWindowInactive()) {
9411 mDocumentState
|= NS_DOCUMENT_STATE_WINDOW_INACTIVE
;
9413 mGotDocumentState
|= NS_DOCUMENT_STATE_WINDOW_INACTIVE
;
9415 return mDocumentState
;
9421 * Stub for LoadSheet(), since all we want is to get the sheet into
9422 * the CSSLoader's style cache
9424 class StubCSSLoaderObserver MOZ_FINAL
: public nsICSSLoaderObserver
{
9425 ~StubCSSLoaderObserver() {}
9428 StyleSheetLoaded(CSSStyleSheet
*, bool, nsresult
)
9434 NS_IMPL_ISUPPORTS(StubCSSLoaderObserver
, nsICSSLoaderObserver
)
9439 nsDocument::PreloadStyle(nsIURI
* uri
, const nsAString
& charset
,
9440 const nsAString
& aCrossOriginAttr
)
9442 // The CSSLoader will retain this object after we return.
9443 nsCOMPtr
<nsICSSLoaderObserver
> obs
= new StubCSSLoaderObserver();
9445 // Charset names are always ASCII.
9446 CSSLoader()->LoadSheet(uri
, NodePrincipal(),
9447 NS_LossyConvertUTF16toASCII(charset
),
9449 Element::StringToCORSMode(aCrossOriginAttr
));
9453 nsDocument::LoadChromeSheetSync(nsIURI
* uri
, bool isAgentSheet
,
9454 CSSStyleSheet
** sheet
)
9456 return CSSLoader()->LoadSheetSync(uri
, isAgentSheet
, isAgentSheet
, sheet
);
9459 class nsDelayedEventDispatcher
: public nsRunnable
9462 explicit nsDelayedEventDispatcher(nsTArray
<nsCOMPtr
<nsIDocument
>>& aDocuments
)
9464 mDocuments
.SwapElements(aDocuments
);
9466 virtual ~nsDelayedEventDispatcher() {}
9470 FireOrClearDelayedEvents(mDocuments
, true);
9475 nsTArray
<nsCOMPtr
<nsIDocument
> > mDocuments
;
9480 struct UnsuppressArgs
9482 explicit UnsuppressArgs(nsIDocument::SuppressionType aWhat
)
9487 nsIDocument::SuppressionType mWhat
;
9488 nsTArray
<nsCOMPtr
<nsIDocument
>> mDocs
;
9494 GetAndUnsuppressSubDocuments(nsIDocument
* aDocument
,
9497 UnsuppressArgs
* args
= static_cast<UnsuppressArgs
*>(aData
);
9498 if (args
->mWhat
!= nsIDocument::eAnimationsOnly
&&
9499 aDocument
->EventHandlingSuppressed() > 0) {
9500 static_cast<nsDocument
*>(aDocument
)->DecreaseEventSuppression();
9501 } else if (args
->mWhat
== nsIDocument::eAnimationsOnly
&&
9502 aDocument
->AnimationsPaused()) {
9503 static_cast<nsDocument
*>(aDocument
)->ResumeAnimations();
9506 if (args
->mWhat
!= nsIDocument::eAnimationsOnly
) {
9507 // No need to remember documents if we only care about animation frames.
9508 args
->mDocs
.AppendElement(aDocument
);
9511 aDocument
->EnumerateSubDocuments(GetAndUnsuppressSubDocuments
, aData
);
9516 nsDocument::UnsuppressEventHandlingAndFireEvents(nsIDocument::SuppressionType aWhat
,
9519 UnsuppressArgs
args(aWhat
);
9520 GetAndUnsuppressSubDocuments(this, &args
);
9522 if (aWhat
== nsIDocument::eAnimationsOnly
) {
9523 // No need to fire events if we only care about animations here.
9528 NS_DispatchToCurrentThread(new nsDelayedEventDispatcher(args
.mDocs
));
9530 FireOrClearDelayedEvents(args
.mDocs
, false);
9535 nsDocument::GetCurrentContentSink()
9537 return mParser
? mParser
->GetContentSink() : nullptr;
9541 nsDocument::GetTemplateContentsOwner()
9543 if (!mTemplateContentsOwner
) {
9544 bool hasHadScriptObject
= true;
9545 nsIScriptGlobalObject
* scriptObject
=
9546 GetScriptHandlingObject(hasHadScriptObject
);
9548 nsCOMPtr
<nsIDOMDocument
> domDocument
;
9549 nsresult rv
= NS_NewDOMDocument(getter_AddRefs(domDocument
),
9550 EmptyString(), // aNamespaceURI
9551 EmptyString(), // aQualifiedName
9552 nullptr, // aDoctype
9553 nsIDocument::GetDocumentURI(),
9554 nsIDocument::GetDocBaseURI(),
9556 true, // aLoadedAsData
9557 scriptObject
, // aEventObject
9558 DocumentFlavorHTML
);
9559 NS_ENSURE_SUCCESS(rv
, nullptr);
9561 mTemplateContentsOwner
= do_QueryInterface(domDocument
);
9562 NS_ENSURE_TRUE(mTemplateContentsOwner
, nullptr);
9564 nsDocument
* doc
= static_cast<nsDocument
*>(mTemplateContentsOwner
.get());
9565 doc
->mHasHadScriptHandlingObject
= hasHadScriptObject
;
9567 if (!scriptObject
) {
9568 mTemplateContentsOwner
->SetScopeObject(GetScopeObject());
9571 // Set |doc| as the template contents owner of itself so that
9572 // |doc| is the template contents owner of template elements created
9574 doc
->mTemplateContentsOwner
= doc
;
9577 return mTemplateContentsOwner
;
9581 nsDocument::RegisterHostObjectUri(const nsACString
& aUri
)
9583 mHostObjectURIs
.AppendElement(aUri
);
9587 nsDocument::UnregisterHostObjectUri(const nsACString
& aUri
)
9589 mHostObjectURIs
.RemoveElement(aUri
);
9593 nsDocument::SetScrollToRef(nsIURI
*aDocumentURI
)
9595 if (!aDocumentURI
) {
9601 // Since all URI's that pass through here aren't URL's we can't
9602 // rely on the nsIURI implementation for providing a way for
9603 // finding the 'ref' part of the URI, we'll haveto revert to
9604 // string routines for finding the data past '#'
9606 aDocumentURI
->GetSpec(ref
);
9608 nsReadingIterator
<char> start
, end
;
9610 ref
.BeginReading(start
);
9611 ref
.EndReading(end
);
9613 if (FindCharInReadable('#', start
, end
)) {
9614 ++start
; // Skip over the '#'
9616 mScrollToRef
= Substring(start
, end
);
9621 nsDocument::ScrollToRef()
9623 if (mScrolledToRefAlready
) {
9624 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
9626 shell
->ScrollToAnchor();
9631 if (mScrollToRef
.IsEmpty()) {
9635 char* tmpstr
= ToNewCString(mScrollToRef
);
9641 nsAutoCString unescapedRef
;
9642 unescapedRef
.Assign(tmpstr
);
9643 nsMemory::Free(tmpstr
);
9645 nsresult rv
= NS_ERROR_FAILURE
;
9646 // We assume that the bytes are in UTF-8, as it says in the spec:
9647 // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1
9648 NS_ConvertUTF8toUTF16
ref(unescapedRef
);
9650 nsCOMPtr
<nsIPresShell
> shell
= GetShell();
9652 // Check an empty string which might be caused by the UTF-8 conversion
9653 if (!ref
.IsEmpty()) {
9654 // Note that GoToAnchor will handle flushing layout as needed.
9655 rv
= shell
->GoToAnchor(ref
, mChangeScrollPosWhenScrollingToRef
);
9657 rv
= NS_ERROR_FAILURE
;
9660 // If UTF-8 URI failed then try to assume the string as a
9661 // document's charset.
9663 if (NS_FAILED(rv
)) {
9664 const nsACString
&docCharset
= GetDocumentCharacterSet();
9666 rv
= nsContentUtils::ConvertStringFromEncoding(docCharset
,
9670 if (NS_SUCCEEDED(rv
) && !ref
.IsEmpty()) {
9671 rv
= shell
->GoToAnchor(ref
, mChangeScrollPosWhenScrollingToRef
);
9674 if (NS_SUCCEEDED(rv
)) {
9675 mScrolledToRefAlready
= true;
9681 nsDocument::ResetScrolledToRefAlready()
9683 mScrolledToRefAlready
= false;
9687 nsDocument::SetChangeScrollPosWhenScrollingToRef(bool aValue
)
9689 mChangeScrollPosWhenScrollingToRef
= aValue
;
9693 nsIDocument::RegisterActivityObserver(nsISupports
* aSupports
)
9695 if (!mActivityObservers
) {
9696 mActivityObservers
= new nsTHashtable
<nsPtrHashKey
<nsISupports
> >();
9697 if (!mActivityObservers
)
9700 mActivityObservers
->PutEntry(aSupports
);
9704 nsIDocument::UnregisterActivityObserver(nsISupports
* aSupports
)
9706 if (!mActivityObservers
)
9708 if (!mActivityObservers
->GetEntry(aSupports
))
9710 mActivityObservers
->RemoveEntry(aSupports
);
9714 struct EnumerateActivityObserversData
{
9715 nsIDocument::ActivityObserverEnumerator mEnumerator
;
9719 static PLDHashOperator
9720 EnumerateObservers(nsPtrHashKey
<nsISupports
>* aEntry
, void* aData
)
9722 EnumerateActivityObserversData
* data
= static_cast<EnumerateActivityObserversData
*>(aData
);
9723 data
->mEnumerator(aEntry
->GetKey(), data
->mData
);
9724 return PL_DHASH_NEXT
;
9728 nsIDocument::EnumerateActivityObservers(ActivityObserverEnumerator aEnumerator
,
9731 if (!mActivityObservers
)
9733 EnumerateActivityObserversData data
= { aEnumerator
, aData
};
9734 mActivityObservers
->EnumerateEntries(EnumerateObservers
, &data
);
9738 nsIDocument::RegisterPendingLinkUpdate(Link
* aLink
)
9740 MOZ_ASSERT(!mIsLinkUpdateRegistrationsForbidden
);
9741 mLinksToUpdate
.PutEntry(aLink
);
9742 mHasLinksToUpdate
= true;
9746 nsIDocument::UnregisterPendingLinkUpdate(Link
* aLink
)
9748 MOZ_ASSERT(!mIsLinkUpdateRegistrationsForbidden
);
9749 if (!mHasLinksToUpdate
)
9752 mLinksToUpdate
.RemoveEntry(aLink
);
9755 static PLDHashOperator
9756 EnumeratePendingLinkUpdates(nsPtrHashKey
<Link
>* aEntry
, void* aData
)
9758 aEntry
->GetKey()->GetElement()->UpdateLinkState(aEntry
->GetKey()->LinkState());
9759 return PL_DHASH_NEXT
;
9763 nsIDocument::FlushPendingLinkUpdates()
9765 MOZ_ASSERT(!mIsLinkUpdateRegistrationsForbidden
);
9766 if (!mHasLinksToUpdate
)
9770 AutoRestore
<bool> saved(mIsLinkUpdateRegistrationsForbidden
);
9771 mIsLinkUpdateRegistrationsForbidden
= true;
9773 mLinksToUpdate
.EnumerateEntries(EnumeratePendingLinkUpdates
, nullptr);
9774 mLinksToUpdate
.Clear();
9775 mHasLinksToUpdate
= false;
9778 already_AddRefed
<nsIDocument
>
9779 nsIDocument::CreateStaticClone(nsIDocShell
* aCloneContainer
)
9781 nsDocument
* thisAsDoc
= static_cast<nsDocument
*>(this);
9782 mCreatingStaticClone
= true;
9784 // Make document use different container during cloning.
9785 nsRefPtr
<nsDocShell
> originalShell
= mDocumentContainer
.get();
9786 SetContainer(static_cast<nsDocShell
*>(aCloneContainer
));
9787 nsCOMPtr
<nsIDOMNode
> clonedNode
;
9788 nsresult rv
= thisAsDoc
->CloneNode(true, 1, getter_AddRefs(clonedNode
));
9789 SetContainer(originalShell
);
9791 nsRefPtr
<nsDocument
> clonedDoc
;
9792 if (NS_SUCCEEDED(rv
)) {
9793 nsCOMPtr
<nsIDocument
> tmp
= do_QueryInterface(clonedNode
);
9795 clonedDoc
= static_cast<nsDocument
*>(tmp
.get());
9796 if (IsStaticDocument()) {
9797 clonedDoc
->mOriginalDocument
= mOriginalDocument
;
9799 clonedDoc
->mOriginalDocument
= this;
9801 int32_t sheetsCount
= GetNumberOfStyleSheets();
9802 for (int32_t i
= 0; i
< sheetsCount
; ++i
) {
9803 nsRefPtr
<CSSStyleSheet
> sheet
= do_QueryObject(GetStyleSheetAt(i
));
9805 if (sheet
->IsApplicable()) {
9806 nsRefPtr
<CSSStyleSheet
> clonedSheet
=
9807 sheet
->Clone(nullptr, nullptr, clonedDoc
, nullptr);
9808 NS_WARN_IF_FALSE(clonedSheet
, "Cloning a stylesheet didn't work!");
9810 clonedDoc
->AddStyleSheet(clonedSheet
);
9816 sheetsCount
= thisAsDoc
->mOnDemandBuiltInUASheets
.Count();
9817 // Iterate backwards to maintain order
9818 for (int32_t i
= sheetsCount
- 1; i
>= 0; --i
) {
9819 nsRefPtr
<CSSStyleSheet
> sheet
=
9820 do_QueryObject(thisAsDoc
->mOnDemandBuiltInUASheets
[i
]);
9822 if (sheet
->IsApplicable()) {
9823 nsRefPtr
<CSSStyleSheet
> clonedSheet
=
9824 sheet
->Clone(nullptr, nullptr, clonedDoc
, nullptr);
9825 NS_WARN_IF_FALSE(clonedSheet
, "Cloning a stylesheet didn't work!");
9827 clonedDoc
->AddOnDemandBuiltInUASheet(clonedSheet
);
9834 mCreatingStaticClone
= false;
9835 return clonedDoc
.forget();
9839 nsIDocument::ScheduleFrameRequestCallback(const FrameRequestCallbackHolder
& aCallback
,
9842 if (mFrameRequestCallbackCounter
== INT32_MAX
) {
9843 // Can't increment without overflowing; bail out
9844 return NS_ERROR_NOT_AVAILABLE
;
9846 int32_t newHandle
= ++mFrameRequestCallbackCounter
;
9848 bool alreadyRegistered
= !mFrameRequestCallbacks
.IsEmpty();
9849 DebugOnly
<FrameRequest
*> request
=
9850 mFrameRequestCallbacks
.AppendElement(FrameRequest(aCallback
, newHandle
));
9851 NS_ASSERTION(request
, "This is supposed to be infallible!");
9852 if (!alreadyRegistered
&& mPresShell
&& IsEventHandlingEnabled()) {
9853 mPresShell
->GetPresContext()->RefreshDriver()->
9854 ScheduleFrameRequestCallbacks(this);
9857 *aHandle
= newHandle
;
9862 nsIDocument::CancelFrameRequestCallback(int32_t aHandle
)
9864 // mFrameRequestCallbacks is stored sorted by handle
9865 if (mFrameRequestCallbacks
.RemoveElementSorted(aHandle
) &&
9866 mFrameRequestCallbacks
.IsEmpty() &&
9867 mPresShell
&& IsEventHandlingEnabled()) {
9868 mPresShell
->GetPresContext()->RefreshDriver()->
9869 RevokeFrameRequestCallbacks(this);
9874 nsDocument::GetStateObject(nsIVariant
** aState
)
9876 // Get the document's current state object. This is the object backing both
9877 // history.state and popStateEvent.state.
9879 // mStateObjectContainer may be null; this just means that there's no
9880 // current state object.
9882 nsCOMPtr
<nsIVariant
> stateObj
;
9883 if (!mStateObjectCached
&& mStateObjectContainer
) {
9885 nsIGlobalObject
* sgo
= GetScopeObject();
9886 NS_ENSURE_TRUE(sgo
, NS_ERROR_UNEXPECTED
);
9887 JS::Rooted
<JSObject
*> global(cx
, sgo
->GetGlobalJSObject());
9888 NS_ENSURE_TRUE(global
, NS_ERROR_UNEXPECTED
);
9889 JSAutoCompartment
ac(cx
, global
);
9891 mStateObjectContainer
->
9892 DeserializeToVariant(cx
, getter_AddRefs(mStateObjectCached
));
9895 NS_IF_ADDREF(*aState
= mStateObjectCached
);
9900 nsDOMNavigationTiming
*
9901 nsDocument::GetNavigationTiming() const
9907 nsDocument::SetNavigationTiming(nsDOMNavigationTiming
* aTiming
)
9910 if (!mLoadingTimeStamp
.IsNull() && mTiming
) {
9911 mTiming
->SetDOMLoadingTimeStamp(nsIDocument::GetDocumentURI(), mLoadingTimeStamp
);
9917 nsDocument::FindImageMap(const nsAString
& aUseMapValue
)
9919 if (aUseMapValue
.IsEmpty()) {
9923 nsAString::const_iterator start
, end
;
9924 aUseMapValue
.BeginReading(start
);
9925 aUseMapValue
.EndReading(end
);
9927 int32_t hash
= aUseMapValue
.FindChar('#');
9931 // aUsemap contains a '#', set start to point right after the '#'
9932 start
.advance(hash
+ 1);
9935 return nullptr; // aUsemap == "#"
9938 const nsAString
& mapName
= Substring(start
, end
);
9941 mImageMaps
= new nsContentList(this, kNameSpaceID_XHTML
, nsGkAtoms::map
, nsGkAtoms::map
);
9944 uint32_t i
, n
= mImageMaps
->Length(true);
9946 for (i
= 0; i
< n
; ++i
) {
9947 nsIContent
* map
= mImageMaps
->Item(i
);
9948 if (map
->AttrValueIs(kNameSpaceID_None
, nsGkAtoms::id
, mapName
,
9950 (map
->GetAttr(kNameSpaceID_None
, nsGkAtoms::name
, name
) &&
9951 mapName
.Equals(name
, nsCaseInsensitiveStringComparator()))) {
9952 return map
->AsElement();
9959 #define DEPRECATED_OPERATION(_op) #_op "Warning",
9960 static const char* kWarnings
[] = {
9961 #include "nsDeprecatedOperationList.h"
9964 #undef DEPRECATED_OPERATION
9967 nsIDocument::HasWarnedAbout(DeprecatedOperations aOperation
)
9969 static_assert(eDeprecatedOperationCount
<= 64,
9970 "Too many deprecated operations");
9971 return mWarnedAbout
& (1ull << aOperation
);
9975 nsIDocument::WarnOnceAbout(DeprecatedOperations aOperation
,
9976 bool asError
/* = false */)
9978 if (HasWarnedAbout(aOperation
)) {
9981 mWarnedAbout
|= (1ull << aOperation
);
9982 uint32_t flags
= asError
? nsIScriptError::errorFlag
9983 : nsIScriptError::warningFlag
;
9984 nsContentUtils::ReportToConsole(flags
,
9985 NS_LITERAL_CSTRING("DOM Core"), this,
9986 nsContentUtils::eDOM_PROPERTIES
,
9987 kWarnings
[aOperation
]);
9991 nsDocument::AddImage(imgIRequest
* aImage
)
9993 NS_ENSURE_ARG_POINTER(aImage
);
9995 // See if the image is already in the hashtable. If it is, get the old count.
9996 uint32_t oldCount
= 0;
9997 mImageTracker
.Get(aImage
, &oldCount
);
9999 // Put the image in the hashtable, with the proper count.
10000 mImageTracker
.Put(aImage
, oldCount
+ 1);
10002 nsresult rv
= NS_OK
;
10004 // If this is the first insertion and we're locking images, lock this image
10006 if (oldCount
== 0) {
10007 if (mLockingImages
)
10008 rv
= aImage
->LockImage();
10009 if (NS_SUCCEEDED(rv
) && (!sOnloadDecodeLimit
||
10010 mImageTracker
.Count() < sOnloadDecodeLimit
))
10011 rv
= aImage
->StartDecoding();
10014 // If this is the first insertion and we're animating images, request
10015 // that this image be animated too.
10016 if (oldCount
== 0 && mAnimatingImages
) {
10017 nsresult rv2
= aImage
->IncrementAnimationConsumers();
10018 rv
= NS_SUCCEEDED(rv
) ? rv2
: rv
;
10025 nsDocument::RemoveImage(imgIRequest
* aImage
, uint32_t aFlags
)
10027 NS_ENSURE_ARG_POINTER(aImage
);
10029 // Get the old count. It should exist and be > 0.
10030 uint32_t count
= 0;
10031 DebugOnly
<bool> found
= mImageTracker
.Get(aImage
, &count
);
10032 NS_ABORT_IF_FALSE(found
, "Removing image that wasn't in the tracker!");
10033 NS_ABORT_IF_FALSE(count
> 0, "Entry in the cache tracker with count 0!");
10035 // We're removing, so decrement the count.
10038 // If the count is now zero, remove from the tracker.
10039 // Otherwise, set the new value.
10041 mImageTracker
.Put(aImage
, count
);
10045 mImageTracker
.Remove(aImage
);
10047 nsresult rv
= NS_OK
;
10049 // Now that we're no longer tracking this image, unlock it if we'd
10050 // previously locked it.
10051 if (mLockingImages
) {
10052 rv
= aImage
->UnlockImage();
10055 // If we're animating images, remove our request to animate this one.
10056 if (mAnimatingImages
) {
10057 nsresult rv2
= aImage
->DecrementAnimationConsumers();
10058 rv
= NS_SUCCEEDED(rv
) ? rv2
: rv
;
10061 if (aFlags
& REQUEST_DISCARD
) {
10062 // Request that the image be discarded if nobody else holds a lock on it.
10063 // Do this even if !mLockingImages, because even if we didn't just unlock
10064 // this image, it might still be a candidate for discarding.
10065 aImage
->RequestDiscard();
10072 nsDocument::AddPlugin(nsIObjectLoadingContent
* aPlugin
)
10074 MOZ_ASSERT(aPlugin
);
10075 if (!mPlugins
.PutEntry(aPlugin
)) {
10076 return NS_ERROR_OUT_OF_MEMORY
;
10082 nsDocument::RemovePlugin(nsIObjectLoadingContent
* aPlugin
)
10084 MOZ_ASSERT(aPlugin
);
10085 mPlugins
.RemoveEntry(aPlugin
);
10089 AllSubDocumentPluginEnum(nsIDocument
* aDocument
, void* userArg
)
10091 nsTArray
<nsIObjectLoadingContent
*>* plugins
=
10092 reinterpret_cast< nsTArray
<nsIObjectLoadingContent
*>* >(userArg
);
10093 MOZ_ASSERT(plugins
);
10094 aDocument
->GetPlugins(*plugins
);
10098 static PLDHashOperator
10099 AllPluginEnum(nsPtrHashKey
<nsIObjectLoadingContent
>* aPlugin
, void* userArg
)
10101 nsTArray
<nsIObjectLoadingContent
*>* allPlugins
=
10102 reinterpret_cast< nsTArray
<nsIObjectLoadingContent
*>* >(userArg
);
10103 MOZ_ASSERT(allPlugins
);
10104 allPlugins
->AppendElement(aPlugin
->GetKey());
10105 return PL_DHASH_NEXT
;
10109 nsDocument::GetPlugins(nsTArray
<nsIObjectLoadingContent
*>& aPlugins
)
10111 aPlugins
.SetCapacity(aPlugins
.Length() + mPlugins
.Count());
10112 mPlugins
.EnumerateEntries(AllPluginEnum
, &aPlugins
);
10113 EnumerateSubDocuments(AllSubDocumentPluginEnum
, &aPlugins
);
10116 PLDHashOperator
LockEnumerator(imgIRequest
* aKey
,
10121 aKey
->RequestDecode();
10122 return PL_DHASH_NEXT
;
10125 PLDHashOperator
UnlockEnumerator(imgIRequest
* aKey
,
10129 aKey
->UnlockImage();
10130 return PL_DHASH_NEXT
;
10135 nsDocument::SetImageLockingState(bool aLocked
)
10137 if (XRE_GetProcessType() == GeckoProcessType_Content
&&
10138 !Preferences::GetBool("image.mem.allow_locking_in_content_processes", true)) {
10142 // If there's no change, there's nothing to do.
10143 if (mLockingImages
== aLocked
)
10146 // Otherwise, iterate over our images and perform the appropriate action.
10147 mImageTracker
.EnumerateRead(aLocked
? LockEnumerator
10148 : UnlockEnumerator
,
10152 mLockingImages
= aLocked
;
10157 PLDHashOperator
IncrementAnimationEnumerator(imgIRequest
* aKey
,
10161 aKey
->IncrementAnimationConsumers();
10162 return PL_DHASH_NEXT
;
10165 PLDHashOperator
DecrementAnimationEnumerator(imgIRequest
* aKey
,
10169 aKey
->DecrementAnimationConsumers();
10170 return PL_DHASH_NEXT
;
10174 nsDocument::SetImagesNeedAnimating(bool aAnimating
)
10176 // If there's no change, there's nothing to do.
10177 if (mAnimatingImages
== aAnimating
)
10180 // Otherwise, iterate over our images and perform the appropriate action.
10181 mImageTracker
.EnumerateRead(aAnimating
? IncrementAnimationEnumerator
10182 : DecrementAnimationEnumerator
,
10186 mAnimatingImages
= aAnimating
;
10189 already_AddRefed
<Touch
>
10190 nsIDocument::CreateTouch(nsIDOMWindow
* aView
,
10191 EventTarget
* aTarget
,
10192 int32_t aIdentifier
,
10193 int32_t aPageX
, int32_t aPageY
,
10194 int32_t aScreenX
, int32_t aScreenY
,
10195 int32_t aClientX
, int32_t aClientY
,
10196 int32_t aRadiusX
, int32_t aRadiusY
,
10197 float aRotationAngle
,
10200 nsRefPtr
<Touch
> touch
= new Touch(aTarget
,
10203 aScreenX
, aScreenY
,
10204 aClientX
, aClientY
,
10205 aRadiusX
, aRadiusY
,
10208 return touch
.forget();
10211 already_AddRefed
<TouchList
>
10212 nsIDocument::CreateTouchList()
10214 nsRefPtr
<TouchList
> retval
= new TouchList(ToSupports(this));
10215 return retval
.forget();
10218 already_AddRefed
<TouchList
>
10219 nsIDocument::CreateTouchList(Touch
& aTouch
,
10220 const Sequence
<OwningNonNull
<Touch
> >& aTouches
)
10222 nsRefPtr
<TouchList
> retval
= new TouchList(ToSupports(this));
10223 retval
->Append(&aTouch
);
10224 for (uint32_t i
= 0; i
< aTouches
.Length(); ++i
) {
10225 retval
->Append(aTouches
[i
].get());
10227 return retval
.forget();
10230 already_AddRefed
<TouchList
>
10231 nsIDocument::CreateTouchList(const Sequence
<OwningNonNull
<Touch
> >& aTouches
)
10233 nsRefPtr
<TouchList
> retval
= new TouchList(ToSupports(this));
10234 for (uint32_t i
= 0; i
< aTouches
.Length(); ++i
) {
10235 retval
->Append(aTouches
[i
].get());
10237 return retval
.forget();
10240 already_AddRefed
<nsDOMCaretPosition
>
10241 nsIDocument::CaretPositionFromPoint(float aX
, float aY
)
10243 nscoord x
= nsPresContext::CSSPixelsToAppUnits(aX
);
10244 nscoord y
= nsPresContext::CSSPixelsToAppUnits(aY
);
10247 FlushPendingNotifications(Flush_Layout
);
10249 nsIPresShell
*ps
= GetShell();
10254 nsIFrame
*rootFrame
= ps
->GetRootFrame();
10256 // XUL docs, unlike HTML, have no frame tree until everything's done loading
10261 nsIFrame
*ptFrame
= nsLayoutUtils::GetFrameForPoint(rootFrame
, pt
,
10262 nsLayoutUtils::IGNORE_PAINT_SUPPRESSION
| nsLayoutUtils::IGNORE_CROSS_DOC
);
10267 // GetContentOffsetsFromPoint requires frame-relative coordinates, so we need
10268 // to adjust to frame-relative coordinates before we can perform this call.
10269 // It should also not take into account the padding of the frame.
10270 nsPoint adjustedPoint
= pt
- ptFrame
->GetOffsetTo(rootFrame
);
10272 nsFrame::ContentOffsets offsets
=
10273 ptFrame
->GetContentOffsetsFromPoint(adjustedPoint
);
10275 nsCOMPtr
<nsIContent
> node
= offsets
.content
;
10276 uint32_t offset
= offsets
.offset
;
10277 nsCOMPtr
<nsIContent
> anonNode
= node
;
10278 bool nodeIsAnonymous
= node
&& node
->IsInNativeAnonymousSubtree();
10279 if (nodeIsAnonymous
) {
10280 node
= ptFrame
->GetContent();
10281 nsIContent
* nonanon
= node
->FindFirstNonChromeOnlyAccessContent();
10282 nsCOMPtr
<nsIDOMHTMLInputElement
> input
= do_QueryInterface(nonanon
);
10283 nsCOMPtr
<nsIDOMHTMLTextAreaElement
> textArea
= do_QueryInterface(nonanon
);
10285 if (textArea
|| (input
&&
10286 NS_SUCCEEDED(input
->MozIsTextField(false, &isText
)) &&
10288 // If the anonymous content node has a child, then we need to make sure
10289 // that we get the appropriate child, as otherwise the offset may not be
10290 // correct when we construct a range for it.
10291 nsCOMPtr
<nsIContent
> firstChild
= anonNode
->GetFirstChild();
10293 anonNode
= firstChild
;
10297 offset
= nsContentUtils::GetAdjustedOffsetInTextControl(ptFrame
, offset
);
10307 nsRefPtr
<nsDOMCaretPosition
> aCaretPos
= new nsDOMCaretPosition(node
, offset
);
10308 if (nodeIsAnonymous
) {
10309 aCaretPos
->SetAnonymousContentNode(anonNode
);
10311 return aCaretPos
.forget();
10315 nsDocument::CaretPositionFromPoint(float aX
, float aY
, nsISupports
** aCaretPos
)
10317 NS_ENSURE_ARG_POINTER(aCaretPos
);
10318 *aCaretPos
= nsIDocument::CaretPositionFromPoint(aX
, aY
).take();
10323 nsIDocument::ObsoleteSheet(nsIURI
*aSheetURI
, ErrorResult
& rv
)
10325 nsresult res
= CSSLoader()->ObsoleteSheet(aSheetURI
);
10326 if (NS_FAILED(res
)) {
10332 nsIDocument::ObsoleteSheet(const nsAString
& aSheetURI
, ErrorResult
& rv
)
10334 nsCOMPtr
<nsIURI
> uri
;
10335 nsresult res
= NS_NewURI(getter_AddRefs(uri
), aSheetURI
);
10336 if (NS_FAILED(res
)) {
10340 res
= CSSLoader()->ObsoleteSheet(uri
);
10341 if (NS_FAILED(res
)) {
10347 nsIDocument::Children()
10349 if (!mChildrenCollection
) {
10350 mChildrenCollection
= new nsContentList(this, kNameSpaceID_Wildcard
,
10351 nsGkAtoms::_asterix
,
10352 nsGkAtoms::_asterix
,
10356 return mChildrenCollection
;
10360 nsIDocument::ChildElementCount()
10362 return Children()->Length();
10365 namespace mozilla
{
10367 // Singleton class to manage the list of fullscreen documents which are the
10368 // root of a branch which contains fullscreen documents. We maintain this list
10369 // so that we can easily exit all windows from fullscreen when the user
10370 // presses the escape key.
10371 class FullscreenRoots
{
10373 // Adds a root to the manager. Adding a root multiple times does not result
10374 // in duplicate entries for that item, only one.
10375 static void Add(nsIDocument
* aRoot
);
10377 // Iterates over every root in the root list, and calls aFunction, passing
10378 // each root once to aFunction. It is safe to call Add() and Remove() while
10379 // iterating over the list (i.e. in aFunction). Documents that are removed
10380 // from the manager during traversal are not traversed, and documents that
10381 // are added to the manager during traversal are also not traversed.
10382 static void ForEach(void(*aFunction
)(nsIDocument
* aDoc
));
10384 // Removes a specific root from the manager.
10385 static void Remove(nsIDocument
* aRoot
);
10387 // Returns true if all roots added to the list have been removed.
10388 static bool IsEmpty();
10392 FullscreenRoots() {
10393 MOZ_COUNT_CTOR(FullscreenRoots
);
10395 ~FullscreenRoots() {
10396 MOZ_COUNT_DTOR(FullscreenRoots
);
10400 NotFound
= uint32_t(-1)
10402 // Looks in mRoots for aRoot. Returns the index if found, otherwise NotFound.
10403 static uint32_t Find(nsIDocument
* aRoot
);
10405 // Returns true if aRoot is in the list of fullscreen roots.
10406 static bool Contains(nsIDocument
* aRoot
);
10408 // Singleton instance of the FullscreenRoots. This is instantiated when a
10409 // root is added, and it is deleted when the last root is removed.
10410 static FullscreenRoots
* sInstance
;
10412 // List of weak pointers to roots.
10413 nsTArray
<nsWeakPtr
> mRoots
;
10416 FullscreenRoots
* FullscreenRoots::sInstance
= nullptr;
10420 FullscreenRoots::ForEach(void(*aFunction
)(nsIDocument
* aDoc
))
10425 // Create a copy of the roots array, and iterate over the copy. This is so
10426 // that if an element is removed from mRoots we don't mess up our iteration.
10427 nsTArray
<nsWeakPtr
> roots(sInstance
->mRoots
);
10428 // Call aFunction on all entries.
10429 for (uint32_t i
= 0; i
< roots
.Length(); i
++) {
10430 nsCOMPtr
<nsIDocument
> root
= do_QueryReferent(roots
[i
]);
10431 // Check that the root isn't in the manager. This is so that new additions
10432 // while we were running don't get traversed.
10433 if (root
&& FullscreenRoots::Contains(root
)) {
10441 FullscreenRoots::Contains(nsIDocument
* aRoot
)
10443 return FullscreenRoots::Find(aRoot
) != NotFound
;
10448 FullscreenRoots::Add(nsIDocument
* aRoot
)
10450 if (!FullscreenRoots::Contains(aRoot
)) {
10452 sInstance
= new FullscreenRoots();
10454 nsWeakPtr weakRoot
= do_GetWeakReference(aRoot
);
10455 sInstance
->mRoots
.AppendElement(weakRoot
);
10461 FullscreenRoots::Find(nsIDocument
* aRoot
)
10466 nsTArray
<nsWeakPtr
>& roots
= sInstance
->mRoots
;
10467 for (uint32_t i
= 0; i
< roots
.Length(); i
++) {
10468 nsCOMPtr
<nsIDocument
> otherRoot(do_QueryReferent(roots
[i
]));
10469 if (otherRoot
== aRoot
) {
10478 FullscreenRoots::Remove(nsIDocument
* aRoot
)
10480 uint32_t index
= Find(aRoot
);
10481 NS_ASSERTION(index
!= NotFound
,
10482 "Should only try to remove roots which are still added!");
10483 if (index
== NotFound
|| !sInstance
) {
10486 sInstance
->mRoots
.RemoveElementAt(index
);
10487 if (sInstance
->mRoots
.IsEmpty()) {
10489 sInstance
= nullptr;
10495 FullscreenRoots::IsEmpty()
10500 } // end namespace mozilla.
10501 using mozilla::FullscreenRoots
;
10504 nsDocument::GetFullscreenRoot()
10506 nsCOMPtr
<nsIDocument
> root
= do_QueryReferent(mFullscreenRoot
);
10511 nsDocument::SetFullscreenRoot(nsIDocument
* aRoot
)
10513 mFullscreenRoot
= do_GetWeakReference(aRoot
);
10517 nsDocument::MozCancelFullScreen()
10519 nsIDocument::MozCancelFullScreen();
10524 nsIDocument::MozCancelFullScreen()
10526 RestorePreviousFullScreenState();
10529 // Runnable to set window full-screen mode. Used as a script runner
10530 // to ensure we only call nsGlobalWindow::SetFullScreen() when it's safe to
10531 // run script. nsGlobalWindow::SetFullScreen() dispatches a synchronous event
10532 // (handled in chome code) which is unsafe to run if this is called in
10533 // Element::UnbindFromTree().
10534 class nsSetWindowFullScreen
: public nsRunnable
{
10536 nsSetWindowFullScreen(nsIDocument
* aDoc
, bool aValue
)
10537 : mDoc(aDoc
), mValue(aValue
) {}
10541 if (mDoc
->GetWindow()) {
10542 mDoc
->GetWindow()->SetFullScreenInternal(mValue
, false);
10548 nsCOMPtr
<nsIDocument
> mDoc
;
10552 static nsIDocument
*
10553 GetFullscreenRootDocument(nsIDocument
* aDoc
)
10558 nsIDocument
* doc
= aDoc
;
10559 nsIDocument
* parent
;
10560 while ((parent
= doc
->GetParentDocument()) &&
10561 (!nsContentUtils::IsFullscreenApiContentOnly() ||
10562 !nsContentUtils::IsChromeDoc(parent
))) {
10569 SetWindowFullScreen(nsIDocument
* aDoc
, bool aValue
)
10571 // Maintain list of fullscreen root documents.
10572 nsCOMPtr
<nsIDocument
> root
= GetFullscreenRootDocument(aDoc
);
10574 FullscreenRoots::Add(root
);
10576 FullscreenRoots::Remove(root
);
10578 if (!nsContentUtils::IsFullscreenApiContentOnly()) {
10579 nsContentUtils::AddScriptRunner(new nsSetWindowFullScreen(aDoc
, aValue
));
10583 class nsCallExitFullscreen
: public nsRunnable
{
10585 explicit nsCallExitFullscreen(nsIDocument
* aDoc
)
10589 nsDocument::ExitFullscreen(mDoc
);
10593 nsCOMPtr
<nsIDocument
> mDoc
;
10598 nsIDocument::ExitFullscreen(nsIDocument
* aDoc
, bool aRunAsync
)
10600 if (aDoc
&& !aDoc
->IsFullScreenDoc()) {
10604 NS_DispatchToCurrentThread(new nsCallExitFullscreen(aDoc
));
10607 nsDocument::ExitFullscreen(aDoc
);
10610 // Returns true if the document is a direct child of a cross process parent
10611 // mozbrowser iframe or TabParent. This is the case when the document has
10612 // a null parent and its DocShell reports that it is a browser frame, or
10613 // we can get a TabChild from it.
10615 HasCrossProcessParent(nsIDocument
* aDocument
)
10617 if (XRE_GetProcessType() != GeckoProcessType_Content
) {
10620 if (aDocument
->GetParentDocument() != nullptr) {
10623 nsPIDOMWindow
* win
= aDocument
->GetWindow();
10627 nsCOMPtr
<nsIDocShell
> docShell
= win
->GetDocShell();
10631 TabChild
* tabChild(TabChild::GetFrom(docShell
));
10640 CountFullscreenSubDocuments(nsIDocument
* aDoc
, void* aData
)
10642 if (aDoc
->IsFullScreenDoc()) {
10643 uint32_t* count
= static_cast<uint32_t*>(aData
);
10650 CountFullscreenSubDocuments(nsIDocument
* aDoc
)
10652 uint32_t count
= 0;
10653 aDoc
->EnumerateSubDocuments(CountFullscreenSubDocuments
, &count
);
10658 nsDocument::IsFullscreenLeaf()
10660 // A fullscreen leaf document is fullscreen, and has no fullscreen
10662 if (!IsFullScreenDoc()) {
10665 return CountFullscreenSubDocuments(this) == 0;
10669 ResetFullScreen(nsIDocument
* aDocument
, void* aData
)
10671 if (aDocument
->IsFullScreenDoc()) {
10672 NS_ASSERTION(CountFullscreenSubDocuments(aDocument
) <= 1,
10673 "Should have at most 1 fullscreen subdocument.");
10674 static_cast<nsDocument
*>(aDocument
)->CleanupFullscreenState();
10675 NS_ASSERTION(!aDocument
->IsFullScreenDoc(), "Should reset full-screen");
10676 nsTArray
<nsIDocument
*>* changed
= reinterpret_cast<nsTArray
<nsIDocument
*>*>(aData
);
10677 changed
->AppendElement(aDocument
);
10679 if (HasCrossProcessParent(aDocument
)) {
10680 // We're at the top of the content-process side doc tree. Ask the parent
10681 // process to exit fullscreen.
10682 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
10683 os
->NotifyObservers(aDocument
, "ask-parent-to-exit-fullscreen", nullptr);
10686 // Dispatch a notification so that if this document has any
10687 // cross-process subdocuments, they'll be notified to exit fullscreen.
10688 // The BrowserElementParent listens for this event and performs the
10689 // cross process notification if it has a remote child process.
10690 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
10691 os
->NotifyObservers(aDocument
, "ask-children-to-exit-fullscreen", nullptr);
10693 aDocument
->EnumerateSubDocuments(ResetFullScreen
, aData
);
10699 ExitFullscreenInDocTree(nsIDocument
* aMaybeNotARootDoc
)
10701 MOZ_ASSERT(aMaybeNotARootDoc
);
10702 nsCOMPtr
<nsIDocument
> root
= aMaybeNotARootDoc
->GetFullscreenRoot();
10703 NS_ASSERTION(root
, "Should have root when in fullscreen!");
10707 NS_ASSERTION(root
->IsFullScreenDoc(),
10708 "Fullscreen root should be a fullscreen doc...");
10710 // Stores a list of documents to which we must dispatch "mozfullscreenchange".
10711 // We're required by the spec to dispatch the events in leaf-to-root
10712 // order when exiting fullscreen, but we traverse the doctree in a
10713 // root-to-leaf order, so we save references to the documents we must
10714 // dispatch to so that we dispatch in the specified order.
10715 nsAutoTArray
<nsIDocument
*, 8> changed
;
10717 // Walk the tree of fullscreen documents, and reset their fullscreen state.
10718 ResetFullScreen(root
, static_cast<void*>(&changed
));
10720 // Dispatch "mozfullscreenchange" events. Note this loop is in reverse
10721 // order so that the events for the leaf document arrives before the root
10722 // document, as required by the spec.
10723 for (uint32_t i
= 0; i
< changed
.Length(); ++i
) {
10724 DispatchFullScreenChange(changed
[changed
.Length() - i
- 1]);
10727 NS_ASSERTION(!root
->IsFullScreenDoc(),
10728 "Fullscreen root should no longer be a fullscreen doc...");
10730 // Move the top-level window out of fullscreen mode.
10731 SetWindowFullScreen(root
, false);
10736 nsDocument::ExitFullscreen(nsIDocument
* aDoc
)
10738 // Unlock the pointer, if it's locked.
10739 nsCOMPtr
<Element
> pointerLockedElement
=
10740 do_QueryReferent(EventStateManager::sPointerLockedElement
);
10741 if (pointerLockedElement
) {
10746 ExitFullscreenInDocTree(aDoc
);
10750 // Clear fullscreen stacks in all fullscreen roots' descendant documents.
10751 FullscreenRoots::ForEach(&ExitFullscreenInDocTree
);
10752 NS_ASSERTION(FullscreenRoots::IsEmpty(),
10753 "Should have exited all fullscreen roots from fullscreen");
10757 GetFullscreenLeaf(nsIDocument
* aDoc
, void* aData
)
10759 if (aDoc
->IsFullscreenLeaf()) {
10760 nsIDocument
** result
= static_cast<nsIDocument
**>(aData
);
10763 } else if (aDoc
->IsFullScreenDoc()) {
10764 aDoc
->EnumerateSubDocuments(GetFullscreenLeaf
, aData
);
10769 static nsIDocument
*
10770 GetFullscreenLeaf(nsIDocument
* aDoc
)
10772 nsIDocument
* leaf
= nullptr;
10773 GetFullscreenLeaf(aDoc
, &leaf
);
10777 // Otherwise we could be either in a non-fullscreen doc tree, or we're
10778 // below the fullscreen doc. Start the search from the root.
10779 nsIDocument
* root
= GetFullscreenRootDocument(aDoc
);
10780 // Check that the root is actually fullscreen so we don't waste time walking
10781 // around its descendants.
10782 if (!root
->IsFullScreenDoc()) {
10785 GetFullscreenLeaf(root
, &leaf
);
10790 nsDocument::RestorePreviousFullScreenState()
10792 NS_ASSERTION(!IsFullScreenDoc() || !FullscreenRoots::IsEmpty(),
10793 "Should have at least 1 fullscreen root when fullscreen!");
10794 NS_ASSERTION(!nsContentUtils::IsFullscreenApiContentOnly() ||
10795 !nsContentUtils::IsChromeDoc(this),
10796 "Should not run RestorePreviousFullScreenState() on "
10797 "chrome document when fullscreen is content only");
10799 if (!IsFullScreenDoc() || !GetWindow() || FullscreenRoots::IsEmpty()) {
10803 // If fullscreen mode is updated the pointer should be unlocked
10804 nsCOMPtr
<Element
> pointerLockedElement
=
10805 do_QueryReferent(EventStateManager::sPointerLockedElement
);
10806 if (pointerLockedElement
) {
10810 nsCOMPtr
<nsIDocument
> fullScreenDoc
= GetFullscreenLeaf(this);
10812 // The fullscreen document may contain a <iframe mozbrowser> element which
10813 // has a cross process child. So send a notification so that its browser
10814 // parent will send a message to its child process to also exit fullscreen.
10815 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
10816 os
->NotifyObservers(fullScreenDoc
, "ask-children-to-exit-fullscreen", nullptr);
10818 // Clear full-screen stacks in all descendant in process documents, bottom up.
10819 nsIDocument
* doc
= fullScreenDoc
;
10820 while (doc
!= this) {
10821 NS_ASSERTION(doc
->IsFullScreenDoc(), "Should be full-screen doc");
10822 static_cast<nsDocument
*>(doc
)->CleanupFullscreenState();
10824 DispatchFullScreenChange(doc
);
10825 doc
= doc
->GetParentDocument();
10828 // Roll-back full-screen state to previous full-screen element.
10829 NS_ASSERTION(doc
== this, "Must have reached this doc.");
10830 while (doc
!= nullptr) {
10831 static_cast<nsDocument
*>(doc
)->FullScreenStackPop();
10833 DispatchFullScreenChange(doc
);
10834 if (static_cast<nsDocument
*>(doc
)->mFullScreenStack
.IsEmpty()) {
10835 if (HasCrossProcessParent(doc
)) {
10836 // Send notification to the parent process to tell it to rollback to
10837 // the previous fullscreen elements in its fullscreen element stacks.
10838 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
10839 os
->NotifyObservers(doc
, "ask-parent-to-rollback-fullscreen", nullptr);
10841 // Full-screen stack in document is empty. Go back up to the parent
10842 // document. We'll pop the containing element off its stack, and use
10843 // its next full-screen element as the full-screen element.
10844 static_cast<nsDocument
*>(doc
)->CleanupFullscreenState();
10845 doc
= doc
->GetParentDocument();
10847 // Else we popped the top of the stack, and there's still another
10848 // element in there, so that will become the full-screen element.
10849 if (fullScreenDoc
!= doc
) {
10850 // We've popped so enough off the stack that we've rolled back to
10851 // a fullscreen element in a parent document. If this document isn't
10852 // approved for fullscreen, or if it's cross origin, dispatch an
10853 // event to chrome so it knows to show the authorization/warning UI.
10854 if (!nsContentUtils::HaveEqualPrincipals(fullScreenDoc
, doc
) ||
10855 (!nsContentUtils::IsSitePermAllow(doc
->NodePrincipal(), "fullscreen") &&
10856 !static_cast<nsDocument
*>(doc
)->mIsApprovedForFullscreen
)) {
10857 nsRefPtr
<AsyncEventDispatcher
> asyncDispatcher
=
10858 new AsyncEventDispatcher(doc
,
10859 NS_LITERAL_STRING("MozEnteredDomFullscreen"),
10862 asyncDispatcher
->PostDOMEvent();
10866 if (!nsContentUtils::HaveEqualPrincipals(doc
, fullScreenDoc
)) {
10867 // The origin which is fullscreen changed. Send a notification to
10868 // the root process so that a warning or approval UI can be shown
10870 nsAutoString origin
;
10871 nsContentUtils::GetUTFOrigin(doc
->NodePrincipal(), origin
);
10872 nsIDocument
* root
= GetFullscreenRootDocument(doc
);
10873 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
10874 os
->NotifyObservers(root
, "fullscreen-origin-change", origin
.get());
10881 if (doc
== nullptr) {
10882 // We moved all documents in this doctree out of fullscreen mode,
10883 // move the top-level window out of fullscreen mode.
10884 NS_ASSERTION(!GetFullscreenRootDocument(this)->IsFullScreenDoc(),
10885 "Should have cleared all docs' stacks");
10886 SetWindowFullScreen(this, false);
10891 nsDocument::IsFullScreenDoc()
10893 return GetFullScreenElement() != nullptr;
10896 class nsCallRequestFullScreen
: public nsRunnable
10899 explicit nsCallRequestFullScreen(Element
* aElement
)
10900 : mElement(aElement
),
10901 mDoc(aElement
->OwnerDoc()),
10902 mWasCallerChrome(nsContentUtils::IsCallerChrome()),
10903 mHadRequestPending(static_cast<nsDocument
*>(mDoc
.get())->
10904 mAsyncFullscreenPending
)
10906 static_cast<nsDocument
*>(mDoc
.get())->
10907 mAsyncFullscreenPending
= true;
10912 static_cast<nsDocument
*>(mDoc
.get())->
10913 mAsyncFullscreenPending
= mHadRequestPending
;
10914 nsDocument
* doc
= static_cast<nsDocument
*>(mDoc
.get());
10915 doc
->RequestFullScreen(mElement
,
10917 /* aNotifyOnOriginChange */ true);
10921 nsRefPtr
<Element
> mElement
;
10922 nsCOMPtr
<nsIDocument
> mDoc
;
10923 bool mWasCallerChrome
;
10924 bool mHadRequestPending
;
10928 nsDocument::AsyncRequestFullScreen(Element
* aElement
)
10930 NS_ASSERTION(aElement
,
10931 "Must pass non-null element to nsDocument::AsyncRequestFullScreen");
10935 // Request full-screen asynchronously.
10936 nsCOMPtr
<nsIRunnable
> event(new nsCallRequestFullScreen(aElement
));
10937 NS_DispatchToCurrentThread(event
);
10941 LogFullScreenDenied(bool aLogFailure
, const char* aMessage
, nsIDocument
* aDoc
)
10943 if (!aLogFailure
) {
10946 nsRefPtr
<AsyncEventDispatcher
> asyncDispatcher
=
10947 new AsyncEventDispatcher(aDoc
,
10948 NS_LITERAL_STRING("mozfullscreenerror"),
10951 asyncDispatcher
->PostDOMEvent();
10952 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag
,
10953 NS_LITERAL_CSTRING("DOM"), aDoc
,
10954 nsContentUtils::eDOM_PROPERTIES
,
10959 nsDocument::AddFullscreenApprovedObserver()
10961 if (mHasFullscreenApprovedObserver
||
10962 !Preferences::GetBool("full-screen-api.approval-required")) {
10966 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
10967 NS_ENSURE_TRUE(os
, NS_ERROR_FAILURE
);
10969 nsresult res
= os
->AddObserver(this, "fullscreen-approved", true);
10970 NS_ENSURE_SUCCESS(res
, res
);
10972 mHasFullscreenApprovedObserver
= true;
10978 nsDocument::RemoveFullscreenApprovedObserver()
10980 if (!mHasFullscreenApprovedObserver
) {
10983 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
10984 NS_ENSURE_TRUE(os
, NS_ERROR_FAILURE
);
10986 nsresult res
= os
->RemoveObserver(this, "fullscreen-approved");
10987 NS_ENSURE_SUCCESS(res
, res
);
10989 mHasFullscreenApprovedObserver
= false;
10995 nsDocument::CleanupFullscreenState()
10997 if (!mFullScreenStack
.IsEmpty()) {
10998 // The top element in the full-screen stack will have full-screen
10999 // style bits set on it and its ancestors. Remove the style bits.
11000 // Note the non-top elements won't have the style bits set.
11001 Element
* top
= FullScreenStackTop();
11002 NS_ASSERTION(top
, "Should have a top when full-screen stack isn't empty");
11004 EventStateManager::SetFullScreenState(top
, false);
11006 mFullScreenStack
.Clear();
11008 SetApprovedForFullscreen(false);
11009 RemoveFullscreenApprovedObserver();
11010 mFullscreenRoot
= nullptr;
11014 nsDocument::FullScreenStackPush(Element
* aElement
)
11016 NS_ASSERTION(aElement
, "Must pass non-null to FullScreenStackPush()");
11017 Element
* top
= FullScreenStackTop();
11018 if (top
== aElement
|| !aElement
) {
11022 // We're pushing a new element onto the full-screen stack, so we must
11023 // remove the ancestor and full-screen styles from the former top of the
11025 EventStateManager::SetFullScreenState(top
, false);
11027 EventStateManager::SetFullScreenState(aElement
, true);
11028 nsWeakPtr weakElement
= do_GetWeakReference(aElement
);
11029 mFullScreenStack
.AppendElement(weakElement
);
11030 NS_ASSERTION(GetFullScreenElement() == aElement
, "Should match");
11035 nsDocument::FullScreenStackPop()
11037 if (mFullScreenStack
.IsEmpty()) {
11041 // Remove styles from existing top element.
11042 Element
* top
= FullScreenStackTop();
11043 EventStateManager::SetFullScreenState(top
, false);
11045 // Remove top element. Note the remaining top element in the stack
11046 // will not have full-screen style bits set, so we will need to restore
11047 // them on the new top element before returning.
11048 uint32_t last
= mFullScreenStack
.Length() - 1;
11049 mFullScreenStack
.RemoveElementAt(last
);
11051 // Pop from the stack null elements (references to elements which have
11052 // been GC'd since they were added to the stack) and elements which are
11053 // no longer in this document.
11054 while (!mFullScreenStack
.IsEmpty()) {
11055 Element
* element
= FullScreenStackTop();
11056 if (!element
|| !element
->IsInDoc() || element
->OwnerDoc() != this) {
11057 NS_ASSERTION(!element
->IsFullScreenAncestor(),
11058 "Should have already removed full-screen styles");
11059 uint32_t last
= mFullScreenStack
.Length() - 1;
11060 mFullScreenStack
.RemoveElementAt(last
);
11062 // The top element of the stack is now an in-doc element. Apply the
11063 // full-screen styles and return.
11064 EventStateManager::SetFullScreenState(element
, true);
11071 nsDocument::FullScreenStackTop()
11073 if (mFullScreenStack
.IsEmpty()) {
11076 uint32_t last
= mFullScreenStack
.Length() - 1;
11077 nsCOMPtr
<Element
> element(do_QueryReferent(mFullScreenStack
[last
]));
11078 NS_ASSERTION(element
, "Should have full-screen element!");
11079 NS_ASSERTION(element
->IsInDoc(), "Full-screen element should be in doc");
11080 NS_ASSERTION(element
->OwnerDoc() == this, "Full-screen element should be in this doc");
11084 // Returns true if aDoc is in the focused tab in the active window.
11086 IsInActiveTab(nsIDocument
* aDoc
)
11088 nsCOMPtr
<nsIDocShell
> docshell
= aDoc
->GetDocShell();
11093 bool isActive
= false;
11094 docshell
->GetIsActive(&isActive
);
11099 nsCOMPtr
<nsIDocShellTreeItem
> rootItem
;
11100 docshell
->GetRootTreeItem(getter_AddRefs(rootItem
));
11104 nsCOMPtr
<nsIDOMWindow
> rootWin
= rootItem
->GetWindow();
11109 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
11114 nsCOMPtr
<nsIDOMWindow
> activeWindow
;
11115 fm
->GetActiveWindow(getter_AddRefs(activeWindow
));
11116 if (!activeWindow
) {
11120 return activeWindow
== rootWin
;
11123 nsresult
nsDocument::RemoteFrameFullscreenChanged(nsIDOMElement
* aFrameElement
,
11124 const nsAString
& aOrigin
)
11126 // Ensure the frame element is the fullscreen element in this document.
11127 // If the frame element is already the fullscreen element in this document,
11128 // this has no effect.
11129 nsCOMPtr
<nsIContent
> content(do_QueryInterface(aFrameElement
));
11130 RequestFullScreen(content
->AsElement(),
11131 /* aWasCallerChrome */ false,
11132 /* aNotifyOnOriginChange */ false);
11134 // Origin changed in child process, send notifiction, so that chrome can
11135 // update the UI to reflect the fullscreen origin change if necessary.
11136 // The BrowserElementChild listens on this, and forwards it over its
11137 // parent process, where it is redispatched. Chrome (in the root process,
11138 // which could be *this* process) listens for this notification so that
11139 // it can show a warning or approval UI.
11140 if (!aOrigin
.IsEmpty()) {
11141 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
11142 os
->NotifyObservers(GetFullscreenRootDocument(this),
11143 "fullscreen-origin-change",
11144 PromiseFlatString(aOrigin
).get());
11150 nsresult
nsDocument::RemoteFrameFullscreenReverted()
11152 RestorePreviousFullScreenState();
11157 nsDocument::RequestFullScreen(Element
* aElement
,
11158 bool aWasCallerChrome
,
11159 bool aNotifyOnOriginChange
)
11161 NS_ASSERTION(aElement
,
11162 "Must pass non-null element to nsDocument::RequestFullScreen");
11163 if (!aElement
|| aElement
== GetFullScreenElement()) {
11166 if (!aElement
->IsInDoc()) {
11167 LogFullScreenDenied(true, "FullScreenDeniedNotInDocument", this);
11170 if (aElement
->OwnerDoc() != this) {
11171 LogFullScreenDenied(true, "FullScreenDeniedMovedDocument", this);
11174 if (!GetWindow()) {
11175 LogFullScreenDenied(true, "FullScreenDeniedLostWindow", this);
11178 if (nsContentUtils::IsFullscreenApiContentOnly() &&
11179 nsContentUtils::IsChromeDoc(this)) {
11180 // Block fullscreen requests in the chrome document when the fullscreen API
11181 // is configured for content only.
11182 LogFullScreenDenied(true, "FullScreenDeniedContentOnly", this);
11185 if (!IsFullScreenEnabled(aWasCallerChrome
, true)) {
11186 // IsFullScreenEnabled calls LogFullScreenDenied, no need to log.
11189 if (GetFullScreenElement() &&
11190 !nsContentUtils::ContentIsDescendantOf(aElement
, GetFullScreenElement())) {
11191 // If this document is full-screen, only grant full-screen requests from
11192 // a descendant of the current full-screen element.
11193 LogFullScreenDenied(true, "FullScreenDeniedNotDescendant", this);
11196 if (!nsContentUtils::IsChromeDoc(this) && !IsInActiveTab(this)) {
11197 LogFullScreenDenied(true, "FullScreenDeniedNotFocusedTab", this);
11200 // Deny requests when a windowed plugin is focused.
11201 nsIFocusManager
* fm
= nsFocusManager::GetFocusManager();
11203 NS_WARNING("Failed to retrieve focus manager in full-screen request.");
11206 nsCOMPtr
<nsIDOMElement
> focusedElement
;
11207 fm
->GetFocusedElement(getter_AddRefs(focusedElement
));
11208 if (focusedElement
) {
11209 nsCOMPtr
<nsIContent
> content
= do_QueryInterface(focusedElement
);
11210 if (nsContentUtils::HasPluginWithUncontrolledEventDispatch(content
)) {
11211 LogFullScreenDenied(true, "FullScreenDeniedFocusedPlugin", this);
11216 // Stash a reference to any existing fullscreen doc, we'll use this later
11217 // to detect if the origin which is fullscreen has changed.
11218 nsCOMPtr
<nsIDocument
> previousFullscreenDoc
= GetFullscreenLeaf(this);
11220 AddFullscreenApprovedObserver();
11222 // Stores a list of documents which we must dispatch "mozfullscreenchange"
11223 // too. We're required by the spec to dispatch the events in root-to-leaf
11224 // order, but we traverse the doctree in a leaf-to-root order, so we save
11225 // references to the documents we must dispatch to so that we get the order
11227 nsAutoTArray
<nsIDocument
*, 8> changed
;
11229 // Remember the root document, so that if a full-screen document is hidden
11230 // we can reset full-screen state in the remaining visible full-screen documents.
11231 nsIDocument
* fullScreenRootDoc
= GetFullscreenRootDocument(this);
11232 if (fullScreenRootDoc
->IsFullScreenDoc()) {
11233 // A document is already in fullscreen, unlock the mouse pointer
11234 // before setting a new document to fullscreen
11238 // If a document is already in fullscreen, then unlock the mouse pointer
11239 // before setting a new document to fullscreen
11240 nsCOMPtr
<Element
> pointerLockedElement
=
11241 do_QueryReferent(EventStateManager::sPointerLockedElement
);
11242 if (pointerLockedElement
) {
11246 // Set the full-screen element. This sets the full-screen style on the
11247 // element, and the full-screen-ancestor styles on ancestors of the element
11248 // in this document.
11249 DebugOnly
<bool> x
= FullScreenStackPush(aElement
);
11250 NS_ASSERTION(x
, "Full-screen state of requesting doc should always change!");
11251 changed
.AppendElement(this);
11253 // Propagate up the document hierarchy, setting the full-screen element as
11254 // the element's container in ancestor documents. This also sets the
11255 // appropriate css styles as well. Note we don't propagate down the
11256 // document hierarchy, the full-screen element (or its container) is not
11257 // visible there. Stop when we reach the root document.
11258 nsIDocument
* child
= this;
11260 child
->SetFullscreenRoot(fullScreenRootDoc
);
11261 NS_ASSERTION(child
->GetFullscreenRoot() == fullScreenRootDoc
,
11262 "Fullscreen root should be set!");
11263 if (child
== fullScreenRootDoc
) {
11266 nsIDocument
* parent
= child
->GetParentDocument();
11267 Element
* element
= parent
->FindContentForSubDocument(child
)->AsElement();
11268 if (static_cast<nsDocument
*>(parent
)->FullScreenStackPush(element
)) {
11269 changed
.AppendElement(parent
);
11272 // We've reached either the root, or a point in the doctree where the
11273 // new full-screen element container is the same as the previous
11274 // full-screen element's container. No more changes need to be made
11275 // to the full-screen stacks of documents further up the tree.
11280 // Dispatch "mozfullscreenchange" events. Note this loop is in reverse
11281 // order so that the events for the root document arrives before the leaf
11282 // document, as required by the spec.
11283 for (uint32_t i
= 0; i
< changed
.Length(); ++i
) {
11284 DispatchFullScreenChange(changed
[changed
.Length() - i
- 1]);
11287 // If this document hasn't already been approved in this session,
11288 // check to see if the user has granted the fullscreen access
11289 // to the document's principal's host, if it has one. Note that documents
11290 // in web apps which are the same origin as the web app are considered
11291 // trusted and so are automatically approved.
11292 if (!mIsApprovedForFullscreen
) {
11293 mIsApprovedForFullscreen
=
11294 !Preferences::GetBool("full-screen-api.approval-required") ||
11295 NodePrincipal()->GetAppStatus() >= nsIPrincipal::APP_STATUS_INSTALLED
||
11296 nsContentUtils::IsSitePermAllow(NodePrincipal(), "fullscreen");
11299 // If this document, or a document with the same principal has not
11300 // already been approved for fullscreen this fullscreen-session, dispatch
11301 // an event so that chrome knows to pop up a warning/approval UI.
11302 // Note previousFullscreenDoc=nullptr upon first entry, so we always
11303 // take this path on the first time we enter fullscreen in a fullscreen
11305 if (!mIsApprovedForFullscreen
||
11306 !nsContentUtils::HaveEqualPrincipals(previousFullscreenDoc
, this)) {
11307 nsRefPtr
<AsyncEventDispatcher
> asyncDispatcher
=
11308 new AsyncEventDispatcher(this,
11309 NS_LITERAL_STRING("MozEnteredDomFullscreen"),
11312 asyncDispatcher
->PostDOMEvent();
11316 // Note assertions must run before SetWindowFullScreen() as that does
11317 // synchronous event dispatch which can run script which exits full-screen!
11318 NS_ASSERTION(GetFullScreenElement() == aElement
,
11319 "Full-screen element should be the requested element!");
11320 NS_ASSERTION(IsFullScreenDoc(), "Should be full-screen doc");
11321 nsCOMPtr
<nsIDOMElement
> fse
;
11322 GetMozFullScreenElement(getter_AddRefs(fse
));
11323 nsCOMPtr
<nsIContent
> c(do_QueryInterface(fse
));
11324 NS_ASSERTION(c
->AsElement() == aElement
,
11325 "GetMozFullScreenElement should match GetFullScreenElement()");
11328 // The origin which is fullscreen changed, send a notifiction so that the
11329 // root document knows the origin of the document which requested fullscreen.
11330 // This is used for the fullscreen approval UI. If we're in a child
11331 // process, the root BrowserElementChild listens for this notification,
11332 // and forwards it across to its BrowserElementParent, which
11333 // re-broadcasts the message for the root document in its process.
11334 if (aNotifyOnOriginChange
&&
11335 !nsContentUtils::HaveEqualPrincipals(previousFullscreenDoc
, this)) {
11336 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
11337 nsIDocument
* root
= GetFullscreenRootDocument(this);
11338 nsAutoString origin
;
11339 nsContentUtils::GetUTFOrigin(NodePrincipal(), origin
);
11340 os
->NotifyObservers(root
, "fullscreen-origin-change", origin
.get());
11343 // Make the window full-screen. Note we must make the state changes above
11344 // before making the window full-screen, as then the document reports as
11345 // being in full-screen mode when the chrome "fullscreen" event fires,
11346 // enabling chrome to distinguish between browser and dom full-screen
11347 // modes. Also note that nsGlobalWindow::SetFullScreen() (which
11348 // SetWindowFullScreen() calls) proxies to the root window in its hierarchy,
11349 // and does not operate on the a per-nsIDOMWindow basis.
11350 SetWindowFullScreen(this, true);
11354 nsDocument::GetMozFullScreenElement(nsIDOMElement
**aFullScreenElement
)
11357 Element
* el
= GetMozFullScreenElement(rv
);
11359 return rv
.ErrorCode();
11361 nsCOMPtr
<nsIDOMElement
> retval
= do_QueryInterface(el
);
11362 retval
.forget(aFullScreenElement
);
11367 nsDocument::GetMozFullScreenElement(ErrorResult
& rv
)
11369 if (IsFullScreenDoc()) {
11370 // Must have a full-screen element while in full-screen mode.
11371 Element
* el
= GetFullScreenElement();
11373 rv
.Throw(NS_ERROR_UNEXPECTED
);
11381 nsDocument::GetFullScreenElement()
11383 Element
* element
= FullScreenStackTop();
11384 NS_ASSERTION(!element
||
11385 element
->IsFullScreenAncestor(),
11386 "Fullscreen element should have fullscreen styles applied");
11391 nsDocument::GetMozFullScreen(bool *aFullScreen
)
11393 *aFullScreen
= MozFullScreen();
11398 nsDocument::GetMozFullScreenEnabled(bool *aFullScreen
)
11400 NS_ENSURE_ARG_POINTER(aFullScreen
);
11401 *aFullScreen
= MozFullScreenEnabled();
11406 nsDocument::MozFullScreenEnabled()
11408 return IsFullScreenEnabled(nsContentUtils::IsCallerChrome(), false);
11412 HasFullScreenSubDocument(nsIDocument
* aDoc
)
11414 uint32_t count
= CountFullscreenSubDocuments(aDoc
);
11415 NS_ASSERTION(count
<= 1, "Fullscreen docs should have at most 1 fullscreen child!");
11420 nsDocument::IsFullScreenEnabled(bool aCallerIsChrome
, bool aLogFailure
)
11422 if (nsContentUtils::IsFullScreenApiEnabled() && aCallerIsChrome
) {
11423 // Chrome code can always use the full-screen API, provided it's not
11424 // explicitly disabled. Note IsCallerChrome() returns true when running
11425 // in an nsRunnable, so don't use GetMozFullScreenEnabled() from an
11430 if (!nsContentUtils::IsFullScreenApiEnabled()) {
11431 LogFullScreenDenied(aLogFailure
, "FullScreenDeniedDisabled", this);
11434 if (!IsVisible()) {
11435 LogFullScreenDenied(aLogFailure
, "FullScreenDeniedHidden", this);
11438 if (HasFullScreenSubDocument(this)) {
11439 LogFullScreenDenied(aLogFailure
, "FullScreenDeniedSubDocFullScreen", this);
11443 // Ensure that all ancestor <iframe> elements have the allowfullscreen
11444 // boolean attribute set.
11445 nsCOMPtr
<nsIDocShell
> docShell(mDocumentContainer
);
11446 bool allowed
= false;
11448 docShell
->GetFullscreenAllowed(&allowed
);
11451 LogFullScreenDenied(aLogFailure
, "FullScreenDeniedIframeNotAllowed", this);
11458 DispatchPointerLockChange(nsIDocument
* aTarget
)
11464 nsRefPtr
<AsyncEventDispatcher
> asyncDispatcher
=
11465 new AsyncEventDispatcher(aTarget
,
11466 NS_LITERAL_STRING("mozpointerlockchange"),
11469 asyncDispatcher
->PostDOMEvent();
11473 DispatchPointerLockError(nsIDocument
* aTarget
)
11479 nsRefPtr
<AsyncEventDispatcher
> asyncDispatcher
=
11480 new AsyncEventDispatcher(aTarget
,
11481 NS_LITERAL_STRING("mozpointerlockerror"),
11484 asyncDispatcher
->PostDOMEvent();
11487 mozilla::StaticRefPtr
<nsPointerLockPermissionRequest
> gPendingPointerLockRequest
;
11489 class nsPointerLockPermissionRequest
: public nsRunnable
,
11490 public nsIContentPermissionRequest
11493 nsPointerLockPermissionRequest(Element
* aElement
, bool aUserInputOrChromeCaller
)
11494 : mElement(do_GetWeakReference(aElement
)),
11495 mDocument(do_GetWeakReference(aElement
->OwnerDoc())),
11496 mUserInputOrChromeCaller(aUserInputOrChromeCaller
) {}
11498 NS_DECL_ISUPPORTS_INHERITED
11499 NS_DECL_NSICONTENTPERMISSIONREQUEST
11503 nsCOMPtr
<Element
> e
= do_QueryReferent(mElement
);
11504 nsCOMPtr
<nsIDocument
> d
= do_QueryReferent(mDocument
);
11505 if (!e
|| !d
|| gPendingPointerLockRequest
!= this ||
11506 e
->GetCurrentDoc() != d
) {
11508 DispatchPointerLockError(d
);
11512 // We're about to enter fullscreen mode.
11513 nsDocument
* doc
= static_cast<nsDocument
*>(d
.get());
11514 if (doc
->mAsyncFullscreenPending
||
11515 (doc
->mHasFullscreenApprovedObserver
&& !doc
->mIsApprovedForFullscreen
)) {
11516 // We're still waiting for approval.
11520 if (doc
->mIsApprovedForFullscreen
|| doc
->mAllowRelocking
) {
11521 Allow(JS::UndefinedHandleValue
);
11525 // In non-fullscreen mode user input (or chrome caller) is required!
11526 // Also, don't let the page to try to get the permission too many times.
11527 if (!mUserInputOrChromeCaller
||
11528 doc
->mCancelledPointerLockRequests
> 2) {
11530 DispatchPointerLockError(d
);
11534 // Handling a request from user input in non-fullscreen mode.
11535 // Do a normal permission check.
11536 nsCOMPtr
<nsPIDOMWindow
> window
= doc
->GetInnerWindow();
11537 nsContentPermissionUtils::AskPermission(this, window
);
11543 mElement
= nullptr;
11544 mDocument
= nullptr;
11545 if (gPendingPointerLockRequest
== this) {
11546 gPendingPointerLockRequest
= nullptr;
11550 nsWeakPtr mElement
;
11551 nsWeakPtr mDocument
;
11552 bool mUserInputOrChromeCaller
;
11555 virtual ~nsPointerLockPermissionRequest() {}
11558 NS_IMPL_ISUPPORTS_INHERITED(nsPointerLockPermissionRequest
,
11560 nsIContentPermissionRequest
)
11563 nsPointerLockPermissionRequest::GetTypes(nsIArray
** aTypes
)
11565 nsTArray
<nsString
> emptyOptions
;
11566 return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("pointerLock"),
11567 NS_LITERAL_CSTRING("unused"),
11573 nsPointerLockPermissionRequest::GetPrincipal(nsIPrincipal
** aPrincipal
)
11575 nsCOMPtr
<nsIDocument
> d
= do_QueryReferent(mDocument
);
11577 NS_ADDREF(*aPrincipal
= d
->NodePrincipal());
11583 nsPointerLockPermissionRequest::GetWindow(nsIDOMWindow
** aWindow
)
11585 nsCOMPtr
<nsIDocument
> d
= do_QueryReferent(mDocument
);
11587 NS_IF_ADDREF(*aWindow
= d
->GetInnerWindow());
11593 nsPointerLockPermissionRequest::GetElement(nsIDOMElement
** aElement
)
11595 // It is enough to implement GetWindow.
11596 *aElement
= nullptr;
11601 nsPointerLockPermissionRequest::Cancel()
11603 nsCOMPtr
<nsIDocument
> d
= do_QueryReferent(mDocument
);
11606 static_cast<nsDocument
*>(d
.get())->mCancelledPointerLockRequests
++;
11607 DispatchPointerLockError(d
);
11613 nsPointerLockPermissionRequest::Allow(JS::HandleValue aChoices
)
11615 MOZ_ASSERT(aChoices
.isUndefined());
11617 nsCOMPtr
<Element
> e
= do_QueryReferent(mElement
);
11618 nsCOMPtr
<nsIDocument
> doc
= do_QueryReferent(mDocument
);
11619 nsDocument
* d
= static_cast<nsDocument
*>(doc
.get());
11620 if (!e
|| !d
|| gPendingPointerLockRequest
!= this ||
11621 e
->GetCurrentDoc() != d
||
11622 (!mUserInputOrChromeCaller
&& !d
->mIsApprovedForFullscreen
)) {
11624 DispatchPointerLockError(d
);
11628 // Mark handled here so that we don't need to call it everywhere below.
11631 nsCOMPtr
<Element
> pointerLockedElement
=
11632 do_QueryReferent(EventStateManager::sPointerLockedElement
);
11633 if (e
== pointerLockedElement
) {
11634 DispatchPointerLockChange(d
);
11638 // Note, we must bypass focus change, so pass true as the last parameter!
11639 if (!d
->ShouldLockPointer(e
, pointerLockedElement
, true)) {
11640 DispatchPointerLockError(d
);
11644 if (!d
->SetPointerLock(e
, NS_STYLE_CURSOR_NONE
)) {
11645 DispatchPointerLockError(d
);
11649 d
->mCancelledPointerLockRequests
= 0;
11650 e
->SetPointerLock();
11651 EventStateManager::sPointerLockedElement
= do_GetWeakReference(e
);
11652 EventStateManager::sPointerLockedDoc
= do_GetWeakReference(doc
);
11653 NS_ASSERTION(EventStateManager::sPointerLockedElement
&&
11654 EventStateManager::sPointerLockedDoc
,
11655 "aElement and this should support weak references!");
11657 DispatchPointerLockChange(d
);
11662 nsDocument::SetApprovedForFullscreen(bool aIsApproved
)
11664 mIsApprovedForFullscreen
= aIsApproved
;
11668 nsDocument::Observe(nsISupports
*aSubject
,
11669 const char *aTopic
,
11670 const char16_t
*aData
)
11672 if (strcmp("fullscreen-approved", aTopic
) == 0) {
11673 nsCOMPtr
<nsIDocument
> subject(do_QueryInterface(aSubject
));
11674 if (subject
!= this) {
11677 SetApprovedForFullscreen(true);
11678 if (gPendingPointerLockRequest
) {
11679 // We have a request pending. Create a clone of it and re-dispatch so that
11680 // Run() method gets called again.
11681 nsCOMPtr
<Element
> el
=
11682 do_QueryReferent(gPendingPointerLockRequest
->mElement
);
11683 nsCOMPtr
<nsIDocument
> doc
=
11684 do_QueryReferent(gPendingPointerLockRequest
->mDocument
);
11685 bool userInputOrChromeCaller
=
11686 gPendingPointerLockRequest
->mUserInputOrChromeCaller
;
11687 gPendingPointerLockRequest
->Handled();
11688 if (doc
== this && el
&& el
->GetCurrentDoc() == doc
) {
11689 nsPointerLockPermissionRequest
* clone
=
11690 new nsPointerLockPermissionRequest(el
, userInputOrChromeCaller
);
11691 gPendingPointerLockRequest
= clone
;
11692 nsCOMPtr
<nsIRunnable
> r
= gPendingPointerLockRequest
.get();
11693 NS_DispatchToMainThread(r
);
11696 } else if (strcmp("app-theme-changed", aTopic
) == 0) {
11697 if (!nsContentUtils::IsSystemPrincipal(NodePrincipal()) &&
11698 !IsUnstyledDocument()) {
11699 // We don't want to style the chrome window, only app ones.
11700 OnAppThemeChanged();
11707 nsDocument::OnAppThemeChanged()
11709 // Bail out if there is no theme support set up properly.
11710 auto themeOrigin
= Preferences::GetString("b2g.theme.origin");
11711 if (!themeOrigin
|| !Preferences::GetBool("dom.mozApps.themable")) {
11715 for (int32_t i
= 0; i
< GetNumberOfStyleSheets(); i
++) {
11716 nsRefPtr
<CSSStyleSheet
> sheet
= do_QueryObject(GetStyleSheetAt(i
));
11721 nsINode
* owningNode
= sheet
->GetOwnerNode();
11725 // Get a DOM stylesheet link to check the href against the theme origin.
11726 nsIURI
* sheetURI
= sheet
->GetOriginalURI();
11730 nsAutoString sheetOrigin
;
11731 nsContentUtils::GetUTFOrigin(sheetURI
, sheetOrigin
);
11732 if (!sheetOrigin
.Equals(themeOrigin
)) {
11736 // Finally getting a Stylesheet link.
11737 nsCOMPtr
<nsIStyleSheetLinkingElement
> link
= do_QueryInterface(owningNode
);
11743 link
->UpdateStyleSheet(nullptr, &willNotify
, &isAlternate
, true);
11748 nsDocument::RequestPointerLock(Element
* aElement
)
11750 NS_ASSERTION(aElement
,
11751 "Must pass non-null element to nsDocument::RequestPointerLock");
11753 nsCOMPtr
<Element
> pointerLockedElement
=
11754 do_QueryReferent(EventStateManager::sPointerLockedElement
);
11755 if (aElement
== pointerLockedElement
) {
11756 DispatchPointerLockChange(this);
11760 if (!ShouldLockPointer(aElement
, pointerLockedElement
)) {
11761 DispatchPointerLockError(this);
11765 bool userInputOrChromeCaller
= EventStateManager::IsHandlingUserInput() ||
11766 nsContentUtils::IsCallerChrome();
11768 gPendingPointerLockRequest
=
11769 new nsPointerLockPermissionRequest(aElement
, userInputOrChromeCaller
);
11770 nsCOMPtr
<nsIRunnable
> r
= gPendingPointerLockRequest
.get();
11771 NS_DispatchToMainThread(r
);
11775 nsDocument::ShouldLockPointer(Element
* aElement
, Element
* aCurrentLock
,
11776 bool aNoFocusCheck
)
11778 // Check if pointer lock pref is enabled
11779 if (!Preferences::GetBool("full-screen-api.pointer-lock.enabled")) {
11780 NS_WARNING("ShouldLockPointer(): Pointer Lock pref not enabled");
11784 if (aCurrentLock
&& aCurrentLock
->OwnerDoc() != aElement
->OwnerDoc()) {
11785 NS_WARNING("ShouldLockPointer(): Existing pointer lock element in a different document");
11789 if (!aElement
->IsInDoc()) {
11790 NS_WARNING("ShouldLockPointer(): Element without Document");
11794 if (mSandboxFlags
& SANDBOXED_POINTER_LOCK
) {
11795 NS_WARNING("ShouldLockPointer(): Document is sandboxed and doesn't allow pointer-lock");
11799 // Check if the element is in a document with a docshell.
11800 nsCOMPtr
<nsIDocument
> ownerDoc
= aElement
->OwnerDoc();
11801 if (!ownerDoc
->GetContainer()) {
11804 nsCOMPtr
<nsPIDOMWindow
> ownerWindow
= ownerDoc
->GetWindow();
11805 if (!ownerWindow
) {
11808 nsCOMPtr
<nsPIDOMWindow
> ownerInnerWindow
= ownerDoc
->GetInnerWindow();
11809 if (!ownerInnerWindow
) {
11812 if (ownerWindow
->GetCurrentInnerWindow() != ownerInnerWindow
) {
11816 nsCOMPtr
<nsIDOMWindow
> top
;
11817 ownerWindow
->GetScriptableTop(getter_AddRefs(top
));
11818 nsCOMPtr
<nsPIDOMWindow
> piTop
= do_QueryInterface(top
);
11819 if (!piTop
|| !piTop
->GetExtantDoc() ||
11820 piTop
->GetExtantDoc()->Hidden()) {
11821 NS_WARNING("ShouldLockPointer(): Top document isn't visible.");
11825 if (!aNoFocusCheck
) {
11826 mozilla::ErrorResult rv
;
11827 if (!piTop
->GetExtantDoc()->HasFocus(rv
)) {
11828 NS_WARNING("ShouldLockPointer(): Top document isn't focused.");
11837 nsDocument::SetPointerLock(Element
* aElement
, int aCursorStyle
)
11839 // NOTE: aElement will be nullptr when unlocking.
11840 nsCOMPtr
<nsPIDOMWindow
> window
= GetWindow();
11842 NS_WARNING("SetPointerLock(): No Window");
11846 nsIDocShell
*docShell
= window
->GetDocShell();
11848 NS_WARNING("SetPointerLock(): No DocShell (window already closed?)");
11852 nsRefPtr
<nsPresContext
> presContext
;
11853 docShell
->GetPresContext(getter_AddRefs(presContext
));
11854 if (!presContext
) {
11855 NS_WARNING("SetPointerLock(): Unable to get presContext in \
11856 domWindow->GetDocShell()->GetPresContext()");
11860 nsCOMPtr
<nsIPresShell
> shell
= presContext
->PresShell();
11862 NS_WARNING("SetPointerLock(): Unable to find presContext->PresShell()");
11866 nsIFrame
* rootFrame
= shell
->GetRootFrame();
11868 NS_WARNING("SetPointerLock(): Unable to get root frame");
11872 nsCOMPtr
<nsIWidget
> widget
= rootFrame
->GetNearestWidget();
11874 NS_WARNING("SetPointerLock(): Unable to find widget in \
11875 shell->GetRootFrame()->GetNearestWidget();");
11879 if (aElement
&& (aElement
->OwnerDoc() != this)) {
11880 NS_WARNING("SetPointerLock(): Element not in this document.");
11884 // Hide the cursor and set pointer lock for future mouse events
11885 nsRefPtr
<EventStateManager
> esm
= presContext
->EventStateManager();
11886 esm
->SetCursor(aCursorStyle
, nullptr, false,
11887 0.0f
, 0.0f
, widget
, true);
11888 esm
->SetPointerLock(widget
, aElement
);
11894 nsDocument::UnlockPointer(nsIDocument
* aDoc
)
11896 if (!EventStateManager::sIsPointerLocked
) {
11900 nsCOMPtr
<nsIDocument
> pointerLockedDoc
=
11901 do_QueryReferent(EventStateManager::sPointerLockedDoc
);
11902 if (!pointerLockedDoc
|| (aDoc
&& aDoc
!= pointerLockedDoc
)) {
11905 nsDocument
* doc
= static_cast<nsDocument
*>(pointerLockedDoc
.get());
11906 if (!doc
->SetPointerLock(nullptr, NS_STYLE_CURSOR_AUTO
)) {
11910 nsCOMPtr
<Element
> pointerLockedElement
=
11911 do_QueryReferent(EventStateManager::sPointerLockedElement
);
11912 if (pointerLockedElement
) {
11913 pointerLockedElement
->ClearPointerLock();
11916 EventStateManager::sPointerLockedElement
= nullptr;
11917 EventStateManager::sPointerLockedDoc
= nullptr;
11918 static_cast<nsDocument
*>(pointerLockedDoc
.get())->mAllowRelocking
= !!aDoc
;
11919 gPendingPointerLockRequest
= nullptr;
11920 DispatchPointerLockChange(pointerLockedDoc
);
11924 nsIDocument::UnlockPointer(nsIDocument
* aDoc
)
11926 nsDocument::UnlockPointer(aDoc
);
11930 nsDocument::MozExitPointerLock()
11932 nsIDocument::MozExitPointerLock();
11937 nsDocument::GetMozPointerLockElement(nsIDOMElement
** aPointerLockedElement
)
11939 Element
* el
= nsIDocument::GetMozPointerLockElement();
11940 nsCOMPtr
<nsIDOMElement
> retval
= do_QueryInterface(el
);
11941 retval
.forget(aPointerLockedElement
);
11946 nsIDocument::GetMozPointerLockElement()
11948 nsCOMPtr
<Element
> pointerLockedElement
=
11949 do_QueryReferent(EventStateManager::sPointerLockedElement
);
11950 if (!pointerLockedElement
) {
11954 // Make sure pointer locked element is in the same document.
11955 nsCOMPtr
<nsIDocument
> pointerLockedDoc
=
11956 do_QueryReferent(EventStateManager::sPointerLockedDoc
);
11957 if (pointerLockedDoc
!= this) {
11961 return pointerLockedElement
;
11965 nsDocument::XPCOMShutdown()
11967 gPendingPointerLockRequest
= nullptr;
11968 sProcessingStack
.reset();
11972 nsDocument::UpdateVisibilityState()
11974 dom::VisibilityState oldState
= mVisibilityState
;
11975 mVisibilityState
= GetVisibilityState();
11976 if (oldState
!= mVisibilityState
) {
11977 nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument
*>(this),
11978 NS_LITERAL_STRING("visibilitychange"),
11979 /* bubbles = */ true,
11980 /* cancelable = */ false);
11981 nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument
*>(this),
11982 NS_LITERAL_STRING("mozvisibilitychange"),
11983 /* bubbles = */ true,
11984 /* cancelable = */ false);
11986 EnumerateActivityObservers(NotifyActivityChanged
, nullptr);
11991 nsDocument::GetVisibilityState() const
11993 // We have to check a few pieces of information here:
11994 // 1) Are we in bfcache (!IsVisible())? If so, nothing else matters.
11995 // 2) Do we have an outer window? If not, we're hidden. Note that we don't
11996 // want to use GetWindow here because it does weird groveling for windows
11998 // 3) Is our outer window background? If so, we're hidden.
11999 // Otherwise, we're visible.
12000 if (!IsVisible() || !mWindow
|| !mWindow
->GetOuterWindow() ||
12001 mWindow
->GetOuterWindow()->IsBackground()) {
12002 return dom::VisibilityState::Hidden
;
12005 return dom::VisibilityState::Visible
;
12009 nsDocument::PostVisibilityUpdateEvent()
12011 nsCOMPtr
<nsIRunnable
> event
=
12012 NS_NewRunnableMethod(this, &nsDocument::UpdateVisibilityState
);
12013 NS_DispatchToMainThread(event
);
12017 nsDocument::GetMozHidden(bool* aHidden
)
12019 *aHidden
= MozHidden();
12024 nsDocument::GetHidden(bool* aHidden
)
12026 *aHidden
= Hidden();
12031 nsDocument::GetMozVisibilityState(nsAString
& aState
)
12033 WarnOnceAbout(ePrefixedVisibilityAPI
);
12034 return GetVisibilityState(aState
);
12038 nsDocument::GetVisibilityState(nsAString
& aState
)
12040 const EnumEntry
& entry
=
12041 VisibilityStateValues::strings
[static_cast<int>(mVisibilityState
)];
12042 aState
.AssignASCII(entry
.value
, entry
.length
);
12047 nsIDocument::DocAddSizeOfExcludingThis(nsWindowSizes
* aWindowSizes
) const
12049 aWindowSizes
->mDOMOtherSize
+=
12050 nsINode::SizeOfExcludingThis(aWindowSizes
->mMallocSizeOf
);
12053 mPresShell
->AddSizeOfIncludingThis(aWindowSizes
->mMallocSizeOf
,
12054 &aWindowSizes
->mArenaStats
,
12055 &aWindowSizes
->mLayoutPresShellSize
,
12056 &aWindowSizes
->mLayoutStyleSetsSize
,
12057 &aWindowSizes
->mLayoutTextRunsSize
,
12058 &aWindowSizes
->mLayoutPresContextSize
);
12061 aWindowSizes
->mPropertyTablesSize
+=
12062 mPropertyTable
.SizeOfExcludingThis(aWindowSizes
->mMallocSizeOf
);
12063 for (uint32_t i
= 0, count
= mExtraPropertyTables
.Length();
12065 aWindowSizes
->mPropertyTablesSize
+=
12066 mExtraPropertyTables
[i
]->SizeOfIncludingThis(aWindowSizes
->mMallocSizeOf
);
12069 if (EventListenerManager
* elm
= GetExistingListenerManager()) {
12070 aWindowSizes
->mDOMEventListenersCount
+= elm
->ListenerCount();
12073 // Measurement of the following members may be added later if DMD finds it
12079 nsIDocument::DocAddSizeOfIncludingThis(nsWindowSizes
* aWindowSizes
) const
12081 aWindowSizes
->mDOMOtherSize
+= aWindowSizes
->mMallocSizeOf(this);
12082 DocAddSizeOfExcludingThis(aWindowSizes
);
12086 SizeOfStyleSheetsElementIncludingThis(nsIStyleSheet
* aStyleSheet
,
12087 MallocSizeOf aMallocSizeOf
,
12090 if (!aStyleSheet
->GetOwningDocument()) {
12091 // Avoid over-reporting shared sheets.
12094 return aStyleSheet
->SizeOfIncludingThis(aMallocSizeOf
);
12098 nsDocument::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf
) const
12100 // This SizeOfExcludingThis() overrides the one from nsINode. But
12101 // nsDocuments can only appear at the top of the DOM tree, and we use the
12102 // specialized DocAddSizeOfExcludingThis() in that case. So this should never
12108 nsDocument::DocAddSizeOfExcludingThis(nsWindowSizes
* aWindowSizes
) const
12110 nsIDocument::DocAddSizeOfExcludingThis(aWindowSizes
);
12112 for (nsIContent
* node
= nsINode::GetFirstChild();
12114 node
= node
->GetNextNode(this))
12116 size_t nodeSize
= node
->SizeOfIncludingThis(aWindowSizes
->mMallocSizeOf
);
12119 switch (node
->NodeType()) {
12120 case nsIDOMNode::ELEMENT_NODE
:
12121 p
= &aWindowSizes
->mDOMElementNodesSize
;
12123 case nsIDOMNode::TEXT_NODE
:
12124 p
= &aWindowSizes
->mDOMTextNodesSize
;
12126 case nsIDOMNode::CDATA_SECTION_NODE
:
12127 p
= &aWindowSizes
->mDOMCDATANodesSize
;
12129 case nsIDOMNode::COMMENT_NODE
:
12130 p
= &aWindowSizes
->mDOMCommentNodesSize
;
12133 p
= &aWindowSizes
->mDOMOtherSize
;
12139 if (EventListenerManager
* elm
= node
->GetExistingListenerManager()) {
12140 aWindowSizes
->mDOMEventListenersCount
+= elm
->ListenerCount();
12144 aWindowSizes
->mStyleSheetsSize
+=
12145 mStyleSheets
.SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis
,
12146 aWindowSizes
->mMallocSizeOf
);
12147 // Note that we do not own the sheets pointed to by mOnDemandBuiltInUASheets
12148 // (the nsLayoutStyleSheetCache singleton does) so pass nullptr as the
12149 // aSizeOfElementIncludingThis callback argument.
12150 aWindowSizes
->mStyleSheetsSize
+=
12151 mOnDemandBuiltInUASheets
.SizeOfExcludingThis(nullptr,
12152 aWindowSizes
->mMallocSizeOf
);
12153 aWindowSizes
->mStyleSheetsSize
+=
12154 mAdditionalSheets
[eAgentSheet
].
12155 SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis
,
12156 aWindowSizes
->mMallocSizeOf
);
12157 aWindowSizes
->mStyleSheetsSize
+=
12158 mAdditionalSheets
[eUserSheet
].
12159 SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis
,
12160 aWindowSizes
->mMallocSizeOf
);
12161 aWindowSizes
->mStyleSheetsSize
+=
12162 mAdditionalSheets
[eAuthorSheet
].
12163 SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis
,
12164 aWindowSizes
->mMallocSizeOf
);
12165 // Lumping in the loader with the style-sheets size is not ideal,
12166 // but most of the things in there are in fact stylesheets, so it
12167 // doesn't seem worthwhile to separate it out.
12168 aWindowSizes
->mStyleSheetsSize
+=
12169 CSSLoader()->SizeOfIncludingThis(aWindowSizes
->mMallocSizeOf
);
12171 aWindowSizes
->mDOMOtherSize
+=
12173 mAttrStyleSheet
->DOMSizeOfIncludingThis(aWindowSizes
->mMallocSizeOf
) :
12176 aWindowSizes
->mDOMOtherSize
+=
12177 mStyledLinks
.SizeOfExcludingThis(nullptr, aWindowSizes
->mMallocSizeOf
);
12179 aWindowSizes
->mDOMOtherSize
+=
12180 mIdentifierMap
.SizeOfExcludingThis(aWindowSizes
->mMallocSizeOf
);
12182 // Measurement of the following members may be added later if DMD finds it
12188 nsDocument::QuerySelector(const nsAString
& aSelector
, nsIDOMElement
**aReturn
)
12190 return nsINode::QuerySelector(aSelector
, aReturn
);
12194 nsDocument::QuerySelectorAll(const nsAString
& aSelector
, nsIDOMNodeList
**aReturn
)
12196 return nsINode::QuerySelectorAll(aSelector
, aReturn
);
12199 already_AddRefed
<nsIDocument
>
12200 nsIDocument::Constructor(const GlobalObject
& aGlobal
,
12203 nsCOMPtr
<nsIScriptGlobalObject
> global
= do_QueryInterface(aGlobal
.GetAsSupports());
12205 rv
.Throw(NS_ERROR_UNEXPECTED
);
12209 nsCOMPtr
<nsIScriptObjectPrincipal
> prin
= do_QueryInterface(aGlobal
.GetAsSupports());
12211 rv
.Throw(NS_ERROR_UNEXPECTED
);
12215 nsCOMPtr
<nsIURI
> uri
;
12216 NS_NewURI(getter_AddRefs(uri
), "about:blank");
12218 rv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
12222 nsCOMPtr
<nsIDOMDocument
> document
;
12224 NS_NewDOMDocument(getter_AddRefs(document
),
12230 prin
->GetPrincipal(),
12233 DocumentFlavorPlain
);
12234 if (NS_FAILED(res
)) {
12239 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(document
);
12240 doc
->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE
);
12242 return doc
.forget();
12246 nsIDocument::CreateExpression(const nsAString
& aExpression
,
12247 nsIDOMXPathNSResolver
* aResolver
,
12250 return XPathEvaluator()->CreateExpression(aExpression
, aResolver
, rv
);
12253 already_AddRefed
<nsIDOMXPathNSResolver
>
12254 nsIDocument::CreateNSResolver(nsINode
* aNodeResolver
,
12257 return XPathEvaluator()->CreateNSResolver(aNodeResolver
, rv
);
12260 already_AddRefed
<XPathResult
>
12261 nsIDocument::Evaluate(JSContext
* aCx
, const nsAString
& aExpression
,
12262 nsINode
* aContextNode
, nsIDOMXPathNSResolver
* aResolver
,
12263 uint16_t aType
, JS::Handle
<JSObject
*> aResult
,
12266 return XPathEvaluator()->Evaluate(aCx
, aExpression
, aContextNode
, aResolver
,
12267 aType
, aResult
, rv
);
12271 nsDocument::CreateNSResolver(nsIDOMNode
* aNodeResolver
,
12272 nsIDOMXPathNSResolver
** aResult
)
12274 return XPathEvaluator()->CreateNSResolver(aNodeResolver
, aResult
);
12278 nsDocument::Evaluate(const nsAString
& aExpression
, nsIDOMNode
* aContextNode
,
12279 nsIDOMXPathNSResolver
* aResolver
, uint16_t aType
,
12280 nsISupports
* aInResult
, nsISupports
** aResult
)
12282 return XPathEvaluator()->Evaluate(aExpression
, aContextNode
, aResolver
, aType
,
12283 aInResult
, aResult
);
12286 // This is just a hack around the fact that window.document is not
12287 // [Unforgeable] yet.
12289 nsIDocument::WrapObject(JSContext
*aCx
)
12291 MOZ_ASSERT(IsDOMBinding());
12293 JS::Rooted
<JSObject
*> obj(aCx
, nsINode::WrapObject(aCx
));
12298 nsCOMPtr
<nsPIDOMWindow
> win
= do_QueryInterface(GetInnerWindow());
12300 static_cast<nsGlobalWindow
*>(win
.get())->IsDOMBinding()) {
12301 // No window or window on new DOM binding, nothing else to do here.
12305 if (this != win
->GetExtantDoc()) {
12306 // We're not the current document; we're also done here
12310 JSAutoCompartment
ac(aCx
, obj
);
12312 JS::Rooted
<JS::Value
> winVal(aCx
);
12313 nsresult rv
= nsContentUtils::WrapNative(aCx
, win
, &NS_GET_IID(nsIDOMWindow
),
12316 if (NS_FAILED(rv
)) {
12321 NS_NAMED_LITERAL_STRING(doc_str
, "document");
12323 JS::Rooted
<JSObject
*> winObj(aCx
, &winVal
.toObject());
12324 if (!JS_DefineUCProperty(aCx
, winObj
, doc_str
.get(),
12325 doc_str
.Length(), obj
,
12326 JSPROP_READONLY
| JSPROP_ENUMERATE
,
12327 JS_PropertyStub
, JS_StrictPropertyStub
)) {
12335 nsIDocument::XPathEvaluator()
12337 if (!mXPathEvaluator
) {
12338 mXPathEvaluator
= new dom::XPathEvaluator(this);
12340 return mXPathEvaluator
;
12343 already_AddRefed
<nsIDocumentEncoder
>
12344 nsIDocument::GetCachedEncoder()
12346 return mCachedEncoder
.forget();
12350 nsIDocument::SetCachedEncoder(already_AddRefed
<nsIDocumentEncoder
> aEncoder
)
12352 mCachedEncoder
= aEncoder
;
12356 nsIDocument::SetContentTypeInternal(const nsACString
& aType
)
12358 mCachedEncoder
= nullptr;
12359 mContentType
= aType
;
12363 nsIDocument::GetLoadContext() const
12365 return mDocumentContainer
;
12369 nsIDocument::GetDocShell() const
12371 return mDocumentContainer
;
12375 nsIDocument::SetStateObject(nsIStructuredCloneContainer
*scContainer
)
12377 mStateObjectContainer
= scContainer
;
12378 mStateObjectCached
= nullptr;
12381 already_AddRefed
<Element
>
12382 nsIDocument::CreateHTMLElement(nsIAtom
* aTag
)
12384 nsRefPtr
<mozilla::dom::NodeInfo
> nodeInfo
;
12385 nodeInfo
= mNodeInfoManager
->GetNodeInfo(aTag
, nullptr, kNameSpaceID_XHTML
,
12386 nsIDOMNode::ELEMENT_NODE
);
12387 MOZ_ASSERT(nodeInfo
, "GetNodeInfo should never fail");
12389 nsCOMPtr
<Element
> element
;
12390 DebugOnly
<nsresult
> rv
= NS_NewHTMLElement(getter_AddRefs(element
),
12392 mozilla::dom::NOT_FROM_PARSER
);
12394 MOZ_ASSERT(NS_SUCCEEDED(rv
), "NS_NewHTMLElement should never fail");
12395 return element
.forget();
12399 MarkDocumentTreeToBeInSyncOperation(nsIDocument
* aDoc
, void* aData
)
12401 nsCOMArray
<nsIDocument
>* documents
=
12402 static_cast<nsCOMArray
<nsIDocument
>*>(aData
);
12404 aDoc
->SetIsInSyncOperation(true);
12405 documents
->AppendObject(aDoc
);
12406 aDoc
->EnumerateSubDocuments(MarkDocumentTreeToBeInSyncOperation
, aData
);
12411 nsAutoSyncOperation::nsAutoSyncOperation(nsIDocument
* aDoc
)
12413 mMicroTaskLevel
= nsContentUtils::MicroTaskLevel();
12414 nsContentUtils::SetMicroTaskLevel(0);
12416 nsPIDOMWindow
* win
= aDoc
->GetWindow();
12418 nsCOMPtr
<nsIDOMWindow
> topWindow
;
12419 win
->GetTop(getter_AddRefs(topWindow
));
12420 nsCOMPtr
<nsPIDOMWindow
> top
= do_QueryInterface(topWindow
);
12422 nsCOMPtr
<nsIDocument
> doc
= top
->GetExtantDoc();
12423 MarkDocumentTreeToBeInSyncOperation(doc
, &mDocuments
);
12429 nsAutoSyncOperation::~nsAutoSyncOperation()
12431 for (int32_t i
= 0; i
< mDocuments
.Count(); ++i
) {
12432 mDocuments
[i
]->SetIsInSyncOperation(false);
12434 nsContentUtils::SetMicroTaskLevel(mMicroTaskLevel
);