Bug 1655413 [wpt PR 24763] - Make CSP default-src without 'unsafe-eval' block eval...
[gecko.git] / dom / html / nsHTMLDocument.cpp
bloba94089bb646e7959f682d08eb185f8e260e9e622
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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/. */
7 #include "nsHTMLDocument.h"
9 #include "mozilla/DebugOnly.h"
10 #include "mozilla/PresShell.h"
11 #include "mozilla/StaticPrefs_intl.h"
12 #include "nsCommandManager.h"
13 #include "nsCOMPtr.h"
14 #include "nsGlobalWindow.h"
15 #include "nsString.h"
16 #include "nsPrintfCString.h"
17 #include "nsReadableUtils.h"
18 #include "nsUnicharUtils.h"
19 #include "nsGlobalWindowInner.h"
20 #include "nsIHTMLContentSink.h"
21 #include "nsIProtocolHandler.h"
22 #include "nsIXMLContentSink.h"
23 #include "nsHTMLParts.h"
24 #include "nsHTMLStyleSheet.h"
25 #include "nsGkAtoms.h"
26 #include "nsPresContext.h"
27 #include "nsPIDOMWindow.h"
28 #include "nsDOMString.h"
29 #include "nsIStreamListener.h"
30 #include "nsIURI.h"
31 #include "nsNetUtil.h"
32 #include "nsIContentViewer.h"
33 #include "nsDocShell.h"
34 #include "nsDocShellLoadTypes.h"
35 #include "nsIScriptContext.h"
36 #include "nsContentList.h"
37 #include "nsError.h"
38 #include "nsIPrincipal.h"
39 #include "nsJSPrincipals.h"
40 #include "nsAttrName.h"
42 #include "nsNetCID.h"
43 #include "nsParserCIID.h"
44 #include "mozilla/parser/PrototypeDocumentParser.h"
45 #include "mozilla/dom/PrototypeDocumentContentSink.h"
46 #include "nsNameSpaceManager.h"
47 #include "nsGenericHTMLElement.h"
48 #include "mozilla/css/Loader.h"
49 #include "nsFrameSelection.h"
51 #include "nsContentUtils.h"
52 #include "nsJSUtils.h"
53 #include "DocumentInlines.h"
54 #include "nsICachingChannel.h"
55 #include "nsIContentViewer.h"
56 #include "nsIScriptElement.h"
57 #include "nsArrayUtils.h"
59 // AHMED 12-2
60 #include "nsBidiUtils.h"
62 #include "mozilla/Encoding.h"
63 #include "mozilla/EventListenerManager.h"
64 #include "mozilla/IdentifierMapEntry.h"
65 #include "mozilla/LoadInfo.h"
66 #include "nsNodeInfoManager.h"
67 #include "nsRange.h"
68 #include "mozAutoDocUpdate.h"
69 #include "nsCCUncollectableMarker.h"
70 #include "nsHtml5Module.h"
71 #include "mozilla/dom/Element.h"
72 #include "mozilla/Preferences.h"
73 #include "nsMimeTypes.h"
74 #include "nsIRequest.h"
75 #include "nsHtml5TreeOpExecutor.h"
76 #include "nsHtml5Parser.h"
77 #include "nsSandboxFlags.h"
78 #include "mozilla/dom/HTMLBodyElement.h"
79 #include "mozilla/dom/HTMLDocumentBinding.h"
80 #include "mozilla/dom/nsCSPContext.h"
81 #include "mozilla/dom/Selection.h"
82 #include "mozilla/dom/ShadowIncludingTreeIterator.h"
83 #include "nsCharsetSource.h"
84 #include "nsFocusManager.h"
85 #include "nsIFrame.h"
86 #include "nsIContent.h"
87 #include "mozilla/StyleSheet.h"
88 #include "mozilla/StyleSheetInlines.h"
89 #include "mozilla/Unused.h"
91 using namespace mozilla;
92 using namespace mozilla::dom;
94 #include "prtime.h"
96 //#define DEBUG_charset
98 static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
100 // ==================================================================
101 // =
102 // ==================================================================
104 static bool IsAsciiCompatible(const Encoding* aEncoding) {
105 return aEncoding->IsAsciiCompatible() || aEncoding == ISO_2022_JP_ENCODING;
108 nsresult NS_NewHTMLDocument(Document** aInstancePtrResult, bool aLoadedAsData) {
109 RefPtr<nsHTMLDocument> doc = new nsHTMLDocument();
111 nsresult rv = doc->Init();
113 if (NS_FAILED(rv)) {
114 *aInstancePtrResult = nullptr;
115 return rv;
118 doc->SetLoadedAsData(aLoadedAsData);
119 doc.forget(aInstancePtrResult);
121 return NS_OK;
124 nsHTMLDocument::nsHTMLDocument()
125 : Document("text/html"),
126 mContentListHolder(nullptr),
127 mNumForms(0),
128 mLoadFlags(0),
129 mWarnedWidthHeight(false),
130 mIsPlainText(false) {
131 mType = eHTML;
132 mDefaultElementType = kNameSpaceID_XHTML;
133 mCompatMode = eCompatibility_NavQuirks;
136 nsHTMLDocument::~nsHTMLDocument() = default;
138 JSObject* nsHTMLDocument::WrapNode(JSContext* aCx,
139 JS::Handle<JSObject*> aGivenProto) {
140 return HTMLDocument_Binding::Wrap(aCx, this, aGivenProto);
143 nsresult nsHTMLDocument::Init() {
144 nsresult rv = Document::Init();
145 NS_ENSURE_SUCCESS(rv, rv);
147 // Now reset the compatibility mode of the CSSLoader
148 // to match our compat mode.
149 CSSLoader()->SetCompatibilityMode(mCompatMode);
151 return NS_OK;
154 void nsHTMLDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) {
155 Document::Reset(aChannel, aLoadGroup);
157 if (aChannel) {
158 aChannel->GetLoadFlags(&mLoadFlags);
162 void nsHTMLDocument::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
163 nsIPrincipal* aPrincipal,
164 nsIPrincipal* aPartitionedPrincipal) {
165 mLoadFlags = nsIRequest::LOAD_NORMAL;
167 Document::ResetToURI(aURI, aLoadGroup, aPrincipal, aPartitionedPrincipal);
169 mImages = nullptr;
170 mApplets = nullptr;
171 mEmbeds = nullptr;
172 mLinks = nullptr;
173 mAnchors = nullptr;
174 mScripts = nullptr;
176 mForms = nullptr;
178 // Make the content type default to "text/html", we are a HTML
179 // document, after all. Once we start getting data, this may be
180 // changed.
181 SetContentTypeInternal(nsDependentCString("text/html"));
184 void nsHTMLDocument::TryHintCharset(nsIContentViewer* aCv,
185 int32_t& aCharsetSource,
186 NotNull<const Encoding*>& aEncoding) {
187 if (aCv) {
188 int32_t requestCharsetSource;
189 nsresult rv = aCv->GetHintCharacterSetSource(&requestCharsetSource);
191 if (NS_SUCCEEDED(rv) && kCharsetUninitialized != requestCharsetSource) {
192 auto requestCharset = aCv->GetHintCharset();
193 aCv->SetHintCharacterSetSource((int32_t)(kCharsetUninitialized));
195 if (requestCharsetSource <= aCharsetSource) return;
197 if (requestCharset && IsAsciiCompatible(requestCharset)) {
198 aCharsetSource = requestCharsetSource;
199 aEncoding = WrapNotNull(requestCharset);
205 void nsHTMLDocument::TryUserForcedCharset(nsIContentViewer* aCv,
206 nsIDocShell* aDocShell,
207 int32_t& aCharsetSource,
208 NotNull<const Encoding*>& aEncoding) {
209 if (kCharsetFromUserForced <= aCharsetSource) return;
211 // mCharacterSet not updated yet for channel, so check aEncoding, too.
212 if (WillIgnoreCharsetOverride() || !IsAsciiCompatible(aEncoding)) {
213 return;
216 if (aDocShell) {
217 // This is the Character Encoding menu code path in Firefox
218 auto encoding = nsDocShell::Cast(aDocShell)->GetForcedCharset();
220 if (encoding) {
221 if (!IsAsciiCompatible(encoding)) {
222 return;
224 aEncoding = WrapNotNull(encoding);
225 aCharsetSource = kCharsetFromUserForced;
226 aDocShell->SetCharset(EmptyCString());
231 void nsHTMLDocument::TryCacheCharset(nsICachingChannel* aCachingChannel,
232 int32_t& aCharsetSource,
233 NotNull<const Encoding*>& aEncoding) {
234 nsresult rv;
236 if (kCharsetFromCache <= aCharsetSource) {
237 return;
240 nsCString cachedCharset;
241 rv = aCachingChannel->GetCacheTokenCachedCharset(cachedCharset);
242 if (NS_FAILED(rv) || cachedCharset.IsEmpty()) {
243 return;
245 // The canonical names changed, so the cache may have an old name.
246 const Encoding* encoding = Encoding::ForLabelNoReplacement(cachedCharset);
247 if (!encoding) {
248 return;
250 // Check IsAsciiCompatible() even in the cache case, because the value
251 // might be stale and in the case of a stale charset that is not a rough
252 // ASCII superset, the parser has no way to recover.
253 if (!encoding->IsAsciiCompatible() && encoding != ISO_2022_JP_ENCODING) {
254 return;
256 aEncoding = WrapNotNull(encoding);
257 aCharsetSource = kCharsetFromCache;
260 void nsHTMLDocument::TryParentCharset(nsIDocShell* aDocShell,
261 int32_t& aCharsetSource,
262 NotNull<const Encoding*>& aEncoding) {
263 if (!aDocShell) {
264 return;
266 if (aCharsetSource >= kCharsetFromUserForced) {
267 return;
270 int32_t parentSource;
271 const Encoding* parentCharset;
272 nsCOMPtr<nsIPrincipal> parentPrincipal;
273 aDocShell->GetParentCharset(parentCharset, &parentSource,
274 getter_AddRefs(parentPrincipal));
275 if (!parentCharset) {
276 return;
278 if (kCharsetFromUserForced == parentSource ||
279 kCharsetFromUserForcedAutoDetection == parentSource) {
280 if (WillIgnoreCharsetOverride() ||
281 !IsAsciiCompatible(aEncoding) || // if channel said UTF-16
282 !IsAsciiCompatible(parentCharset)) {
283 return;
285 aEncoding = WrapNotNull(parentCharset);
286 aCharsetSource = kCharsetFromUserForced;
287 return;
290 if (aCharsetSource >= kCharsetFromParentFrame) {
291 return;
294 if (kCharsetFromCache <= parentSource) {
295 // Make sure that's OK
296 if (!NodePrincipal()->Equals(parentPrincipal) ||
297 !IsAsciiCompatible(parentCharset)) {
298 return;
301 aEncoding = WrapNotNull(parentCharset);
302 aCharsetSource = kCharsetFromParentFrame;
306 // Using a prototype document is only allowed with chrome privilege.
307 bool ShouldUsePrototypeDocument(nsIChannel* aChannel, Document* aDoc) {
308 if (!aChannel || !aDoc ||
309 !StaticPrefs::dom_prototype_document_cache_enabled()) {
310 return false;
312 return nsContentUtils::IsChromeDoc(aDoc);
315 nsresult nsHTMLDocument::StartDocumentLoad(const char* aCommand,
316 nsIChannel* aChannel,
317 nsILoadGroup* aLoadGroup,
318 nsISupports* aContainer,
319 nsIStreamListener** aDocListener,
320 bool aReset, nsIContentSink* aSink) {
321 if (!aCommand) {
322 MOZ_ASSERT(false, "Command is mandatory");
323 return NS_ERROR_INVALID_POINTER;
325 if (aSink) {
326 MOZ_ASSERT(false, "Got a sink override. Should not happen for HTML doc.");
327 return NS_ERROR_INVALID_ARG;
329 if (mType != eHTML) {
330 MOZ_ASSERT(mType == eXHTML);
331 MOZ_ASSERT(false, "Must not set HTML doc to XHTML mode before load start.");
332 return NS_ERROR_DOM_INVALID_STATE_ERR;
335 nsAutoCString contentType;
336 aChannel->GetContentType(contentType);
338 bool view =
339 !strcmp(aCommand, "view") || !strcmp(aCommand, "external-resource");
340 bool viewSource = !strcmp(aCommand, "view-source");
341 bool asData = !strcmp(aCommand, kLoadAsData);
342 if (!(view || viewSource || asData)) {
343 MOZ_ASSERT(false, "Bad parser command");
344 return NS_ERROR_INVALID_ARG;
347 bool html = contentType.EqualsLiteral(TEXT_HTML);
348 bool xhtml = !html && (contentType.EqualsLiteral(APPLICATION_XHTML_XML) ||
349 contentType.EqualsLiteral(APPLICATION_WAPXHTML_XML));
350 mIsPlainText =
351 !html && !xhtml && nsContentUtils::IsPlainTextType(contentType);
352 if (!(html || xhtml || mIsPlainText || viewSource)) {
353 MOZ_ASSERT(false, "Channel with bad content type.");
354 return NS_ERROR_INVALID_ARG;
357 bool forceUtf8 =
358 mIsPlainText && nsContentUtils::IsUtf8OnlyPlainTextType(contentType);
360 bool loadAsHtml5 = true;
362 if (!viewSource && xhtml) {
363 // We're parsing XHTML as XML, remember that.
364 mType = eXHTML;
365 SetCompatibilityMode(eCompatibility_FullStandards);
366 loadAsHtml5 = false;
369 // TODO: Proper about:blank treatment is bug 543435
370 if (loadAsHtml5 && view) {
371 // mDocumentURI hasn't been set, yet, so get the URI from the channel
372 nsCOMPtr<nsIURI> uri;
373 aChannel->GetOriginalURI(getter_AddRefs(uri));
374 // Adapted from nsDocShell:
375 // GetSpec can be expensive for some URIs, so check the scheme first.
376 if (uri && uri->SchemeIs("about")) {
377 if (uri->GetSpecOrDefault().EqualsLiteral("about:blank")) {
378 loadAsHtml5 = false;
383 nsresult rv = Document::StartDocumentLoad(aCommand, aChannel, aLoadGroup,
384 aContainer, aDocListener, aReset);
385 if (NS_FAILED(rv)) {
386 return rv;
389 nsCOMPtr<nsIURI> uri;
390 rv = aChannel->GetURI(getter_AddRefs(uri));
391 if (NS_FAILED(rv)) {
392 return rv;
395 nsCOMPtr<nsICachingChannel> cachingChan = do_QueryInterface(aChannel);
396 nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aContainer));
398 bool loadWithPrototype = false;
399 RefPtr<nsHtml5Parser> html5Parser;
400 if (loadAsHtml5) {
401 html5Parser = nsHtml5Module::NewHtml5Parser();
402 mParser = html5Parser;
403 if (mIsPlainText) {
404 if (viewSource) {
405 html5Parser->MarkAsNotScriptCreated("view-source-plain");
406 } else {
407 html5Parser->MarkAsNotScriptCreated("plain-text");
409 } else if (viewSource && !html) {
410 html5Parser->MarkAsNotScriptCreated("view-source-xml");
411 } else {
412 html5Parser->MarkAsNotScriptCreated(aCommand);
414 } else if (xhtml && ShouldUsePrototypeDocument(aChannel, this)) {
415 loadWithPrototype = true;
416 nsCOMPtr<nsIURI> originalURI;
417 aChannel->GetOriginalURI(getter_AddRefs(originalURI));
418 mParser = new mozilla::parser::PrototypeDocumentParser(originalURI, this);
419 } else {
420 mParser = do_CreateInstance(kCParserCID, &rv);
421 NS_ENSURE_SUCCESS(rv, rv);
424 // Look for the parent document. Note that at this point we don't have our
425 // content viewer set up yet, and therefore do not have a useful
426 // mParentDocument.
428 // in this block of code, if we get an error result, we return it
429 // but if we get a null pointer, that's perfectly legal for parent
430 // and parentContentViewer
431 nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
432 if (docShell) {
433 docShell->GetInProcessSameTypeParent(getter_AddRefs(parentAsItem));
436 nsCOMPtr<nsIDocShell> parent(do_QueryInterface(parentAsItem));
437 nsCOMPtr<nsIContentViewer> parentContentViewer;
438 if (parent) {
439 rv = parent->GetContentViewer(getter_AddRefs(parentContentViewer));
440 NS_ENSURE_SUCCESS(rv, rv);
443 nsCOMPtr<nsIContentViewer> cv;
444 if (docShell) {
445 docShell->GetContentViewer(getter_AddRefs(cv));
447 if (!cv) {
448 cv = std::move(parentContentViewer);
451 nsAutoCString urlSpec;
452 uri->GetSpec(urlSpec);
453 #ifdef DEBUG_charset
454 printf("Determining charset for %s\n", urlSpec.get());
455 #endif
457 // These are the charset source and charset for our document
458 int32_t charsetSource;
459 auto encoding = UTF_8_ENCODING;
461 // For error reporting and referrer policy setting
462 nsHtml5TreeOpExecutor* executor = nullptr;
463 if (loadAsHtml5) {
464 executor = static_cast<nsHtml5TreeOpExecutor*>(mParser->GetContentSink());
467 if (forceUtf8) {
468 charsetSource = kCharsetFromUtf8OnlyMime;
469 } else if (!IsHTMLDocument() || !docShell) { // no docshell for text/html XHR
470 charsetSource =
471 IsHTMLDocument() ? kCharsetFromFallback : kCharsetFromDocTypeDefault;
472 TryChannelCharset(aChannel, charsetSource, encoding, executor);
473 } else {
474 NS_ASSERTION(docShell, "Unexpected null value");
476 charsetSource = kCharsetUninitialized;
477 // Used for .in and .lk TLDs. .jp is handled in the parser.
478 encoding = WINDOWS_1252_ENCODING;
480 // The following will try to get the character encoding from various
481 // sources. Each Try* function will return early if the source is already
482 // at least as large as any of the sources it might look at. Some of
483 // these functions (like TryHintCharset and TryParentCharset) can set
484 // charsetSource to various values depending on where the charset they
485 // end up finding originally comes from.
487 // Try the channel's charset (e.g., charset from HTTP
488 // "Content-Type" header) first. This way, we get to reject overrides in
489 // TryParentCharset and TryUserForcedCharset if the channel said UTF-16.
490 // This is to avoid socially engineered XSS by adding user-supplied
491 // content to a UTF-16 site such that the byte have a dangerous
492 // interpretation as ASCII and the user can be lured to using the
493 // charset menu.
494 TryChannelCharset(aChannel, charsetSource, encoding, executor);
496 TryUserForcedCharset(cv, docShell, charsetSource, encoding);
498 TryHintCharset(cv, charsetSource, encoding); // For encoding reload
499 TryParentCharset(docShell, charsetSource, encoding);
501 if (cachingChan && !urlSpec.IsEmpty()) {
502 TryCacheCharset(cachingChan, charsetSource, encoding);
506 SetDocumentCharacterSetSource(charsetSource);
507 SetDocumentCharacterSet(encoding);
509 if (cachingChan) {
510 nsAutoCString charset;
511 encoding->Name(charset);
512 rv = cachingChan->SetCacheTokenCachedCharset(charset);
513 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "cannot SetMetaDataElement");
514 rv = NS_OK; // don't propagate error
517 // Set the parser as the stream listener for the document loader...
518 rv = NS_OK;
519 nsCOMPtr<nsIStreamListener> listener = mParser->GetStreamListener();
520 listener.forget(aDocListener);
522 #ifdef DEBUG_charset
523 printf(" charset = %s source %d\n", charset.get(), charsetSource);
524 #endif
525 mParser->SetDocumentCharset(encoding, charsetSource);
526 mParser->SetCommand(aCommand);
528 if (!IsHTMLDocument()) {
529 MOZ_ASSERT(!loadAsHtml5);
530 if (loadWithPrototype) {
531 nsCOMPtr<nsIContentSink> sink;
532 NS_NewPrototypeDocumentContentSink(getter_AddRefs(sink), this, uri,
533 docShell, aChannel);
534 mParser->SetContentSink(sink);
535 } else {
536 nsCOMPtr<nsIXMLContentSink> xmlsink;
537 NS_NewXMLContentSink(getter_AddRefs(xmlsink), this, uri, docShell,
538 aChannel);
539 mParser->SetContentSink(xmlsink);
541 } else {
542 if (loadAsHtml5) {
543 html5Parser->Initialize(this, uri, docShell, aChannel);
544 } else {
545 // about:blank *only*
546 nsCOMPtr<nsIHTMLContentSink> htmlsink;
547 NS_NewHTMLContentSink(getter_AddRefs(htmlsink), this, uri, docShell,
548 aChannel);
549 mParser->SetContentSink(htmlsink);
553 // parser the content of the URI
554 mParser->Parse(uri, nullptr, (void*)this);
556 return rv;
559 bool nsHTMLDocument::UseWidthDeviceWidthFallbackViewport() const {
560 if (mIsPlainText) {
561 // Plain text documents are simple enough that font inflation doesn't offer
562 // any appreciable advantage over defaulting to "width=device-width" and
563 // subsequently turning on word-wrapping.
564 return true;
566 return Document::UseWidthDeviceWidthFallbackViewport();
569 Element* nsHTMLDocument::GetUnfocusedKeyEventTarget() {
570 if (nsGenericHTMLElement* body = GetBody()) {
571 return body;
573 return Document::GetUnfocusedKeyEventTarget();
576 bool nsHTMLDocument::IsRegistrableDomainSuffixOfOrEqualTo(
577 const nsAString& aHostSuffixString, const nsACString& aOrigHost) {
578 // https://html.spec.whatwg.org/multipage/browsers.html#is-a-registrable-domain-suffix-of-or-is-equal-to
579 if (aHostSuffixString.IsEmpty()) {
580 return false;
583 nsCOMPtr<nsIURI> origURI = CreateInheritingURIForHost(aOrigHost);
584 if (!origURI) {
585 // Error: failed to parse input domain
586 return false;
589 nsCOMPtr<nsIURI> newURI =
590 RegistrableDomainSuffixOfInternal(aHostSuffixString, origURI);
591 if (!newURI) {
592 // Error: illegal domain
593 return false;
595 return true;
598 void nsHTMLDocument::AddedForm() { ++mNumForms; }
600 void nsHTMLDocument::RemovedForm() { --mNumForms; }
602 int32_t nsHTMLDocument::GetNumFormsSynchronous() { return mNumForms; }
604 bool nsHTMLDocument::ResolveName(JSContext* aCx, const nsAString& aName,
605 JS::MutableHandle<JS::Value> aRetval,
606 ErrorResult& aError) {
607 IdentifierMapEntry* entry = mIdentifierMap.GetEntry(aName);
608 if (!entry) {
609 return false;
612 nsBaseContentList* list = entry->GetNameContentList();
613 uint32_t length = list ? list->Length() : 0;
615 nsIContent* node;
616 if (length > 0) {
617 if (length > 1) {
618 // The list contains more than one element, return the whole list.
619 if (!ToJSValue(aCx, list, aRetval)) {
620 aError.NoteJSContextException(aCx);
621 return false;
623 return true;
626 // Only one element in the list, return the element instead of returning
627 // the list.
628 node = list->Item(0);
629 } else {
630 // No named items were found, see if there's one registerd by id for aName.
631 Element* e = entry->GetIdElement();
633 if (!e || !nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(e)) {
634 return false;
637 node = e;
640 if (!ToJSValue(aCx, node, aRetval)) {
641 aError.NoteJSContextException(aCx);
642 return false;
645 return true;
648 void nsHTMLDocument::GetSupportedNames(nsTArray<nsString>& aNames) {
649 for (auto iter = mIdentifierMap.Iter(); !iter.Done(); iter.Next()) {
650 IdentifierMapEntry* entry = iter.Get();
651 if (entry->HasNameElement() ||
652 entry->HasIdElementExposedAsHTMLDocumentProperty()) {
653 aNames.AppendElement(entry->GetKeyAsString());
658 //----------------------------
660 // forms related stuff
662 bool nsHTMLDocument::MatchFormControls(Element* aElement, int32_t aNamespaceID,
663 nsAtom* aAtom, void* aData) {
664 return aElement->IsNodeOfType(nsIContent::eHTML_FORM_CONTROL);
667 nsresult nsHTMLDocument::Clone(dom::NodeInfo* aNodeInfo,
668 nsINode** aResult) const {
669 NS_ASSERTION(aNodeInfo->NodeInfoManager() == mNodeInfoManager,
670 "Can't import this document into another document!");
672 RefPtr<nsHTMLDocument> clone = new nsHTMLDocument();
673 nsresult rv = CloneDocHelper(clone.get());
674 NS_ENSURE_SUCCESS(rv, rv);
676 // State from nsHTMLDocument
677 clone->mLoadFlags = mLoadFlags;
679 clone.forget(aResult);
680 return NS_OK;
683 /* virtual */
684 void nsHTMLDocument::DocAddSizeOfExcludingThis(
685 nsWindowSizes& aWindowSizes) const {
686 Document::DocAddSizeOfExcludingThis(aWindowSizes);
688 // Measurement of the following members may be added later if DMD finds it is
689 // worthwhile:
690 // - mLinks
691 // - mAnchors
694 bool nsHTMLDocument::WillIgnoreCharsetOverride() {
695 if (mEncodingMenuDisabled) {
696 return true;
698 if (mType != eHTML) {
699 MOZ_ASSERT(mType == eXHTML);
700 return true;
702 if (mCharacterSetSource >= kCharsetFromByteOrderMark) {
703 return true;
705 if (!mCharacterSet->IsAsciiCompatible() &&
706 mCharacterSet != ISO_2022_JP_ENCODING) {
707 return true;
709 nsIURI* uri = GetOriginalURI();
710 if (uri) {
711 if (uri->SchemeIs("about")) {
712 return true;
714 bool isResource;
715 nsresult rv = NS_URIChainHasFlags(
716 uri, nsIProtocolHandler::URI_IS_UI_RESOURCE, &isResource);
717 if (NS_FAILED(rv) || isResource) {
718 return true;
721 return false;
724 void nsHTMLDocument::GetFormsAndFormControls(nsContentList** aFormList,
725 nsContentList** aFormControlList) {
726 RefPtr<ContentListHolder> holder = mContentListHolder;
727 if (!holder) {
728 // Flush our content model so it'll be up to date
729 // If this becomes unnecessary and the following line is removed,
730 // please also remove the corresponding flush operation from
731 // nsHtml5TreeBuilderCppSupplement.h. (Look for "See bug 497861." there.)
732 // XXXsmaug nsHtml5TreeBuilderCppSupplement doesn't seem to have such flush
733 // anymore.
734 FlushPendingNotifications(FlushType::Content);
736 RefPtr<nsContentList> htmlForms = GetExistingForms();
737 if (!htmlForms) {
738 // If the document doesn't have an existing forms content list, create a
739 // new one which will be released soon by ContentListHolder. The idea is
740 // that we don't have that list hanging around for a long time and slowing
741 // down future DOM mutations.
743 // Please keep this in sync with Document::Forms().
744 htmlForms = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::form,
745 nsGkAtoms::form,
746 /* aDeep = */ true,
747 /* aLiveList = */ true);
750 RefPtr<nsContentList> htmlFormControls = new nsContentList(
751 this, nsHTMLDocument::MatchFormControls, nullptr, nullptr,
752 /* aDeep = */ true,
753 /* aMatchAtom = */ nullptr,
754 /* aMatchNameSpaceId = */ kNameSpaceID_None,
755 /* aFuncMayDependOnAttr = */ true,
756 /* aLiveList = */ true);
758 holder = new ContentListHolder(this, htmlForms, htmlFormControls);
759 RefPtr<ContentListHolder> runnable = holder;
760 if (NS_SUCCEEDED(
761 Dispatch(TaskCategory::GarbageCollection, runnable.forget()))) {
762 mContentListHolder = holder;
766 NS_ADDREF(*aFormList = holder->mFormList);
767 NS_ADDREF(*aFormControlList = holder->mFormControlList);