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 #include "mozilla/CheckedInt.h"
9 #include "mozilla/Likely.h"
10 #include "mozilla/StaticPrefs_dom.h"
11 #include "mozilla/StaticPrefs_network.h"
12 #include "mozilla/UniquePtr.h"
14 nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsHtml5OplessBuilder
* aBuilder
)
19 scriptingEnabled(false),
23 contextNamespace(kNameSpaceID_None
),
34 isSrcdocDocument(false),
40 mSpeculativeLoadStage(nullptr),
42 mCurrentHtmlScriptIsAsyncOrDefer(false),
43 mPreventScriptExecution(false)
49 MOZ_COUNT_CTOR(nsHtml5TreeBuilder
);
52 nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsAHtml5TreeOpSink
* aOpSink
,
53 nsHtml5TreeOpStage
* aStage
)
58 scriptingEnabled(false),
62 contextNamespace(kNameSpaceID_None
),
73 isSrcdocDocument(false),
77 mHandles(new nsIContent
*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH
]),
79 mSpeculativeLoadStage(aStage
),
81 mCurrentHtmlScriptIsAsyncOrDefer(false),
82 mPreventScriptExecution(false)
88 MOZ_COUNT_CTOR(nsHtml5TreeBuilder
);
91 nsHtml5TreeBuilder::~nsHtml5TreeBuilder() {
92 MOZ_COUNT_DTOR(nsHtml5TreeBuilder
);
93 NS_ASSERTION(!mActive
,
94 "nsHtml5TreeBuilder deleted without ever calling end() on it!");
98 nsIContentHandle
* nsHtml5TreeBuilder::createElement(
99 int32_t aNamespace
, nsAtom
* aName
, nsHtml5HtmlAttributes
* aAttributes
,
100 nsIContentHandle
* aIntendedParent
, nsHtml5ContentCreatorFunction aCreator
) {
101 MOZ_ASSERT(aAttributes
, "Got null attributes.");
102 MOZ_ASSERT(aName
, "Got null name.");
103 MOZ_ASSERT(aNamespace
== kNameSpaceID_XHTML
||
104 aNamespace
== kNameSpaceID_SVG
||
105 aNamespace
== kNameSpaceID_MathML
,
109 nsIContent
* intendedParent
=
110 aIntendedParent
? static_cast<nsIContent
*>(aIntendedParent
) : nullptr;
112 // intendedParent == nullptr is a special case where the
113 // intended parent is the document.
114 nsNodeInfoManager
* nodeInfoManager
=
115 intendedParent
? intendedParent
->OwnerDoc()->NodeInfoManager()
116 : mBuilder
->GetNodeInfoManager();
119 if (aNamespace
== kNameSpaceID_XHTML
) {
120 elem
= nsHtml5TreeOperation::CreateHTMLElement(
121 aName
, aAttributes
, mozilla::dom::FROM_PARSER_FRAGMENT
,
122 nodeInfoManager
, mBuilder
, aCreator
.html
);
123 } else if (aNamespace
== kNameSpaceID_SVG
) {
124 elem
= nsHtml5TreeOperation::CreateSVGElement(
125 aName
, aAttributes
, mozilla::dom::FROM_PARSER_FRAGMENT
,
126 nodeInfoManager
, mBuilder
, aCreator
.svg
);
128 MOZ_ASSERT(aNamespace
== kNameSpaceID_MathML
);
129 elem
= nsHtml5TreeOperation::CreateMathMLElement(
130 aName
, aAttributes
, nodeInfoManager
, mBuilder
);
132 if (MOZ_UNLIKELY(aAttributes
!= tokenizer
->GetAttributes() &&
133 aAttributes
!= nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES
)) {
139 nsIContentHandle
* content
= AllocateContentHandle();
140 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
141 if (MOZ_UNLIKELY(!treeOp
)) {
142 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
146 if (aNamespace
== kNameSpaceID_XHTML
) {
147 opCreateHTMLElement
opeation(
148 content
, aName
, aAttributes
, aCreator
.html
, aIntendedParent
,
149 (!!mSpeculativeLoadStage
) ? mozilla::dom::FROM_PARSER_NETWORK
150 : mozilla::dom::FROM_PARSER_DOCUMENT_WRITE
);
151 treeOp
->Init(mozilla::AsVariant(opeation
));
152 } else if (aNamespace
== kNameSpaceID_SVG
) {
153 opCreateSVGElement
operation(
154 content
, aName
, aAttributes
, aCreator
.svg
, aIntendedParent
,
155 (!!mSpeculativeLoadStage
) ? mozilla::dom::FROM_PARSER_NETWORK
156 : mozilla::dom::FROM_PARSER_DOCUMENT_WRITE
);
157 treeOp
->Init(mozilla::AsVariant(operation
));
159 // kNameSpaceID_MathML
160 opCreateMathMLElement
operation(content
, aName
, aAttributes
,
162 treeOp
->Init(mozilla::AsVariant(operation
));
165 // mSpeculativeLoadStage is non-null only in the off-the-main-thread
166 // tree builder, which handles the network stream
168 // Start wall of code for speculative loading and line numbers
170 if (mSpeculativeLoadStage
&& mode
!= IN_TEMPLATE
) {
171 switch (aNamespace
) {
172 case kNameSpaceID_XHTML
:
173 if (nsGkAtoms::img
== aName
) {
174 nsHtml5String loading
=
175 aAttributes
->getValue(nsHtml5AttributeName::ATTR_LOADING
);
176 if (!StaticPrefs::dom_image_lazy_loading_enabled() ||
177 !loading
.LowerCaseEqualsASCII("lazy")) {
179 aAttributes
->getValue(nsHtml5AttributeName::ATTR_SRC
);
180 nsHtml5String srcset
=
181 aAttributes
->getValue(nsHtml5AttributeName::ATTR_SRCSET
);
182 nsHtml5String crossOrigin
=
183 aAttributes
->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN
);
184 nsHtml5String referrerPolicy
= aAttributes
->getValue(
185 nsHtml5AttributeName::ATTR_REFERRERPOLICY
);
186 nsHtml5String sizes
=
187 aAttributes
->getValue(nsHtml5AttributeName::ATTR_SIZES
);
188 mSpeculativeLoadQueue
.AppendElement()->InitImage(
189 url
, crossOrigin
, /* aMedia = */ nullptr, referrerPolicy
,
190 srcset
, sizes
, false);
192 } else if (nsGkAtoms::source
== aName
) {
193 nsHtml5String srcset
=
194 aAttributes
->getValue(nsHtml5AttributeName::ATTR_SRCSET
);
195 // Sources without srcset cannot be selected. The source could also be
196 // for a media element, but in that context doesn't use srcset. See
197 // comments in nsHtml5SpeculativeLoad.h about <picture> preloading
199 nsHtml5String sizes
=
200 aAttributes
->getValue(nsHtml5AttributeName::ATTR_SIZES
);
202 aAttributes
->getValue(nsHtml5AttributeName::ATTR_TYPE
);
203 nsHtml5String media
=
204 aAttributes
->getValue(nsHtml5AttributeName::ATTR_MEDIA
);
205 mSpeculativeLoadQueue
.AppendElement()->InitPictureSource(
206 srcset
, sizes
, type
, media
);
208 } else if (nsGkAtoms::script
== aName
) {
209 nsHtml5TreeOperation
* treeOp
=
210 mOpQueue
.AppendElement(mozilla::fallible
);
211 if (MOZ_UNLIKELY(!treeOp
)) {
212 MarkAsBrokenAndRequestSuspensionWithoutBuilder(
213 NS_ERROR_OUT_OF_MEMORY
);
216 opSetScriptLineNumberAndFreeze
operation(content
,
217 tokenizer
->getLineNumber());
218 treeOp
->Init(mozilla::AsVariant(operation
));
221 aAttributes
->getValue(nsHtml5AttributeName::ATTR_SRC
);
223 nsHtml5String charset
=
224 aAttributes
->getValue(nsHtml5AttributeName::ATTR_CHARSET
);
226 aAttributes
->getValue(nsHtml5AttributeName::ATTR_TYPE
);
227 nsHtml5String crossOrigin
=
228 aAttributes
->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN
);
229 nsHtml5String integrity
=
230 aAttributes
->getValue(nsHtml5AttributeName::ATTR_INTEGRITY
);
231 nsHtml5String referrerPolicy
= aAttributes
->getValue(
232 nsHtml5AttributeName::ATTR_REFERRERPOLICY
);
234 aAttributes
->contains(nsHtml5AttributeName::ATTR_ASYNC
);
236 aAttributes
->contains(nsHtml5AttributeName::ATTR_DEFER
);
238 aAttributes
->contains(nsHtml5AttributeName::ATTR_NOMODULE
);
239 mSpeculativeLoadQueue
.AppendElement()->InitScript(
240 url
, charset
, type
, crossOrigin
, /* aMedia = */ nullptr,
241 integrity
, referrerPolicy
, mode
== nsHtml5TreeBuilder::IN_HEAD
,
242 async
, defer
, noModule
, false);
243 mCurrentHtmlScriptIsAsyncOrDefer
= async
|| defer
;
245 } else if (nsGkAtoms::link
== aName
) {
247 aAttributes
->getValue(nsHtml5AttributeName::ATTR_REL
);
248 // Not splitting on space here is bogus but the old parser didn't even
249 // do a case-insensitive check.
251 if (rel
.LowerCaseEqualsASCII("stylesheet")) {
253 aAttributes
->getValue(nsHtml5AttributeName::ATTR_HREF
);
255 nsHtml5String charset
=
256 aAttributes
->getValue(nsHtml5AttributeName::ATTR_CHARSET
);
257 nsHtml5String crossOrigin
= aAttributes
->getValue(
258 nsHtml5AttributeName::ATTR_CROSSORIGIN
);
259 nsHtml5String integrity
=
260 aAttributes
->getValue(nsHtml5AttributeName::ATTR_INTEGRITY
);
261 nsHtml5String referrerPolicy
= aAttributes
->getValue(
262 nsHtml5AttributeName::ATTR_REFERRERPOLICY
);
263 nsHtml5String media
=
264 aAttributes
->getValue(nsHtml5AttributeName::ATTR_MEDIA
);
265 mSpeculativeLoadQueue
.AppendElement()->InitStyle(
266 url
, charset
, crossOrigin
, media
, referrerPolicy
, integrity
,
269 } else if (rel
.LowerCaseEqualsASCII("preconnect")) {
271 aAttributes
->getValue(nsHtml5AttributeName::ATTR_HREF
);
273 nsHtml5String crossOrigin
= aAttributes
->getValue(
274 nsHtml5AttributeName::ATTR_CROSSORIGIN
);
275 mSpeculativeLoadQueue
.AppendElement()->InitPreconnect(
278 } else if (StaticPrefs::network_preload() &&
279 rel
.LowerCaseEqualsASCII("preload")) {
281 aAttributes
->getValue(nsHtml5AttributeName::ATTR_HREF
);
284 aAttributes
->getValue(nsHtml5AttributeName::ATTR_AS
);
285 nsHtml5String charset
=
286 aAttributes
->getValue(nsHtml5AttributeName::ATTR_CHARSET
);
287 nsHtml5String crossOrigin
= aAttributes
->getValue(
288 nsHtml5AttributeName::ATTR_CROSSORIGIN
);
289 nsHtml5String integrity
=
290 aAttributes
->getValue(nsHtml5AttributeName::ATTR_INTEGRITY
);
291 nsHtml5String referrerPolicy
= aAttributes
->getValue(
292 nsHtml5AttributeName::ATTR_REFERRERPOLICY
);
293 nsHtml5String media
=
294 aAttributes
->getValue(nsHtml5AttributeName::ATTR_MEDIA
);
296 // Note that respective speculative loaders for scripts and
297 // styles check all additional attributes to be equal to use the
298 // speculative load. So, if any of them is specified and the
299 // preload has to take the expected effect, those attributes
300 // must also be specified on the actual tag to use the preload.
301 // Omitting an attribute on both will make the values equal
302 // (empty) and thus use the preload.
303 if (as
.LowerCaseEqualsASCII("script")) {
305 aAttributes
->getValue(nsHtml5AttributeName::ATTR_TYPE
);
306 mSpeculativeLoadQueue
.AppendElement()->InitScript(
307 url
, charset
, type
, crossOrigin
, media
, integrity
,
308 referrerPolicy
, mode
== nsHtml5TreeBuilder::IN_HEAD
,
309 false, false, false, true);
310 } else if (as
.LowerCaseEqualsASCII("style")) {
311 mSpeculativeLoadQueue
.AppendElement()->InitStyle(
312 url
, charset
, crossOrigin
, media
, referrerPolicy
,
314 } else if (as
.LowerCaseEqualsASCII("image")) {
315 nsHtml5String srcset
= aAttributes
->getValue(
316 nsHtml5AttributeName::ATTR_IMAGESRCSET
);
317 nsHtml5String sizes
= aAttributes
->getValue(
318 nsHtml5AttributeName::ATTR_IMAGESIZES
);
319 mSpeculativeLoadQueue
.AppendElement()->InitImage(
320 url
, crossOrigin
, media
, referrerPolicy
, srcset
, sizes
,
322 } else if (as
.LowerCaseEqualsASCII("font")) {
323 mSpeculativeLoadQueue
.AppendElement()->InitFont(
324 url
, crossOrigin
, media
, referrerPolicy
);
325 } else if (as
.LowerCaseEqualsASCII("fetch")) {
326 mSpeculativeLoadQueue
.AppendElement()->InitFetch(
327 url
, crossOrigin
, media
, referrerPolicy
);
329 // Other "as" values will be supported later.
333 } else if (nsGkAtoms::video
== aName
) {
335 aAttributes
->getValue(nsHtml5AttributeName::ATTR_POSTER
);
337 mSpeculativeLoadQueue
.AppendElement()->InitImage(
338 url
, nullptr, nullptr, nullptr, nullptr, nullptr, false);
340 } else if (nsGkAtoms::style
== aName
) {
341 mImportScanner
.Start();
342 nsHtml5TreeOperation
* treeOp
=
343 mOpQueue
.AppendElement(mozilla::fallible
);
344 if (MOZ_UNLIKELY(!treeOp
)) {
345 MarkAsBrokenAndRequestSuspensionWithoutBuilder(
346 NS_ERROR_OUT_OF_MEMORY
);
349 opSetStyleLineNumber
operation(content
, tokenizer
->getLineNumber());
350 treeOp
->Init(mozilla::AsVariant(operation
));
351 } else if (nsGkAtoms::html
== aName
) {
353 aAttributes
->getValue(nsHtml5AttributeName::ATTR_MANIFEST
);
354 mSpeculativeLoadQueue
.AppendElement()->InitManifest(url
);
355 } else if (nsGkAtoms::base
== aName
) {
357 aAttributes
->getValue(nsHtml5AttributeName::ATTR_HREF
);
359 mSpeculativeLoadQueue
.AppendElement()->InitBase(url
);
361 } else if (nsGkAtoms::meta
== aName
) {
362 if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
363 "content-security-policy",
364 aAttributes
->getValue(
365 nsHtml5AttributeName::ATTR_HTTP_EQUIV
))) {
367 aAttributes
->getValue(nsHtml5AttributeName::ATTR_CONTENT
);
369 mSpeculativeLoadQueue
.AppendElement()->InitMetaCSP(csp
);
371 } else if (nsHtml5Portability::
372 lowerCaseLiteralEqualsIgnoreAsciiCaseString(
374 aAttributes
->getValue(
375 nsHtml5AttributeName::ATTR_NAME
))) {
376 nsHtml5String referrerPolicy
=
377 aAttributes
->getValue(nsHtml5AttributeName::ATTR_CONTENT
);
378 if (referrerPolicy
) {
379 mSpeculativeLoadQueue
.AppendElement()->InitMetaReferrerPolicy(
385 case kNameSpaceID_SVG
:
386 if (nsGkAtoms::image
== aName
) {
388 aAttributes
->getValue(nsHtml5AttributeName::ATTR_HREF
);
390 url
= aAttributes
->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF
);
393 mSpeculativeLoadQueue
.AppendElement()->InitImage(
394 url
, nullptr, nullptr, nullptr, nullptr, nullptr, false);
396 } else if (nsGkAtoms::script
== aName
) {
397 nsHtml5TreeOperation
* treeOp
=
398 mOpQueue
.AppendElement(mozilla::fallible
);
399 if (MOZ_UNLIKELY(!treeOp
)) {
400 MarkAsBrokenAndRequestSuspensionWithoutBuilder(
401 NS_ERROR_OUT_OF_MEMORY
);
404 opSetScriptLineNumberAndFreeze
operation(content
,
405 tokenizer
->getLineNumber());
406 treeOp
->Init(mozilla::AsVariant(operation
));
409 aAttributes
->getValue(nsHtml5AttributeName::ATTR_HREF
);
411 url
= aAttributes
->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF
);
415 aAttributes
->getValue(nsHtml5AttributeName::ATTR_TYPE
);
416 nsHtml5String crossOrigin
=
417 aAttributes
->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN
);
418 nsHtml5String integrity
=
419 aAttributes
->getValue(nsHtml5AttributeName::ATTR_INTEGRITY
);
420 nsHtml5String referrerPolicy
= aAttributes
->getValue(
421 nsHtml5AttributeName::ATTR_REFERRERPOLICY
);
422 mSpeculativeLoadQueue
.AppendElement()->InitScript(
423 url
, nullptr, type
, crossOrigin
, /* aMedia = */ nullptr,
424 integrity
, referrerPolicy
, mode
== nsHtml5TreeBuilder::IN_HEAD
,
425 false, false, false, false);
427 } else if (nsGkAtoms::style
== aName
) {
428 mImportScanner
.Start();
429 nsHtml5TreeOperation
* treeOp
=
430 mOpQueue
.AppendElement(mozilla::fallible
);
431 if (MOZ_UNLIKELY(!treeOp
)) {
432 MarkAsBrokenAndRequestSuspensionWithoutBuilder(
433 NS_ERROR_OUT_OF_MEMORY
);
436 opSetStyleLineNumber
operation(content
, tokenizer
->getLineNumber());
437 treeOp
->Init(mozilla::AsVariant(operation
));
441 } else if (aNamespace
!= kNameSpaceID_MathML
) {
442 // No speculative loader--just line numbers and defer/async check
443 if (nsGkAtoms::style
== aName
) {
444 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
445 if (MOZ_UNLIKELY(!treeOp
)) {
446 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
449 opSetStyleLineNumber
operation(content
, tokenizer
->getLineNumber());
450 treeOp
->Init(mozilla::AsVariant(operation
));
451 } else if (nsGkAtoms::script
== aName
) {
452 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
453 if (MOZ_UNLIKELY(!treeOp
)) {
454 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
457 opSetScriptLineNumberAndFreeze
operation(content
,
458 tokenizer
->getLineNumber());
459 treeOp
->Init(mozilla::AsVariant(operation
));
460 if (aNamespace
== kNameSpaceID_XHTML
) {
461 mCurrentHtmlScriptIsAsyncOrDefer
=
462 aAttributes
->contains(nsHtml5AttributeName::ATTR_SRC
) &&
463 (aAttributes
->contains(nsHtml5AttributeName::ATTR_ASYNC
) ||
464 aAttributes
->contains(nsHtml5AttributeName::ATTR_DEFER
));
466 } else if (aNamespace
== kNameSpaceID_XHTML
) {
467 if (nsGkAtoms::html
== aName
) {
469 aAttributes
->getValue(nsHtml5AttributeName::ATTR_MANIFEST
);
470 nsHtml5TreeOperation
* treeOp
=
471 mOpQueue
.AppendElement(mozilla::fallible
);
472 if (MOZ_UNLIKELY(!treeOp
)) {
473 MarkAsBrokenAndRequestSuspensionWithoutBuilder(
474 NS_ERROR_OUT_OF_MEMORY
);
479 urlString
; // Not Auto, because using it to hold nsStringBuffer*
480 url
.ToString(urlString
);
481 opProcessOfflineManifest
operation(ToNewUnicode(urlString
));
482 treeOp
->Init(mozilla::AsVariant(operation
));
484 opProcessOfflineManifest
operation(ToNewUnicode(u
""_ns
));
485 treeOp
->Init(mozilla::AsVariant(operation
));
487 } else if (nsGkAtoms::base
== aName
&& mViewSource
) {
489 aAttributes
->getValue(nsHtml5AttributeName::ATTR_HREF
);
491 mViewSource
->AddBase(url
);
497 // End wall of code for speculative loading
502 nsIContentHandle
* nsHtml5TreeBuilder::createElement(
503 int32_t aNamespace
, nsAtom
* aName
, nsHtml5HtmlAttributes
* aAttributes
,
504 nsIContentHandle
* aFormElement
, nsIContentHandle
* aIntendedParent
,
505 nsHtml5ContentCreatorFunction aCreator
) {
506 nsIContentHandle
* content
=
507 createElement(aNamespace
, aName
, aAttributes
, aIntendedParent
, aCreator
);
510 nsHtml5TreeOperation::SetFormElement(
511 static_cast<nsIContent
*>(content
),
512 static_cast<nsIContent
*>(aFormElement
));
514 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
515 if (MOZ_UNLIKELY(!treeOp
)) {
516 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
519 opSetFormElement
operation(content
, aFormElement
);
520 treeOp
->Init(mozilla::AsVariant(operation
));
526 nsIContentHandle
* nsHtml5TreeBuilder::createHtmlElementSetAsRoot(
527 nsHtml5HtmlAttributes
* aAttributes
) {
528 nsHtml5ContentCreatorFunction creator
;
529 // <html> uses NS_NewHTMLSharedElement creator
530 creator
.html
= NS_NewHTMLSharedElement
;
531 nsIContentHandle
* content
= createElement(kNameSpaceID_XHTML
, nsGkAtoms::html
,
532 aAttributes
, nullptr, creator
);
534 nsresult rv
= nsHtml5TreeOperation::AppendToDocument(
535 static_cast<nsIContent
*>(content
), mBuilder
);
537 MarkAsBrokenAndRequestSuspensionWithBuilder(rv
);
540 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
541 if (MOZ_UNLIKELY(!treeOp
)) {
542 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
545 opAppendToDocument
operation(content
);
546 treeOp
->Init(mozilla::AsVariant(operation
));
551 nsIContentHandle
* nsHtml5TreeBuilder::createAndInsertFosterParentedElement(
552 int32_t aNamespace
, nsAtom
* aName
, nsHtml5HtmlAttributes
* aAttributes
,
553 nsIContentHandle
* aFormElement
, nsIContentHandle
* aTable
,
554 nsIContentHandle
* aStackParent
, nsHtml5ContentCreatorFunction aCreator
) {
555 MOZ_ASSERT(aTable
, "Null table");
556 MOZ_ASSERT(aStackParent
, "Null stack parent");
559 // Get the foster parent to use as the intended parent when creating
560 // the child element.
561 nsIContent
* fosterParent
= nsHtml5TreeOperation::GetFosterParent(
562 static_cast<nsIContent
*>(aTable
),
563 static_cast<nsIContent
*>(aStackParent
));
565 nsIContentHandle
* child
= createElement(
566 aNamespace
, aName
, aAttributes
, aFormElement
, fosterParent
, aCreator
);
568 insertFosterParentedChild(child
, aTable
, aStackParent
);
573 // Tree op to get the foster parent that we use as the intended parent
574 // when creating the child element.
575 nsHtml5TreeOperation
* fosterParentTreeOp
= mOpQueue
.AppendElement();
576 NS_ASSERTION(fosterParentTreeOp
, "Tree op allocation failed.");
577 nsIContentHandle
* fosterParentHandle
= AllocateContentHandle();
578 opGetFosterParent
operation(aTable
, aStackParent
, fosterParentHandle
);
579 fosterParentTreeOp
->Init(mozilla::AsVariant(operation
));
581 // Create the element with the correct intended parent.
582 nsIContentHandle
* child
=
583 createElement(aNamespace
, aName
, aAttributes
, aFormElement
,
584 fosterParentHandle
, aCreator
);
586 // Insert the child into the foster parent.
587 insertFosterParentedChild(child
, aTable
, aStackParent
);
592 void nsHtml5TreeBuilder::detachFromParent(nsIContentHandle
* aElement
) {
593 MOZ_ASSERT(aElement
, "Null element");
596 nsHtml5TreeOperation::Detach(static_cast<nsIContent
*>(aElement
), mBuilder
);
600 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
601 if (MOZ_UNLIKELY(!treeOp
)) {
602 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
605 opDetach
operation(aElement
);
606 treeOp
->Init(mozilla::AsVariant(operation
));
609 void nsHtml5TreeBuilder::appendElement(nsIContentHandle
* aChild
,
610 nsIContentHandle
* aParent
) {
611 MOZ_ASSERT(aChild
, "Null child");
612 MOZ_ASSERT(aParent
, "Null parent");
615 nsresult rv
= nsHtml5TreeOperation::Append(
616 static_cast<nsIContent
*>(aChild
), static_cast<nsIContent
*>(aParent
),
617 mozilla::dom::FROM_PARSER_FRAGMENT
, mBuilder
);
619 MarkAsBrokenAndRequestSuspensionWithBuilder(rv
);
624 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
625 if (MOZ_UNLIKELY(!treeOp
)) {
626 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
630 opAppend
operation(aChild
, aParent
,
631 (!!mSpeculativeLoadStage
)
632 ? mozilla::dom::FROM_PARSER_NETWORK
633 : mozilla::dom::FROM_PARSER_DOCUMENT_WRITE
);
634 treeOp
->Init(mozilla::AsVariant(operation
));
637 void nsHtml5TreeBuilder::appendChildrenToNewParent(
638 nsIContentHandle
* aOldParent
, nsIContentHandle
* aNewParent
) {
639 MOZ_ASSERT(aOldParent
, "Null old parent");
640 MOZ_ASSERT(aNewParent
, "Null new parent");
643 nsresult rv
= nsHtml5TreeOperation::AppendChildrenToNewParent(
644 static_cast<nsIContent
*>(aOldParent
),
645 static_cast<nsIContent
*>(aNewParent
), mBuilder
);
647 MarkAsBrokenAndRequestSuspensionWithBuilder(rv
);
652 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
653 if (MOZ_UNLIKELY(!treeOp
)) {
654 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
657 opAppendChildrenToNewParent
operation(aOldParent
, aNewParent
);
658 treeOp
->Init(mozilla::AsVariant(operation
));
661 void nsHtml5TreeBuilder::insertFosterParentedCharacters(
662 char16_t
* aBuffer
, int32_t aStart
, int32_t aLength
,
663 nsIContentHandle
* aTable
, nsIContentHandle
* aStackParent
) {
664 MOZ_ASSERT(aBuffer
, "Null buffer");
665 MOZ_ASSERT(aTable
, "Null table");
666 MOZ_ASSERT(aStackParent
, "Null stack parent");
667 MOZ_ASSERT(!aStart
, "aStart must always be zero.");
670 nsresult rv
= nsHtml5TreeOperation::FosterParentText(
671 static_cast<nsIContent
*>(aStackParent
),
672 aBuffer
, // XXX aStart always ignored???
673 aLength
, static_cast<nsIContent
*>(aTable
), mBuilder
);
675 MarkAsBrokenAndRequestSuspensionWithBuilder(rv
);
680 auto bufferCopy
= mozilla::MakeUniqueFallible
<char16_t
[]>(aLength
);
682 // Just assigning mBroken instead of generating tree op. The caller
683 // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
684 mBroken
= NS_ERROR_OUT_OF_MEMORY
;
689 memcpy(bufferCopy
.get(), aBuffer
, aLength
* sizeof(char16_t
));
691 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
692 if (MOZ_UNLIKELY(!treeOp
)) {
693 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
696 opFosterParentText
operation(aStackParent
, bufferCopy
.release(), aTable
,
698 treeOp
->Init(mozilla::AsVariant(operation
));
701 void nsHtml5TreeBuilder::insertFosterParentedChild(
702 nsIContentHandle
* aChild
, nsIContentHandle
* aTable
,
703 nsIContentHandle
* aStackParent
) {
704 MOZ_ASSERT(aChild
, "Null child");
705 MOZ_ASSERT(aTable
, "Null table");
706 MOZ_ASSERT(aStackParent
, "Null stack parent");
709 nsresult rv
= nsHtml5TreeOperation::FosterParent(
710 static_cast<nsIContent
*>(aChild
),
711 static_cast<nsIContent
*>(aStackParent
),
712 static_cast<nsIContent
*>(aTable
), mBuilder
);
714 MarkAsBrokenAndRequestSuspensionWithBuilder(rv
);
719 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
720 if (MOZ_UNLIKELY(!treeOp
)) {
721 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
724 opFosterParent
operation(aChild
, aStackParent
, aTable
);
725 treeOp
->Init(mozilla::AsVariant(operation
));
728 void nsHtml5TreeBuilder::appendCharacters(nsIContentHandle
* aParent
,
729 char16_t
* aBuffer
, int32_t aStart
,
731 MOZ_ASSERT(aBuffer
, "Null buffer");
732 MOZ_ASSERT(aParent
, "Null parent");
733 MOZ_ASSERT(!aStart
, "aStart must always be zero.");
736 nsresult rv
= nsHtml5TreeOperation::AppendText(
737 aBuffer
, // XXX aStart always ignored???
738 aLength
, static_cast<nsIContent
*>(aParent
), mBuilder
);
740 MarkAsBrokenAndRequestSuspensionWithBuilder(rv
);
745 auto bufferCopy
= mozilla::MakeUniqueFallible
<char16_t
[]>(aLength
);
747 // Just assigning mBroken instead of generating tree op. The caller
748 // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
749 mBroken
= NS_ERROR_OUT_OF_MEMORY
;
754 memcpy(bufferCopy
.get(), aBuffer
, aLength
* sizeof(char16_t
));
756 if (mImportScanner
.ShouldScan()) {
757 nsTArray
<nsString
> imports
= mImportScanner
.Scan(Span(aBuffer
, aLength
));
758 for (nsString
& url
: imports
) {
759 mSpeculativeLoadQueue
.AppendElement()->InitImportStyle(std::move(url
));
763 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
764 if (MOZ_UNLIKELY(!treeOp
)) {
765 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
768 opAppendText
operation(aParent
, bufferCopy
.release(), aLength
);
769 treeOp
->Init(mozilla::AsVariant(operation
));
772 void nsHtml5TreeBuilder::appendComment(nsIContentHandle
* aParent
,
773 char16_t
* aBuffer
, int32_t aStart
,
775 MOZ_ASSERT(aBuffer
, "Null buffer");
776 MOZ_ASSERT(aParent
, "Null parent");
777 MOZ_ASSERT(!aStart
, "aStart must always be zero.");
780 nsresult rv
= nsHtml5TreeOperation::AppendComment(
781 static_cast<nsIContent
*>(aParent
),
782 aBuffer
, // XXX aStart always ignored???
785 MarkAsBrokenAndRequestSuspensionWithBuilder(rv
);
790 auto bufferCopy
= mozilla::MakeUniqueFallible
<char16_t
[]>(aLength
);
792 // Just assigning mBroken instead of generating tree op. The caller
793 // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
794 mBroken
= NS_ERROR_OUT_OF_MEMORY
;
799 memcpy(bufferCopy
.get(), aBuffer
, aLength
* sizeof(char16_t
));
801 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
802 if (MOZ_UNLIKELY(!treeOp
)) {
803 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
806 opAppendComment
operation(aParent
, bufferCopy
.release(), aLength
);
807 treeOp
->Init(mozilla::AsVariant(operation
));
810 void nsHtml5TreeBuilder::appendCommentToDocument(char16_t
* aBuffer
,
813 MOZ_ASSERT(aBuffer
, "Null buffer");
814 MOZ_ASSERT(!aStart
, "aStart must always be zero.");
817 nsresult rv
= nsHtml5TreeOperation::AppendCommentToDocument(
818 aBuffer
, // XXX aStart always ignored???
821 MarkAsBrokenAndRequestSuspensionWithBuilder(rv
);
826 auto bufferCopy
= mozilla::MakeUniqueFallible
<char16_t
[]>(aLength
);
828 // Just assigning mBroken instead of generating tree op. The caller
829 // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
830 mBroken
= NS_ERROR_OUT_OF_MEMORY
;
835 memcpy(bufferCopy
.get(), aBuffer
, aLength
* sizeof(char16_t
));
837 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
838 if (MOZ_UNLIKELY(!treeOp
)) {
839 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
842 opAppendCommentToDocument
data(bufferCopy
.release(), aLength
);
843 treeOp
->Init(mozilla::AsVariant(data
));
846 void nsHtml5TreeBuilder::addAttributesToElement(
847 nsIContentHandle
* aElement
, nsHtml5HtmlAttributes
* aAttributes
) {
848 MOZ_ASSERT(aElement
, "Null element");
849 MOZ_ASSERT(aAttributes
, "Null attributes");
851 if (aAttributes
== nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES
) {
857 aAttributes
== tokenizer
->GetAttributes(),
858 "Using attribute other than the tokenizer's to add to body or html.");
859 nsresult rv
= nsHtml5TreeOperation::AddAttributes(
860 static_cast<nsIContent
*>(aElement
), aAttributes
, mBuilder
);
862 MarkAsBrokenAndRequestSuspensionWithBuilder(rv
);
867 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
868 if (MOZ_UNLIKELY(!treeOp
)) {
869 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
872 opAddAttributes
opeation(aElement
, aAttributes
);
873 treeOp
->Init(mozilla::AsVariant(opeation
));
876 void nsHtml5TreeBuilder::markMalformedIfScript(nsIContentHandle
* aElement
) {
877 MOZ_ASSERT(aElement
, "Null element");
880 nsHtml5TreeOperation::MarkMalformedIfScript(
881 static_cast<nsIContent
*>(aElement
));
885 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
886 if (MOZ_UNLIKELY(!treeOp
)) {
887 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
890 opMarkMalformedIfScript
operation(aElement
);
891 treeOp
->Init(mozilla::AsVariant(operation
));
894 void nsHtml5TreeBuilder::start(bool fragment
) {
895 mCurrentHtmlScriptIsAsyncOrDefer
= false;
901 void nsHtml5TreeBuilder::end() {
908 void nsHtml5TreeBuilder::appendDoctypeToDocument(nsAtom
* aName
,
909 nsHtml5String aPublicId
,
910 nsHtml5String aSystemId
) {
911 MOZ_ASSERT(aName
, "Null name");
912 nsString publicId
; // Not Auto, because using it to hold nsStringBuffer*
913 nsString systemId
; // Not Auto, because using it to hold nsStringBuffer*
914 aPublicId
.ToString(publicId
);
915 aSystemId
.ToString(systemId
);
917 nsresult rv
= nsHtml5TreeOperation::AppendDoctypeToDocument(
918 aName
, publicId
, systemId
, mBuilder
);
920 MarkAsBrokenAndRequestSuspensionWithBuilder(rv
);
925 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
926 if (MOZ_UNLIKELY(!treeOp
)) {
927 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
930 opAppendDoctypeToDocument
operation(aName
, publicId
, systemId
);
931 treeOp
->Init(mozilla::AsVariant(operation
));
932 // nsXMLContentSink can flush here, but what's the point?
933 // It can also interrupt here, but we can't.
936 void nsHtml5TreeBuilder::elementPushed(int32_t aNamespace
, nsAtom
* aName
,
937 nsIContentHandle
* aElement
) {
938 NS_ASSERTION(aNamespace
== kNameSpaceID_XHTML
||
939 aNamespace
== kNameSpaceID_SVG
||
940 aNamespace
== kNameSpaceID_MathML
,
941 "Element isn't HTML, SVG or MathML!");
942 NS_ASSERTION(aName
, "Element doesn't have local name!");
943 NS_ASSERTION(aElement
, "No element!");
945 * The frame constructor uses recursive algorithms, so it can't deal with
946 * arbitrarily deep trees. This is especially a problem on Windows where
947 * the permitted depth of the runtime stack is rather small.
949 * The following is a protection against author incompetence--not against
950 * malice. There are other ways to make the DOM deep anyway.
952 * The basic idea is that when the tree builder stack gets too deep,
953 * append operations no longer append to the node that the HTML parsing
954 * algorithm says they should but instead text nodes are append to the last
955 * element that was seen before a magic tree builder stack threshold was
956 * reached and element and comment nodes aren't appended to the DOM at all.
958 * However, for security reasons, non-child descendant text nodes inside an
959 * SVG script or style element should not become children. Also, non-cell
960 * table elements shouldn't be used as surrogate parents for user experience
963 if (aNamespace
!= kNameSpaceID_XHTML
) {
966 if (aName
== nsGkAtoms::body
|| aName
== nsGkAtoms::frameset
) {
968 // InnerHTML and DOMParser shouldn't start layout anyway
971 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
972 if (MOZ_UNLIKELY(!treeOp
)) {
973 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
976 treeOp
->Init(mozilla::AsVariant(opStartLayout()));
979 if (nsIContent::RequiresDoneCreatingElement(kNameSpaceID_XHTML
, aName
)) {
981 nsHtml5TreeOperation::DoneCreatingElement(
982 static_cast<nsIContent
*>(aElement
));
984 opDoneCreatingElement
operation(aElement
);
985 mOpQueue
.AppendElement()->Init(mozilla::AsVariant(operation
));
989 if (mSpeculativeLoadStage
&& aName
== nsGkAtoms::picture
) {
990 // mSpeculativeLoadStage is non-null only in the off-the-main-thread
991 // tree builder, which handles the network stream
993 // See comments in nsHtml5SpeculativeLoad.h about <picture> preloading
994 mSpeculativeLoadQueue
.AppendElement()->InitOpenPicture();
998 void nsHtml5TreeBuilder::elementPopped(int32_t aNamespace
, nsAtom
* aName
,
999 nsIContentHandle
* aElement
) {
1000 NS_ASSERTION(aNamespace
== kNameSpaceID_XHTML
||
1001 aNamespace
== kNameSpaceID_SVG
||
1002 aNamespace
== kNameSpaceID_MathML
,
1003 "Element isn't HTML, SVG or MathML!");
1004 NS_ASSERTION(aName
, "Element doesn't have local name!");
1005 NS_ASSERTION(aElement
, "No element!");
1006 if (aNamespace
== kNameSpaceID_MathML
) {
1009 // we now have only SVG and HTML
1010 if (aName
== nsGkAtoms::script
) {
1011 if (mPreventScriptExecution
) {
1013 nsHtml5TreeOperation::PreventScriptExecution(
1014 static_cast<nsIContent
*>(aElement
));
1017 opPreventScriptExecution
operation(aElement
);
1018 mOpQueue
.AppendElement()->Init(mozilla::AsVariant(operation
));
1024 if (mCurrentHtmlScriptIsAsyncOrDefer
) {
1025 NS_ASSERTION(aNamespace
== kNameSpaceID_XHTML
,
1026 "Only HTML scripts may be async/defer.");
1027 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1028 if (MOZ_UNLIKELY(!treeOp
)) {
1029 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1032 opRunScriptAsyncDefer
operation(aElement
);
1033 treeOp
->Init(mozilla::AsVariant(operation
));
1034 mCurrentHtmlScriptIsAsyncOrDefer
= false;
1037 requestSuspension();
1038 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1039 if (MOZ_UNLIKELY(!treeOp
)) {
1040 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1043 opRunScript
operation(aElement
, nullptr);
1044 treeOp
->Init(mozilla::AsVariant(operation
));
1047 // Some nodes need DoneAddingChildren() called to initialize
1048 // properly (e.g. form state restoration).
1049 if (nsIContent::RequiresDoneAddingChildren(aNamespace
, aName
)) {
1051 nsHtml5TreeOperation::DoneAddingChildren(
1052 static_cast<nsIContent
*>(aElement
));
1055 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1056 if (MOZ_UNLIKELY(!treeOp
)) {
1057 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1060 opDoneAddingChildren
operation(aElement
);
1061 treeOp
->Init(mozilla::AsVariant(operation
));
1064 if (aName
== nsGkAtoms::style
||
1065 (aNamespace
== kNameSpaceID_XHTML
&& aName
== nsGkAtoms::link
)) {
1067 MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(),
1068 "Scripts must be blocked.");
1069 mBuilder
->UpdateStyleSheet(static_cast<nsIContent
*>(aElement
));
1073 if (aName
== nsGkAtoms::style
) {
1074 nsTArray
<nsString
> imports
= mImportScanner
.Stop();
1075 for (nsString
& url
: imports
) {
1076 mSpeculativeLoadQueue
.AppendElement()->InitImportStyle(std::move(url
));
1080 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1081 if (MOZ_UNLIKELY(!treeOp
)) {
1082 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1085 opUpdateStyleSheet
operation(aElement
);
1086 treeOp
->Init(mozilla::AsVariant(operation
));
1089 if (aNamespace
== kNameSpaceID_SVG
) {
1090 if (aName
== nsGkAtoms::svg
) {
1091 if (!scriptingEnabled
|| mPreventScriptExecution
) {
1095 nsHtml5TreeOperation::SvgLoad(static_cast<nsIContent
*>(aElement
));
1098 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1099 if (MOZ_UNLIKELY(!treeOp
)) {
1100 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1103 opSvgLoad
operation(aElement
);
1104 treeOp
->Init(mozilla::AsVariant(operation
));
1109 if (mSpeculativeLoadStage
&& aName
== nsGkAtoms::picture
) {
1110 // mSpeculativeLoadStage is non-null only in the off-the-main-thread
1111 // tree builder, which handles the network stream
1113 // See comments in nsHtml5SpeculativeLoad.h about <picture> preloading
1114 mSpeculativeLoadQueue
.AppendElement()->InitEndPicture();
1118 void nsHtml5TreeBuilder::accumulateCharacters(const char16_t
* aBuf
,
1119 int32_t aStart
, int32_t aLength
) {
1120 MOZ_RELEASE_ASSERT(charBufferLen
+ aLength
<= charBuffer
.length
,
1121 "About to memcpy past the end of the buffer!");
1122 memcpy(charBuffer
+ charBufferLen
, aBuf
+ aStart
, sizeof(char16_t
) * aLength
);
1123 charBufferLen
+= aLength
;
1126 // INT32_MAX is (2^31)-1. Therefore, the highest power-of-two that fits
1127 // is 2^30. Note that this is counting char16_t units. The underlying
1128 // bytes will be twice that, but they fit even in 32-bit size_t even
1129 // if a contiguous chunk of memory of that size is pretty unlikely to
1130 // be available on a 32-bit system.
1131 #define MAX_POWER_OF_TWO_IN_INT32 0x40000000
1133 bool nsHtml5TreeBuilder::EnsureBufferSpace(int32_t aLength
) {
1134 // TODO: Unify nsHtml5Tokenizer::strBuf and nsHtml5TreeBuilder::charBuffer
1135 // so that this method becomes unnecessary.
1136 mozilla::CheckedInt
<int32_t> worstCase(charBufferLen
);
1137 worstCase
+= aLength
;
1138 if (!worstCase
.isValid()) {
1141 if (worstCase
.value() > MAX_POWER_OF_TWO_IN_INT32
) {
1145 if (worstCase
.value() < MAX_POWER_OF_TWO_IN_INT32
) {
1146 // Add one to round to the next power of two to avoid immediate
1147 // reallocation once there are a few characters in the buffer.
1150 charBuffer
= jArray
<char16_t
, int32_t>::newFallibleJArray(
1151 mozilla::RoundUpPow2(worstCase
.value()));
1155 } else if (worstCase
.value() > charBuffer
.length
) {
1156 jArray
<char16_t
, int32_t> newBuf
=
1157 jArray
<char16_t
, int32_t>::newFallibleJArray(
1158 mozilla::RoundUpPow2(worstCase
.value()));
1162 memcpy(newBuf
, charBuffer
, sizeof(char16_t
) * size_t(charBufferLen
));
1163 charBuffer
= newBuf
;
1168 nsIContentHandle
* nsHtml5TreeBuilder::AllocateContentHandle() {
1169 if (MOZ_UNLIKELY(mBuilder
)) {
1170 MOZ_ASSERT_UNREACHABLE("Must never allocate a handle with builder.");
1173 if (mHandlesUsed
== NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH
) {
1174 mOldHandles
.AppendElement(std::move(mHandles
));
1175 mHandles
= mozilla::MakeUnique
<nsIContent
*[]>(
1176 NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH
);
1180 mHandles
[mHandlesUsed
] = reinterpret_cast<nsIContent
*>(uintptr_t(0xC0DEDBAD));
1182 return &mHandles
[mHandlesUsed
++];
1185 bool nsHtml5TreeBuilder::HasScript() {
1186 uint32_t len
= mOpQueue
.Length();
1190 return mOpQueue
.ElementAt(len
- 1).IsRunScript();
1193 bool nsHtml5TreeBuilder::Flush(bool aDiscretionary
) {
1194 if (MOZ_UNLIKELY(mBuilder
)) {
1195 MOZ_ASSERT_UNREACHABLE("Must never flush with builder.");
1198 if (NS_SUCCEEDED(mBroken
)) {
1199 if (!aDiscretionary
|| !(charBufferLen
&& currentPtr
>= 0 &&
1200 stack
[currentPtr
]->isFosterParenting())) {
1201 // Don't flush text on discretionary flushes if the current element on
1202 // the stack is a foster-parenting element and there's pending text,
1203 // because flushing in that case would make the tree shape dependent on
1204 // where the flush points fall.
1210 bool hasOps
= !mOpQueue
.IsEmpty();
1212 // If the builder is broken and mOpQueue is not empty, there must be
1213 // one op and it must be eTreeOpMarkAsBroken.
1214 if (NS_FAILED(mBroken
)) {
1215 MOZ_ASSERT(mOpQueue
.Length() == 1,
1216 "Tree builder is broken with a non-empty op queue whose "
1218 MOZ_ASSERT(mOpQueue
[0].IsMarkAsBroken(),
1219 "Tree builder is broken but the op in queue is not marked "
1222 mOpSink
->MoveOpsFrom(mOpQueue
);
1226 // no op sink: throw away ops
1231 void nsHtml5TreeBuilder::FlushLoads() {
1232 if (MOZ_UNLIKELY(mBuilder
)) {
1233 MOZ_ASSERT_UNREACHABLE("Must never flush loads with builder.");
1236 if (!mSpeculativeLoadQueue
.IsEmpty()) {
1237 mSpeculativeLoadStage
->MoveSpeculativeLoadsFrom(mSpeculativeLoadQueue
);
1241 void nsHtml5TreeBuilder::SetDocumentCharset(NotNull
<const Encoding
*> aEncoding
,
1242 int32_t aCharsetSource
) {
1244 mBuilder
->SetDocumentCharsetAndSource(aEncoding
, aCharsetSource
);
1245 } else if (mSpeculativeLoadStage
) {
1246 mSpeculativeLoadQueue
.AppendElement()->InitSetDocumentCharset(
1247 aEncoding
, aCharsetSource
);
1249 opSetDocumentCharset
opearation(aEncoding
, aCharsetSource
);
1250 mOpQueue
.AppendElement()->Init(mozilla::AsVariant(opearation
));
1254 void nsHtml5TreeBuilder::StreamEnded() {
1255 MOZ_ASSERT(!mBuilder
, "Must not call StreamEnded with builder.");
1256 MOZ_ASSERT(!fragment
, "Must not parse fragments off the main thread.");
1257 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1258 if (MOZ_UNLIKELY(!treeOp
)) {
1259 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1262 treeOp
->Init(mozilla::AsVariant(opStreamEnded()));
1265 void nsHtml5TreeBuilder::NeedsCharsetSwitchTo(
1266 NotNull
<const Encoding
*> aEncoding
, int32_t aCharsetSource
,
1267 int32_t aLineNumber
) {
1268 if (MOZ_UNLIKELY(mBuilder
)) {
1269 MOZ_ASSERT_UNREACHABLE("Must never switch charset with builder.");
1272 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1273 if (MOZ_UNLIKELY(!treeOp
)) {
1274 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1277 opCharsetSwitchTo
opeation(aEncoding
, aCharsetSource
, aLineNumber
);
1278 treeOp
->Init(mozilla::AsVariant(opeation
));
1281 void nsHtml5TreeBuilder::MaybeComplainAboutCharset(const char* aMsgId
,
1283 int32_t aLineNumber
) {
1284 if (MOZ_UNLIKELY(mBuilder
)) {
1285 MOZ_ASSERT_UNREACHABLE("Must never complain about charset with builder.");
1288 opMaybeComplainAboutCharset
opeartion(const_cast<char*>(aMsgId
), aError
,
1290 mOpQueue
.AppendElement()->Init(mozilla::AsVariant(opeartion
));
1293 void nsHtml5TreeBuilder::TryToEnableEncodingMenu() {
1294 if (MOZ_UNLIKELY(mBuilder
)) {
1295 MOZ_ASSERT_UNREACHABLE("Must never disable encoding menu with builder.");
1298 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
1299 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
1300 treeOp
->Init(mozilla::AsVariant(opEnableEncodingMenu()));
1303 void nsHtml5TreeBuilder::AddSnapshotToScript(
1304 nsAHtml5TreeBuilderState
* aSnapshot
, int32_t aLine
) {
1305 if (MOZ_UNLIKELY(mBuilder
)) {
1306 MOZ_ASSERT_UNREACHABLE("Must never use snapshots with builder.");
1309 MOZ_ASSERT(HasScript(), "No script to add a snapshot to!");
1310 MOZ_ASSERT(aSnapshot
, "Got null snapshot.");
1311 mOpQueue
.ElementAt(mOpQueue
.Length() - 1).SetSnapshot(aSnapshot
, aLine
);
1314 void nsHtml5TreeBuilder::DropHandles() {
1315 MOZ_ASSERT(!mBuilder
, "Must not drop handles with builder.");
1316 mOldHandles
.Clear();
1320 void nsHtml5TreeBuilder::MarkAsBroken(nsresult aRv
) {
1321 if (MOZ_UNLIKELY(mBuilder
)) {
1322 MOZ_ASSERT_UNREACHABLE("Must not call this with builder.");
1326 mOpQueue
.Clear(); // Previous ops don't matter anymore
1327 opMarkAsBroken
operation(aRv
);
1328 mOpQueue
.AppendElement()->Init(mozilla::AsVariant(operation
));
1331 void nsHtml5TreeBuilder::MarkAsBrokenFromPortability(nsresult aRv
) {
1333 MarkAsBrokenAndRequestSuspensionWithBuilder(aRv
);
1337 requestSuspension();
1340 void nsHtml5TreeBuilder::StartPlainTextViewSource(const nsAutoString
& aTitle
) {
1341 MOZ_ASSERT(!mBuilder
, "Must not view source with builder.");
1343 startTag(nsHtml5ElementName::ELT_META
,
1344 nsHtml5ViewSourceUtils::NewMetaViewportAttributes(), false);
1346 startTag(nsHtml5ElementName::ELT_TITLE
,
1347 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES
, false);
1349 // XUL will add the "Source of: " prefix.
1350 uint32_t length
= aTitle
.Length();
1351 if (length
> INT32_MAX
) {
1354 characters(aTitle
.get(), 0, (int32_t)length
);
1355 endTag(nsHtml5ElementName::ELT_TITLE
);
1357 startTag(nsHtml5ElementName::ELT_LINK
,
1358 nsHtml5ViewSourceUtils::NewLinkAttributes(), false);
1360 startTag(nsHtml5ElementName::ELT_BODY
,
1361 nsHtml5ViewSourceUtils::NewBodyAttributes(), false);
1363 StartPlainTextBody();
1366 void nsHtml5TreeBuilder::StartPlainText() {
1367 MOZ_ASSERT(!mBuilder
, "Must not view source with builder.");
1368 startTag(nsHtml5ElementName::ELT_LINK
,
1369 nsHtml5PlainTextUtils::NewLinkAttributes(), false);
1371 startTag(nsHtml5ElementName::ELT_BODY
,
1372 nsHtml5PlainTextUtils::NewBodyAttributes(), false);
1374 StartPlainTextBody();
1377 void nsHtml5TreeBuilder::StartPlainTextBody() {
1378 MOZ_ASSERT(!mBuilder
, "Must not view source with builder.");
1379 startTag(nsHtml5ElementName::ELT_PRE
, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES
,
1381 needToDropLF
= false;
1384 // DocumentModeHandler
1385 void nsHtml5TreeBuilder::documentMode(nsHtml5DocumentMode m
) {
1387 mBuilder
->SetDocumentMode(m
);
1390 if (mSpeculativeLoadStage
) {
1391 mSpeculativeLoadQueue
.AppendElement()->InitSetDocumentMode(m
);
1394 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1395 if (MOZ_UNLIKELY(!treeOp
)) {
1396 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1399 treeOp
->Init(mozilla::AsVariant(m
));
1402 nsIContentHandle
* nsHtml5TreeBuilder::getDocumentFragmentForTemplate(
1403 nsIContentHandle
* aTemplate
) {
1405 return nsHtml5TreeOperation::GetDocumentFragmentForTemplate(
1406 static_cast<nsIContent
*>(aTemplate
));
1408 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1409 if (MOZ_UNLIKELY(!treeOp
)) {
1410 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1413 nsIContentHandle
* fragHandle
= AllocateContentHandle();
1414 opGetDocumentFragmentForTemplate
operation(aTemplate
, fragHandle
);
1415 treeOp
->Init(mozilla::AsVariant(operation
));
1419 nsIContentHandle
* nsHtml5TreeBuilder::getFormPointerForContext(
1420 nsIContentHandle
* aContext
) {
1421 MOZ_ASSERT(mBuilder
, "Must have builder.");
1426 MOZ_ASSERT(NS_IsMainThread());
1428 // aContext must always be an element that already exists
1430 nsIContent
* contextNode
= static_cast<nsIContent
*>(aContext
);
1431 nsIContent
* currentAncestor
= contextNode
;
1433 // We traverse the ancestors of the context node to find the nearest
1434 // form pointer. This traversal is why aContext must not be an emtpy handle.
1435 nsIContent
* nearestForm
= nullptr;
1436 while (currentAncestor
) {
1437 if (currentAncestor
->IsHTMLElement(nsGkAtoms::form
)) {
1438 nearestForm
= currentAncestor
;
1441 currentAncestor
= currentAncestor
->GetParent();
1453 void nsHtml5TreeBuilder::EnableViewSource(nsHtml5Highlighter
* aHighlighter
) {
1454 MOZ_ASSERT(!mBuilder
, "Must not view source with builder.");
1455 mViewSource
= aHighlighter
;
1458 void nsHtml5TreeBuilder::errDeepTree() {
1459 if (MOZ_UNLIKELY(mViewSource
)) {
1460 mViewSource
->AddErrorToCurrentRun("errDeepTree");
1461 } else if (!mBuilder
) {
1462 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
1463 MOZ_ASSERT(treeOp
, "Tree op allocation failed.");
1464 opMaybeComplainAboutDeepTree
operation(tokenizer
->getLineNumber());
1465 treeOp
->Init(mozilla::AsVariant(operation
));
1469 void nsHtml5TreeBuilder::errStrayStartTag(nsAtom
* aName
) {
1470 if (MOZ_UNLIKELY(mViewSource
)) {
1471 mViewSource
->AddErrorToCurrentRun("errStrayStartTag2", aName
);
1475 void nsHtml5TreeBuilder::errStrayEndTag(nsAtom
* aName
) {
1476 if (MOZ_UNLIKELY(mViewSource
)) {
1477 mViewSource
->AddErrorToCurrentRun("errStrayEndTag", aName
);
1481 void nsHtml5TreeBuilder::errUnclosedElements(int32_t aIndex
, nsAtom
* aName
) {
1482 if (MOZ_UNLIKELY(mViewSource
)) {
1483 mViewSource
->AddErrorToCurrentRun("errUnclosedElements", aName
);
1487 void nsHtml5TreeBuilder::errUnclosedElementsImplied(int32_t aIndex
,
1489 if (MOZ_UNLIKELY(mViewSource
)) {
1490 mViewSource
->AddErrorToCurrentRun("errUnclosedElementsImplied", aName
);
1494 void nsHtml5TreeBuilder::errUnclosedElementsCell(int32_t aIndex
) {
1495 if (MOZ_UNLIKELY(mViewSource
)) {
1496 mViewSource
->AddErrorToCurrentRun("errUnclosedElementsCell");
1500 void nsHtml5TreeBuilder::errStrayDoctype() {
1501 if (MOZ_UNLIKELY(mViewSource
)) {
1502 mViewSource
->AddErrorToCurrentRun("errStrayDoctype");
1506 void nsHtml5TreeBuilder::errAlmostStandardsDoctype() {
1507 if (MOZ_UNLIKELY(mViewSource
) && !isSrcdocDocument
) {
1508 mViewSource
->AddErrorToCurrentRun("errAlmostStandardsDoctype");
1512 void nsHtml5TreeBuilder::errQuirkyDoctype() {
1513 if (MOZ_UNLIKELY(mViewSource
) && !isSrcdocDocument
) {
1514 mViewSource
->AddErrorToCurrentRun("errQuirkyDoctype");
1518 void nsHtml5TreeBuilder::errNonSpaceInTrailer() {
1519 if (MOZ_UNLIKELY(mViewSource
)) {
1520 mViewSource
->AddErrorToCurrentRun("errNonSpaceInTrailer");
1524 void nsHtml5TreeBuilder::errNonSpaceAfterFrameset() {
1525 if (MOZ_UNLIKELY(mViewSource
)) {
1526 mViewSource
->AddErrorToCurrentRun("errNonSpaceAfterFrameset");
1530 void nsHtml5TreeBuilder::errNonSpaceInFrameset() {
1531 if (MOZ_UNLIKELY(mViewSource
)) {
1532 mViewSource
->AddErrorToCurrentRun("errNonSpaceInFrameset");
1536 void nsHtml5TreeBuilder::errNonSpaceAfterBody() {
1537 if (MOZ_UNLIKELY(mViewSource
)) {
1538 mViewSource
->AddErrorToCurrentRun("errNonSpaceAfterBody");
1542 void nsHtml5TreeBuilder::errNonSpaceInColgroupInFragment() {
1543 if (MOZ_UNLIKELY(mViewSource
)) {
1544 mViewSource
->AddErrorToCurrentRun("errNonSpaceInColgroupInFragment");
1548 void nsHtml5TreeBuilder::errNonSpaceInNoscriptInHead() {
1549 if (MOZ_UNLIKELY(mViewSource
)) {
1550 mViewSource
->AddErrorToCurrentRun("errNonSpaceInNoscriptInHead");
1554 void nsHtml5TreeBuilder::errFooBetweenHeadAndBody(nsAtom
* aName
) {
1555 if (MOZ_UNLIKELY(mViewSource
)) {
1556 mViewSource
->AddErrorToCurrentRun("errFooBetweenHeadAndBody", aName
);
1560 void nsHtml5TreeBuilder::errStartTagWithoutDoctype() {
1561 if (MOZ_UNLIKELY(mViewSource
) && !isSrcdocDocument
) {
1562 mViewSource
->AddErrorToCurrentRun("errStartTagWithoutDoctype");
1566 void nsHtml5TreeBuilder::errNoSelectInTableScope() {
1567 if (MOZ_UNLIKELY(mViewSource
)) {
1568 mViewSource
->AddErrorToCurrentRun("errNoSelectInTableScope");
1572 void nsHtml5TreeBuilder::errStartSelectWhereEndSelectExpected() {
1573 if (MOZ_UNLIKELY(mViewSource
)) {
1574 mViewSource
->AddErrorToCurrentRun("errStartSelectWhereEndSelectExpected");
1578 void nsHtml5TreeBuilder::errStartTagWithSelectOpen(nsAtom
* aName
) {
1579 if (MOZ_UNLIKELY(mViewSource
)) {
1580 mViewSource
->AddErrorToCurrentRun("errStartTagWithSelectOpen", aName
);
1584 void nsHtml5TreeBuilder::errBadStartTagInNoscriptInHead(nsAtom
* aName
) {
1585 if (MOZ_UNLIKELY(mViewSource
)) {
1586 mViewSource
->AddErrorToCurrentRun("errBadStartTagInNoscriptInHead", aName
);
1590 void nsHtml5TreeBuilder::errImage() {
1591 if (MOZ_UNLIKELY(mViewSource
)) {
1592 mViewSource
->AddErrorToCurrentRun("errImage");
1596 void nsHtml5TreeBuilder::errIsindex() {
1597 if (MOZ_UNLIKELY(mViewSource
)) {
1598 mViewSource
->AddErrorToCurrentRun("errIsindex");
1602 void nsHtml5TreeBuilder::errFooSeenWhenFooOpen(nsAtom
* aName
) {
1603 if (MOZ_UNLIKELY(mViewSource
)) {
1604 mViewSource
->AddErrorToCurrentRun("errFooSeenWhenFooOpen2", aName
);
1608 void nsHtml5TreeBuilder::errHeadingWhenHeadingOpen() {
1609 if (MOZ_UNLIKELY(mViewSource
)) {
1610 mViewSource
->AddErrorToCurrentRun("errHeadingWhenHeadingOpen");
1614 void nsHtml5TreeBuilder::errFramesetStart() {
1615 if (MOZ_UNLIKELY(mViewSource
)) {
1616 mViewSource
->AddErrorToCurrentRun("errFramesetStart");
1620 void nsHtml5TreeBuilder::errNoCellToClose() {
1621 if (MOZ_UNLIKELY(mViewSource
)) {
1622 mViewSource
->AddErrorToCurrentRun("errNoCellToClose");
1626 void nsHtml5TreeBuilder::errStartTagInTable(nsAtom
* aName
) {
1627 if (MOZ_UNLIKELY(mViewSource
)) {
1628 mViewSource
->AddErrorToCurrentRun("errStartTagInTable", aName
);
1632 void nsHtml5TreeBuilder::errFormWhenFormOpen() {
1633 if (MOZ_UNLIKELY(mViewSource
)) {
1634 mViewSource
->AddErrorToCurrentRun("errFormWhenFormOpen");
1638 void nsHtml5TreeBuilder::errTableSeenWhileTableOpen() {
1639 if (MOZ_UNLIKELY(mViewSource
)) {
1640 mViewSource
->AddErrorToCurrentRun("errTableSeenWhileTableOpen");
1644 void nsHtml5TreeBuilder::errStartTagInTableBody(nsAtom
* aName
) {
1645 if (MOZ_UNLIKELY(mViewSource
)) {
1646 mViewSource
->AddErrorToCurrentRun("errStartTagInTableBody", aName
);
1650 void nsHtml5TreeBuilder::errEndTagSeenWithoutDoctype() {
1651 if (MOZ_UNLIKELY(mViewSource
) && !isSrcdocDocument
) {
1652 mViewSource
->AddErrorToCurrentRun("errEndTagSeenWithoutDoctype");
1656 void nsHtml5TreeBuilder::errEndTagAfterBody() {
1657 if (MOZ_UNLIKELY(mViewSource
)) {
1658 mViewSource
->AddErrorToCurrentRun("errEndTagAfterBody");
1662 void nsHtml5TreeBuilder::errEndTagSeenWithSelectOpen(nsAtom
* aName
) {
1663 if (MOZ_UNLIKELY(mViewSource
)) {
1664 mViewSource
->AddErrorToCurrentRun("errEndTagSeenWithSelectOpen", aName
);
1668 void nsHtml5TreeBuilder::errGarbageInColgroup() {
1669 if (MOZ_UNLIKELY(mViewSource
)) {
1670 mViewSource
->AddErrorToCurrentRun("errGarbageInColgroup");
1674 void nsHtml5TreeBuilder::errEndTagBr() {
1675 if (MOZ_UNLIKELY(mViewSource
)) {
1676 mViewSource
->AddErrorToCurrentRun("errEndTagBr");
1680 void nsHtml5TreeBuilder::errNoElementToCloseButEndTagSeen(nsAtom
* aName
) {
1681 if (MOZ_UNLIKELY(mViewSource
)) {
1682 mViewSource
->AddErrorToCurrentRun("errNoElementToCloseButEndTagSeen",
1687 void nsHtml5TreeBuilder::errHtmlStartTagInForeignContext(nsAtom
* aName
) {
1688 if (MOZ_UNLIKELY(mViewSource
)) {
1689 mViewSource
->AddErrorToCurrentRun("errHtmlStartTagInForeignContext", aName
);
1693 void nsHtml5TreeBuilder::errNoTableRowToClose() {
1694 if (MOZ_UNLIKELY(mViewSource
)) {
1695 mViewSource
->AddErrorToCurrentRun("errNoTableRowToClose");
1699 void nsHtml5TreeBuilder::errNonSpaceInTable() {
1700 if (MOZ_UNLIKELY(mViewSource
)) {
1701 mViewSource
->AddErrorToCurrentRun("errNonSpaceInTable");
1705 void nsHtml5TreeBuilder::errUnclosedChildrenInRuby() {
1706 if (MOZ_UNLIKELY(mViewSource
)) {
1707 mViewSource
->AddErrorToCurrentRun("errUnclosedChildrenInRuby");
1711 void nsHtml5TreeBuilder::errStartTagSeenWithoutRuby(nsAtom
* aName
) {
1712 if (MOZ_UNLIKELY(mViewSource
)) {
1713 mViewSource
->AddErrorToCurrentRun("errStartTagSeenWithoutRuby", aName
);
1717 void nsHtml5TreeBuilder::errSelfClosing() {
1718 if (MOZ_UNLIKELY(mViewSource
)) {
1719 mViewSource
->AddErrorToCurrentSlash("errSelfClosing");
1723 void nsHtml5TreeBuilder::errNoCheckUnclosedElementsOnStack() {
1724 if (MOZ_UNLIKELY(mViewSource
)) {
1725 mViewSource
->AddErrorToCurrentRun("errNoCheckUnclosedElementsOnStack");
1729 void nsHtml5TreeBuilder::errEndTagDidNotMatchCurrentOpenElement(
1730 nsAtom
* aName
, nsAtom
* aOther
) {
1731 if (MOZ_UNLIKELY(mViewSource
)) {
1732 mViewSource
->AddErrorToCurrentRun("errEndTagDidNotMatchCurrentOpenElement",
1737 void nsHtml5TreeBuilder::errEndTagViolatesNestingRules(nsAtom
* aName
) {
1738 if (MOZ_UNLIKELY(mViewSource
)) {
1739 mViewSource
->AddErrorToCurrentRun("errEndTagViolatesNestingRules", aName
);
1743 void nsHtml5TreeBuilder::errEndWithUnclosedElements(nsAtom
* aName
) {
1744 if (MOZ_UNLIKELY(mViewSource
)) {
1745 mViewSource
->AddErrorToCurrentRun("errEndWithUnclosedElements", aName
);
1749 void nsHtml5TreeBuilder::errListUnclosedStartTags(int32_t aIgnored
) {
1750 if (MOZ_UNLIKELY(mViewSource
)) {
1751 mViewSource
->AddErrorToCurrentRun("errListUnclosedStartTags");