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/. */
9 #include "nsHtml5AttributeName.h"
10 #include "nsHtml5String.h"
11 #include "nsNetUtil.h"
12 #include "mozilla/dom/FetchPriority.h"
13 #include "mozilla/CheckedInt.h"
14 #include "mozilla/Likely.h"
15 #include "mozilla/StaticPrefs_dom.h"
16 #include "mozilla/StaticPrefs_network.h"
17 #include "mozilla/UniquePtr.h"
18 #include "mozilla/UniquePtrExtensions.h"
20 nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsHtml5OplessBuilder
* aBuilder
)
25 scriptingEnabled(false),
29 contextNamespace(kNameSpaceID_None
),
46 mSpeculativeLoadStage(nullptr),
48 mCurrentHtmlScriptCannotDocumentWriteOrBlock(false),
49 mPreventScriptExecution(false),
50 mGenerateSpeculativeLoads(false),
51 mHasSeenImportMap(false)
57 MOZ_COUNT_CTOR(nsHtml5TreeBuilder
);
60 nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsAHtml5TreeOpSink
* aOpSink
,
61 nsHtml5TreeOpStage
* aStage
,
62 bool aGenerateSpeculativeLoads
)
67 scriptingEnabled(false),
71 contextNamespace(kNameSpaceID_None
),
86 mHandles(new nsIContent
*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH
]),
88 mSpeculativeLoadStage(aStage
),
90 mCurrentHtmlScriptCannotDocumentWriteOrBlock(false),
91 mPreventScriptExecution(false),
92 mGenerateSpeculativeLoads(aGenerateSpeculativeLoads
),
93 mHasSeenImportMap(false)
99 MOZ_ASSERT(!(!aStage
&& aGenerateSpeculativeLoads
),
100 "Must not generate speculative loads without a stage");
101 MOZ_COUNT_CTOR(nsHtml5TreeBuilder
);
104 nsHtml5TreeBuilder::~nsHtml5TreeBuilder() {
105 MOZ_COUNT_DTOR(nsHtml5TreeBuilder
);
106 NS_ASSERTION(!mActive
,
107 "nsHtml5TreeBuilder deleted without ever calling end() on it!");
111 nsIContentHandle
* nsHtml5TreeBuilder::createElement(
112 int32_t aNamespace
, nsAtom
* aName
, nsHtml5HtmlAttributes
* aAttributes
,
113 nsIContentHandle
* aIntendedParent
, nsHtml5ContentCreatorFunction aCreator
) {
114 MOZ_ASSERT(aAttributes
, "Got null attributes.");
115 MOZ_ASSERT(aName
, "Got null name.");
116 MOZ_ASSERT(aNamespace
== kNameSpaceID_XHTML
||
117 aNamespace
== kNameSpaceID_SVG
||
118 aNamespace
== kNameSpaceID_MathML
,
122 nsIContent
* intendedParent
=
123 aIntendedParent
? static_cast<nsIContent
*>(aIntendedParent
) : nullptr;
125 // intendedParent == nullptr is a special case where the
126 // intended parent is the document.
127 nsNodeInfoManager
* nodeInfoManager
=
128 intendedParent
? intendedParent
->OwnerDoc()->NodeInfoManager()
129 : mBuilder
->GetNodeInfoManager();
132 if (aNamespace
== kNameSpaceID_XHTML
) {
133 elem
= nsHtml5TreeOperation::CreateHTMLElement(
134 aName
, aAttributes
, mozilla::dom::FROM_PARSER_FRAGMENT
,
135 nodeInfoManager
, mBuilder
, aCreator
.html
);
136 } else if (aNamespace
== kNameSpaceID_SVG
) {
137 elem
= nsHtml5TreeOperation::CreateSVGElement(
138 aName
, aAttributes
, mozilla::dom::FROM_PARSER_FRAGMENT
,
139 nodeInfoManager
, mBuilder
, aCreator
.svg
);
141 MOZ_ASSERT(aNamespace
== kNameSpaceID_MathML
);
142 elem
= nsHtml5TreeOperation::CreateMathMLElement(
143 aName
, aAttributes
, nodeInfoManager
, mBuilder
);
145 if (MOZ_UNLIKELY(aAttributes
!= tokenizer
->GetAttributes() &&
146 aAttributes
!= nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES
)) {
152 nsIContentHandle
* content
= AllocateContentHandle();
153 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
154 if (MOZ_UNLIKELY(!treeOp
)) {
155 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
159 if (aNamespace
== kNameSpaceID_XHTML
) {
160 opCreateHTMLElement
opeation(
161 content
, aName
, aAttributes
, aCreator
.html
, aIntendedParent
,
162 (!!mSpeculativeLoadStage
) ? mozilla::dom::FROM_PARSER_NETWORK
163 : mozilla::dom::FROM_PARSER_DOCUMENT_WRITE
);
164 treeOp
->Init(mozilla::AsVariant(opeation
));
165 } else if (aNamespace
== kNameSpaceID_SVG
) {
166 opCreateSVGElement
operation(
167 content
, aName
, aAttributes
, aCreator
.svg
, aIntendedParent
,
168 (!!mSpeculativeLoadStage
) ? mozilla::dom::FROM_PARSER_NETWORK
169 : mozilla::dom::FROM_PARSER_DOCUMENT_WRITE
);
170 treeOp
->Init(mozilla::AsVariant(operation
));
172 // kNameSpaceID_MathML
173 opCreateMathMLElement
operation(content
, aName
, aAttributes
,
175 treeOp
->Init(mozilla::AsVariant(operation
));
178 // mSpeculativeLoadStage is non-null only in the off-the-main-thread
179 // tree builder, which handles the network stream
181 // Start wall of code for speculative loading and line numbers
183 if (mGenerateSpeculativeLoads
&& mode
!= IN_TEMPLATE
) {
184 switch (aNamespace
) {
185 case kNameSpaceID_XHTML
:
186 if (nsGkAtoms::img
== aName
) {
187 nsHtml5String loading
=
188 aAttributes
->getValue(nsHtml5AttributeName::ATTR_LOADING
);
189 if (!loading
.LowerCaseEqualsASCII("lazy")) {
191 aAttributes
->getValue(nsHtml5AttributeName::ATTR_SRC
);
192 nsHtml5String srcset
=
193 aAttributes
->getValue(nsHtml5AttributeName::ATTR_SRCSET
);
194 nsHtml5String crossOrigin
=
195 aAttributes
->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN
);
196 nsHtml5String referrerPolicy
= aAttributes
->getValue(
197 nsHtml5AttributeName::ATTR_REFERRERPOLICY
);
198 nsHtml5String sizes
=
199 aAttributes
->getValue(nsHtml5AttributeName::ATTR_SIZES
);
200 mSpeculativeLoadQueue
.AppendElement()->InitImage(
201 url
, crossOrigin
, /* aMedia = */ nullptr, referrerPolicy
,
202 srcset
, sizes
, false);
204 } else if (nsGkAtoms::source
== aName
) {
205 nsHtml5String srcset
=
206 aAttributes
->getValue(nsHtml5AttributeName::ATTR_SRCSET
);
207 // Sources without srcset cannot be selected. The source could also be
208 // for a media element, but in that context doesn't use srcset. See
209 // comments in nsHtml5SpeculativeLoad.h about <picture> preloading
211 nsHtml5String sizes
=
212 aAttributes
->getValue(nsHtml5AttributeName::ATTR_SIZES
);
214 aAttributes
->getValue(nsHtml5AttributeName::ATTR_TYPE
);
215 nsHtml5String media
=
216 aAttributes
->getValue(nsHtml5AttributeName::ATTR_MEDIA
);
217 mSpeculativeLoadQueue
.AppendElement()->InitPictureSource(
218 srcset
, sizes
, type
, media
);
220 } else if (nsGkAtoms::script
== aName
) {
221 nsHtml5TreeOperation
* treeOp
=
222 mOpQueue
.AppendElement(mozilla::fallible
);
223 if (MOZ_UNLIKELY(!treeOp
)) {
224 MarkAsBrokenAndRequestSuspensionWithoutBuilder(
225 NS_ERROR_OUT_OF_MEMORY
);
228 opSetScriptLineAndColumnNumberAndFreeze
operation(
229 content
, tokenizer
->getLineNumber(),
230 // NOTE: tokenizer->getColumnNumber() points '>'.
231 tokenizer
->getColumnNumber() + 1);
232 treeOp
->Init(mozilla::AsVariant(operation
));
235 aAttributes
->getValue(nsHtml5AttributeName::ATTR_TYPE
);
236 nsAutoString typeString
;
237 type
.ToString(typeString
);
239 // Since `typeString` after trimming and lowercasing is only checked
240 // for "module" and " importmap", we don't need to remember
241 // pre-trimming emptiness here.
243 // ASCII whitespace https://infra.spec.whatwg.org/#ascii-whitespace:
244 // U+0009 TAB, U+000A LF, U+000C FF, U+000D CR, or U+0020 SPACE.
245 static const char kASCIIWhitespace
[] = "\t\n\f\r ";
246 typeString
.Trim(kASCIIWhitespace
);
248 bool isModule
= typeString
.LowerCaseEqualsASCII("module");
249 bool importmap
= typeString
.LowerCaseEqualsASCII("importmap");
253 aAttributes
->contains(nsHtml5AttributeName::ATTR_NOMODULE
);
255 // For microtask semantics, we need to queue either
256 // `opRunScriptThatMayDocumentWriteOrBlock` or
257 // `opRunScriptThatCannotDocumentWriteOrBlock` for every script
258 // element--even ones that we already know won't run.
259 // `mCurrentHtmlScriptCannotDocumentWriteOrBlock` controls which
260 // kind of operation is used for an HTML script, and this is the
261 // place where `mCurrentHtmlScriptCannotDocumentWriteOrBlock`
262 // needs to be set correctly.
264 // Non-async, non-defer classic scripts that will run MUST use
265 // `opRunScriptThatMayDocumentWriteOrBlock` in order to run
266 // the more complex code that
267 // 1. is able to resume the HTML parse after a parser-blocking
268 // scripts no longer blocks the parser
269 // 2. is able to receive more content to parse on the main thread
270 // via document.write
271 // 3. is able to throw away off-the-main-thread parsing results
272 // if what's document.written on the main thread invalidates
275 // Async and defer classic scripts as well as module scripts and
276 // importmaps MUST use `opRunScriptThatCannotDocumentWriteOrBlock`.
277 // This is necessary particularly because the relevant main-thread
278 // code assumes it doesn't need to deal with resuming the HTML
279 // parse some time afterwards, so using a tree operation with
280 // mismatching expectations regarding that responsibility may
281 // cause the HTML parse to stall.
283 // Various scripts that won't actually run work with either type
284 // of tree op in the sense that the HTML parse won't stall.
285 // However, in the case where a script cannot block or insert
286 // data to the HTML parser via document.write, unnecessary use
287 // of `opRunScriptThatMayDocumentWriteOrBlock` instead of
288 // `opRunScriptThatCannotDocumentWriteOrBlock` causes the HTML
289 // parser to enter the speculative mode when doing so isn't
290 // actually required.
292 // Ideally, we would check for `type`/`language` attribute
293 // combinations that are known to cause non-execution as well as
294 // ScriptLoader::IsScriptEventHandler equivalent. That way, we
295 // wouldn't unnecessarily speculate after scripts that won't
296 // execute. https://bugzilla.mozilla.org/show_bug.cgi?id=1848311
299 // If we see an importmap, we don't want to later start speculative
300 // loads for modulepreloads, since such load might finish before
301 // the importmap is created. This also applies to module scripts so
302 // that any modulepreload integrity checks can be performed before
303 // the modules scripts are loaded.
304 // This state is not part of speculation rollback: If an importmap
305 // is seen speculatively and the speculation is rolled back, the
306 // importmap is still considered seen.
307 // TODO: Sync importmap seenness between the main thread and the
309 // https://bugzilla.mozilla.org/show_bug.cgi?id=1848312
310 mHasSeenImportMap
= true;
313 aAttributes
->getValue(nsHtml5AttributeName::ATTR_SRC
);
315 async
= aAttributes
->contains(nsHtml5AttributeName::ATTR_ASYNC
);
316 defer
= aAttributes
->contains(nsHtml5AttributeName::ATTR_DEFER
);
317 if ((isModule
&& !mHasSeenImportMap
) ||
318 (!isModule
&& !importmap
&& !nomodule
)) {
319 nsHtml5String charset
=
320 aAttributes
->getValue(nsHtml5AttributeName::ATTR_CHARSET
);
321 nsHtml5String crossOrigin
=
322 aAttributes
->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN
);
323 nsHtml5String nonce
=
324 aAttributes
->getValue(nsHtml5AttributeName::ATTR_NONCE
);
325 nsHtml5String fetchPriority
= aAttributes
->getValue(
326 nsHtml5AttributeName::ATTR_FETCHPRIORITY
);
327 nsHtml5String integrity
=
328 aAttributes
->getValue(nsHtml5AttributeName::ATTR_INTEGRITY
);
329 nsHtml5String referrerPolicy
= aAttributes
->getValue(
330 nsHtml5AttributeName::ATTR_REFERRERPOLICY
);
331 mSpeculativeLoadQueue
.AppendElement()->InitScript(
332 url
, charset
, type
, crossOrigin
, /* aMedia = */ nullptr,
333 nonce
, fetchPriority
, integrity
, referrerPolicy
,
334 mode
== nsHtml5TreeBuilder::IN_HEAD
, async
, defer
, false);
337 // `mCurrentHtmlScriptCannotDocumentWriteOrBlock` MUST be computed to
338 // match the ScriptLoader-perceived kind of the script regardless of
339 // enqueuing a speculative load. Scripts with the `nomodule` attribute
340 // never block or document.write: Either the attribute prevents a
341 // classic script execution or is ignored on a module script or
343 mCurrentHtmlScriptCannotDocumentWriteOrBlock
=
344 isModule
|| importmap
|| async
|| defer
|| nomodule
;
345 } else if (nsGkAtoms::link
== aName
) {
347 aAttributes
->getValue(nsHtml5AttributeName::ATTR_REL
);
348 // Not splitting on space here is bogus but the old parser didn't even
349 // do a case-insensitive check.
351 if (rel
.LowerCaseEqualsASCII("stylesheet")) {
353 aAttributes
->getValue(nsHtml5AttributeName::ATTR_HREF
);
355 nsHtml5String charset
=
356 aAttributes
->getValue(nsHtml5AttributeName::ATTR_CHARSET
);
357 nsHtml5String crossOrigin
= aAttributes
->getValue(
358 nsHtml5AttributeName::ATTR_CROSSORIGIN
);
359 nsHtml5String nonce
=
360 aAttributes
->getValue(nsHtml5AttributeName::ATTR_NONCE
);
361 nsHtml5String integrity
=
362 aAttributes
->getValue(nsHtml5AttributeName::ATTR_INTEGRITY
);
363 nsHtml5String referrerPolicy
= aAttributes
->getValue(
364 nsHtml5AttributeName::ATTR_REFERRERPOLICY
);
365 nsHtml5String media
=
366 aAttributes
->getValue(nsHtml5AttributeName::ATTR_MEDIA
);
367 nsHtml5String fetchPriority
= aAttributes
->getValue(
368 nsHtml5AttributeName::ATTR_FETCHPRIORITY
);
369 mSpeculativeLoadQueue
.AppendElement()->InitStyle(
370 url
, charset
, crossOrigin
, media
, referrerPolicy
, nonce
,
371 integrity
, false, fetchPriority
);
373 } else if (rel
.LowerCaseEqualsASCII("preconnect")) {
375 aAttributes
->getValue(nsHtml5AttributeName::ATTR_HREF
);
377 nsHtml5String crossOrigin
= aAttributes
->getValue(
378 nsHtml5AttributeName::ATTR_CROSSORIGIN
);
379 mSpeculativeLoadQueue
.AppendElement()->InitPreconnect(
382 } else if (rel
.LowerCaseEqualsASCII("preload")) {
384 aAttributes
->getValue(nsHtml5AttributeName::ATTR_HREF
);
387 aAttributes
->getValue(nsHtml5AttributeName::ATTR_AS
);
388 nsHtml5String charset
=
389 aAttributes
->getValue(nsHtml5AttributeName::ATTR_CHARSET
);
390 nsHtml5String crossOrigin
= aAttributes
->getValue(
391 nsHtml5AttributeName::ATTR_CROSSORIGIN
);
392 nsHtml5String nonce
=
393 aAttributes
->getValue(nsHtml5AttributeName::ATTR_NONCE
);
394 nsHtml5String integrity
=
395 aAttributes
->getValue(nsHtml5AttributeName::ATTR_INTEGRITY
);
396 nsHtml5String referrerPolicy
= aAttributes
->getValue(
397 nsHtml5AttributeName::ATTR_REFERRERPOLICY
);
398 nsHtml5String media
=
399 aAttributes
->getValue(nsHtml5AttributeName::ATTR_MEDIA
);
400 nsHtml5String fetchPriority
= aAttributes
->getValue(
401 nsHtml5AttributeName::ATTR_FETCHPRIORITY
);
403 // Note that respective speculative loaders for scripts and
404 // styles check all additional attributes to be equal to use the
405 // speculative load. So, if any of them is specified and the
406 // preload has to take the expected effect, those attributes
407 // must also be specified on the actual tag to use the preload.
408 // Omitting an attribute on both will make the values equal
409 // (empty) and thus use the preload.
410 if (as
.LowerCaseEqualsASCII("script")) {
412 aAttributes
->getValue(nsHtml5AttributeName::ATTR_TYPE
);
413 mSpeculativeLoadQueue
.AppendElement()->InitScript(
414 url
, charset
, type
, crossOrigin
, media
, nonce
,
415 /* aFetchPriority */ fetchPriority
, integrity
,
416 referrerPolicy
, mode
== nsHtml5TreeBuilder::IN_HEAD
,
418 } else if (as
.LowerCaseEqualsASCII("style")) {
419 mSpeculativeLoadQueue
.AppendElement()->InitStyle(
420 url
, charset
, crossOrigin
, media
, referrerPolicy
, nonce
,
421 integrity
, true, fetchPriority
);
422 } else if (as
.LowerCaseEqualsASCII("image")) {
423 nsHtml5String srcset
= aAttributes
->getValue(
424 nsHtml5AttributeName::ATTR_IMAGESRCSET
);
425 nsHtml5String sizes
= aAttributes
->getValue(
426 nsHtml5AttributeName::ATTR_IMAGESIZES
);
427 mSpeculativeLoadQueue
.AppendElement()->InitImage(
428 url
, crossOrigin
, media
, referrerPolicy
, srcset
, sizes
,
430 } else if (as
.LowerCaseEqualsASCII("font")) {
431 mSpeculativeLoadQueue
.AppendElement()->InitFont(
432 url
, crossOrigin
, media
, referrerPolicy
, fetchPriority
);
433 } else if (as
.LowerCaseEqualsASCII("fetch")) {
434 mSpeculativeLoadQueue
.AppendElement()->InitFetch(
435 url
, crossOrigin
, media
, referrerPolicy
, fetchPriority
);
437 // Other "as" values will be supported later.
439 } else if (mozilla::StaticPrefs::network_modulepreload() &&
440 rel
.LowerCaseEqualsASCII("modulepreload") &&
441 !mHasSeenImportMap
) {
443 aAttributes
->getValue(nsHtml5AttributeName::ATTR_HREF
);
444 if (url
&& url
.Length() != 0) {
446 aAttributes
->getValue(nsHtml5AttributeName::ATTR_AS
);
447 nsAutoString asString
;
448 as
.ToString(asString
);
449 if (mozilla::net::IsScriptLikeOrInvalid(asString
)) {
450 nsHtml5String charset
=
451 aAttributes
->getValue(nsHtml5AttributeName::ATTR_CHARSET
);
452 RefPtr
<nsAtom
> moduleType
= nsGkAtoms::_module
;
454 nsHtml5String::FromAtom(moduleType
.forget());
455 nsHtml5String crossOrigin
= aAttributes
->getValue(
456 nsHtml5AttributeName::ATTR_CROSSORIGIN
);
457 nsHtml5String media
=
458 aAttributes
->getValue(nsHtml5AttributeName::ATTR_MEDIA
);
459 nsHtml5String nonce
=
460 aAttributes
->getValue(nsHtml5AttributeName::ATTR_NONCE
);
461 nsHtml5String integrity
= aAttributes
->getValue(
462 nsHtml5AttributeName::ATTR_INTEGRITY
);
463 nsHtml5String referrerPolicy
= aAttributes
->getValue(
464 nsHtml5AttributeName::ATTR_REFERRERPOLICY
);
465 nsHtml5String fetchPriority
= aAttributes
->getValue(
466 nsHtml5AttributeName::ATTR_FETCHPRIORITY
);
468 mSpeculativeLoadQueue
.AppendElement()->InitScript(
469 url
, charset
, type
, crossOrigin
, media
, nonce
,
470 /* aFetchPriority */ fetchPriority
, integrity
,
471 referrerPolicy
, mode
== nsHtml5TreeBuilder::IN_HEAD
,
477 } else if (nsGkAtoms::video
== aName
) {
479 aAttributes
->getValue(nsHtml5AttributeName::ATTR_POSTER
);
481 mSpeculativeLoadQueue
.AppendElement()->InitImage(
482 url
, nullptr, nullptr, nullptr, nullptr, nullptr, false);
484 } else if (nsGkAtoms::style
== aName
) {
485 mImportScanner
.Start();
486 nsHtml5TreeOperation
* treeOp
=
487 mOpQueue
.AppendElement(mozilla::fallible
);
488 if (MOZ_UNLIKELY(!treeOp
)) {
489 MarkAsBrokenAndRequestSuspensionWithoutBuilder(
490 NS_ERROR_OUT_OF_MEMORY
);
493 opSetStyleLineNumber
operation(content
, tokenizer
->getLineNumber());
494 treeOp
->Init(mozilla::AsVariant(operation
));
495 } else if (nsGkAtoms::html
== aName
) {
497 aAttributes
->getValue(nsHtml5AttributeName::ATTR_MANIFEST
);
498 mSpeculativeLoadQueue
.AppendElement()->InitManifest(url
);
499 } else if (nsGkAtoms::base
== aName
) {
501 aAttributes
->getValue(nsHtml5AttributeName::ATTR_HREF
);
503 mSpeculativeLoadQueue
.AppendElement()->InitBase(url
);
505 } else if (nsGkAtoms::meta
== aName
) {
506 if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
507 "content-security-policy",
508 aAttributes
->getValue(
509 nsHtml5AttributeName::ATTR_HTTP_EQUIV
))) {
511 aAttributes
->getValue(nsHtml5AttributeName::ATTR_CONTENT
);
513 mSpeculativeLoadQueue
.AppendElement()->InitMetaCSP(csp
);
515 } else if (nsHtml5Portability::
516 lowerCaseLiteralEqualsIgnoreAsciiCaseString(
518 aAttributes
->getValue(
519 nsHtml5AttributeName::ATTR_NAME
))) {
520 nsHtml5String referrerPolicy
=
521 aAttributes
->getValue(nsHtml5AttributeName::ATTR_CONTENT
);
522 if (referrerPolicy
) {
523 mSpeculativeLoadQueue
.AppendElement()->InitMetaReferrerPolicy(
529 case kNameSpaceID_SVG
:
530 if (nsGkAtoms::image
== aName
) {
532 aAttributes
->getValue(nsHtml5AttributeName::ATTR_HREF
);
534 url
= aAttributes
->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF
);
537 mSpeculativeLoadQueue
.AppendElement()->InitImage(
538 url
, nullptr, nullptr, nullptr, nullptr, nullptr, false);
540 } else if (nsGkAtoms::script
== aName
) {
541 nsHtml5TreeOperation
* treeOp
=
542 mOpQueue
.AppendElement(mozilla::fallible
);
543 if (MOZ_UNLIKELY(!treeOp
)) {
544 MarkAsBrokenAndRequestSuspensionWithoutBuilder(
545 NS_ERROR_OUT_OF_MEMORY
);
548 opSetScriptLineAndColumnNumberAndFreeze
operation(
549 content
, tokenizer
->getLineNumber(),
550 // NOTE: tokenizer->getColumnNumber() points '>'.
551 tokenizer
->getColumnNumber() + 1);
552 treeOp
->Init(mozilla::AsVariant(operation
));
555 aAttributes
->getValue(nsHtml5AttributeName::ATTR_HREF
);
557 url
= aAttributes
->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF
);
561 aAttributes
->getValue(nsHtml5AttributeName::ATTR_TYPE
);
562 nsHtml5String crossOrigin
=
563 aAttributes
->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN
);
564 nsHtml5String nonce
=
565 aAttributes
->getValue(nsHtml5AttributeName::ATTR_NONCE
);
566 nsHtml5String integrity
=
567 aAttributes
->getValue(nsHtml5AttributeName::ATTR_INTEGRITY
);
568 nsHtml5String referrerPolicy
= aAttributes
->getValue(
569 nsHtml5AttributeName::ATTR_REFERRERPOLICY
);
571 // Bug 1847712: SVG's `<script>` element doesn't support
572 // `fetchpriority` yet.
573 // Use the empty string and rely on the
574 // "invalid value default" state being used later.
575 // Compared to using a non-empty string, this doesn't
576 // require calling `Release()` for the string.
577 nsHtml5String fetchPriority
= nsHtml5String::EmptyString();
579 mSpeculativeLoadQueue
.AppendElement()->InitScript(
580 url
, nullptr, type
, crossOrigin
, /* aMedia = */ nullptr, nonce
,
581 fetchPriority
, integrity
, referrerPolicy
,
582 mode
== nsHtml5TreeBuilder::IN_HEAD
, false, false, false);
584 } else if (nsGkAtoms::style
== aName
) {
585 mImportScanner
.Start();
586 nsHtml5TreeOperation
* treeOp
=
587 mOpQueue
.AppendElement(mozilla::fallible
);
588 if (MOZ_UNLIKELY(!treeOp
)) {
589 MarkAsBrokenAndRequestSuspensionWithoutBuilder(
590 NS_ERROR_OUT_OF_MEMORY
);
593 opSetStyleLineNumber
operation(content
, tokenizer
->getLineNumber());
594 treeOp
->Init(mozilla::AsVariant(operation
));
598 } else if (aNamespace
!= kNameSpaceID_MathML
) {
599 // No speculative loader--just line numbers and defer/async check
600 if (nsGkAtoms::style
== aName
) {
601 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
602 if (MOZ_UNLIKELY(!treeOp
)) {
603 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
606 opSetStyleLineNumber
operation(content
, tokenizer
->getLineNumber());
607 treeOp
->Init(mozilla::AsVariant(operation
));
608 } else if (nsGkAtoms::script
== aName
) {
609 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
610 if (MOZ_UNLIKELY(!treeOp
)) {
611 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
614 opSetScriptLineAndColumnNumberAndFreeze
operation(
615 content
, tokenizer
->getLineNumber(),
616 // NOTE: tokenizer->getColumnNumber() points '>'.
617 tokenizer
->getColumnNumber() + 1);
618 treeOp
->Init(mozilla::AsVariant(operation
));
619 if (aNamespace
== kNameSpaceID_XHTML
) {
620 // Although we come here in cases where the value of
621 // `mCurrentHtmlScriptCannotDocumentWriteOrBlock` doesn't actually
622 // matter, we also come here when parsing document.written content on
623 // the main thread. In that case, IT MATTERS that
624 // `mCurrentHtmlScriptCannotDocumentWriteOrBlock` is set correctly,
625 // so let's just always set it correctly even if it a bit of wasted work
626 // in the scenarios where no scripts execute and it doesn't matter.
628 // See the comments around generating speculative loads for HTML scripts
629 // elements for the details of when
630 // `mCurrentHtmlScriptCannotDocumentWriteOrBlock` needs to be set to
631 // `true` and when to `false`.
634 aAttributes
->getValue(nsHtml5AttributeName::ATTR_TYPE
);
635 nsAutoString typeString
;
636 type
.ToString(typeString
);
638 // Since `typeString` after trimming and lowercasing is only checked
639 // for "module" and " importmap", we don't need to remember
640 // pre-trimming emptiness here.
642 // ASCII whitespace https://infra.spec.whatwg.org/#ascii-whitespace:
643 // U+0009 TAB, U+000A LF, U+000C FF, U+000D CR, or U+0020 SPACE.
644 static const char kASCIIWhitespace
[] = "\t\n\f\r ";
645 typeString
.Trim(kASCIIWhitespace
);
647 mCurrentHtmlScriptCannotDocumentWriteOrBlock
=
648 typeString
.LowerCaseEqualsASCII("module") ||
649 typeString
.LowerCaseEqualsASCII("nomodule") ||
650 typeString
.LowerCaseEqualsASCII("importmap");
652 if (!mCurrentHtmlScriptCannotDocumentWriteOrBlock
&&
653 aAttributes
->contains(nsHtml5AttributeName::ATTR_SRC
)) {
654 mCurrentHtmlScriptCannotDocumentWriteOrBlock
=
655 (aAttributes
->contains(nsHtml5AttributeName::ATTR_ASYNC
) ||
656 aAttributes
->contains(nsHtml5AttributeName::ATTR_DEFER
));
659 } else if (aNamespace
== kNameSpaceID_XHTML
) {
660 if (nsGkAtoms::html
== aName
) {
662 aAttributes
->getValue(nsHtml5AttributeName::ATTR_MANIFEST
);
663 nsHtml5TreeOperation
* treeOp
=
664 mOpQueue
.AppendElement(mozilla::fallible
);
665 if (MOZ_UNLIKELY(!treeOp
)) {
666 MarkAsBrokenAndRequestSuspensionWithoutBuilder(
667 NS_ERROR_OUT_OF_MEMORY
);
672 urlString
; // Not Auto, because using it to hold nsStringBuffer*
673 url
.ToString(urlString
);
674 opProcessOfflineManifest
operation(ToNewUnicode(urlString
));
675 treeOp
->Init(mozilla::AsVariant(operation
));
677 opProcessOfflineManifest
operation(ToNewUnicode(u
""_ns
));
678 treeOp
->Init(mozilla::AsVariant(operation
));
680 } else if (nsGkAtoms::base
== aName
&& mViewSource
) {
682 aAttributes
->getValue(nsHtml5AttributeName::ATTR_HREF
);
684 mViewSource
->AddBase(url
);
690 // End wall of code for speculative loading
695 nsIContentHandle
* nsHtml5TreeBuilder::createElement(
696 int32_t aNamespace
, nsAtom
* aName
, nsHtml5HtmlAttributes
* aAttributes
,
697 nsIContentHandle
* aFormElement
, nsIContentHandle
* aIntendedParent
,
698 nsHtml5ContentCreatorFunction aCreator
) {
699 nsIContentHandle
* content
=
700 createElement(aNamespace
, aName
, aAttributes
, aIntendedParent
, aCreator
);
703 nsHtml5TreeOperation::SetFormElement(
704 static_cast<nsIContent
*>(content
),
705 static_cast<nsIContent
*>(aFormElement
));
707 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
708 if (MOZ_UNLIKELY(!treeOp
)) {
709 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
712 opSetFormElement
operation(content
, aFormElement
);
713 treeOp
->Init(mozilla::AsVariant(operation
));
719 nsIContentHandle
* nsHtml5TreeBuilder::createHtmlElementSetAsRoot(
720 nsHtml5HtmlAttributes
* aAttributes
) {
721 nsHtml5ContentCreatorFunction creator
;
722 // <html> uses NS_NewHTMLSharedElement creator
723 creator
.html
= NS_NewHTMLSharedElement
;
724 nsIContentHandle
* content
= createElement(kNameSpaceID_XHTML
, nsGkAtoms::html
,
725 aAttributes
, nullptr, creator
);
727 nsresult rv
= nsHtml5TreeOperation::AppendToDocument(
728 static_cast<nsIContent
*>(content
), mBuilder
);
730 MarkAsBrokenAndRequestSuspensionWithBuilder(rv
);
733 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
734 if (MOZ_UNLIKELY(!treeOp
)) {
735 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
738 opAppendToDocument
operation(content
);
739 treeOp
->Init(mozilla::AsVariant(operation
));
744 nsIContentHandle
* nsHtml5TreeBuilder::createAndInsertFosterParentedElement(
745 int32_t aNamespace
, nsAtom
* aName
, nsHtml5HtmlAttributes
* aAttributes
,
746 nsIContentHandle
* aFormElement
, nsIContentHandle
* aTable
,
747 nsIContentHandle
* aStackParent
, nsHtml5ContentCreatorFunction aCreator
) {
748 MOZ_ASSERT(aTable
, "Null table");
749 MOZ_ASSERT(aStackParent
, "Null stack parent");
752 // Get the foster parent to use as the intended parent when creating
753 // the child element.
754 nsIContent
* fosterParent
= nsHtml5TreeOperation::GetFosterParent(
755 static_cast<nsIContent
*>(aTable
),
756 static_cast<nsIContent
*>(aStackParent
));
758 nsIContentHandle
* child
= createElement(
759 aNamespace
, aName
, aAttributes
, aFormElement
, fosterParent
, aCreator
);
761 insertFosterParentedChild(child
, aTable
, aStackParent
);
766 // Tree op to get the foster parent that we use as the intended parent
767 // when creating the child element.
768 nsHtml5TreeOperation
* fosterParentTreeOp
= mOpQueue
.AppendElement();
769 NS_ASSERTION(fosterParentTreeOp
, "Tree op allocation failed.");
770 nsIContentHandle
* fosterParentHandle
= AllocateContentHandle();
771 opGetFosterParent
operation(aTable
, aStackParent
, fosterParentHandle
);
772 fosterParentTreeOp
->Init(mozilla::AsVariant(operation
));
774 // Create the element with the correct intended parent.
775 nsIContentHandle
* child
=
776 createElement(aNamespace
, aName
, aAttributes
, aFormElement
,
777 fosterParentHandle
, aCreator
);
779 // Insert the child into the foster parent.
780 insertFosterParentedChild(child
, aTable
, aStackParent
);
785 void nsHtml5TreeBuilder::detachFromParent(nsIContentHandle
* aElement
) {
786 MOZ_ASSERT(aElement
, "Null element");
789 nsHtml5TreeOperation::Detach(static_cast<nsIContent
*>(aElement
), mBuilder
);
793 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
794 if (MOZ_UNLIKELY(!treeOp
)) {
795 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
798 opDetach
operation(aElement
);
799 treeOp
->Init(mozilla::AsVariant(operation
));
802 void nsHtml5TreeBuilder::appendElement(nsIContentHandle
* aChild
,
803 nsIContentHandle
* aParent
) {
804 MOZ_ASSERT(aChild
, "Null child");
805 MOZ_ASSERT(aParent
, "Null parent");
808 nsresult rv
= nsHtml5TreeOperation::Append(
809 static_cast<nsIContent
*>(aChild
), static_cast<nsIContent
*>(aParent
),
810 mozilla::dom::FROM_PARSER_FRAGMENT
, mBuilder
);
812 MarkAsBrokenAndRequestSuspensionWithBuilder(rv
);
817 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
818 if (MOZ_UNLIKELY(!treeOp
)) {
819 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
823 opAppend
operation(aChild
, aParent
,
824 (!!mSpeculativeLoadStage
)
825 ? mozilla::dom::FROM_PARSER_NETWORK
826 : mozilla::dom::FROM_PARSER_DOCUMENT_WRITE
);
827 treeOp
->Init(mozilla::AsVariant(operation
));
830 void nsHtml5TreeBuilder::appendChildrenToNewParent(
831 nsIContentHandle
* aOldParent
, nsIContentHandle
* aNewParent
) {
832 MOZ_ASSERT(aOldParent
, "Null old parent");
833 MOZ_ASSERT(aNewParent
, "Null new parent");
836 nsresult rv
= nsHtml5TreeOperation::AppendChildrenToNewParent(
837 static_cast<nsIContent
*>(aOldParent
),
838 static_cast<nsIContent
*>(aNewParent
), mBuilder
);
840 MarkAsBrokenAndRequestSuspensionWithBuilder(rv
);
845 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
846 if (MOZ_UNLIKELY(!treeOp
)) {
847 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
850 opAppendChildrenToNewParent
operation(aOldParent
, aNewParent
);
851 treeOp
->Init(mozilla::AsVariant(operation
));
854 void nsHtml5TreeBuilder::insertFosterParentedCharacters(
855 char16_t
* aBuffer
, int32_t aStart
, int32_t aLength
,
856 nsIContentHandle
* aTable
, nsIContentHandle
* aStackParent
) {
857 MOZ_ASSERT(aBuffer
, "Null buffer");
858 MOZ_ASSERT(aTable
, "Null table");
859 MOZ_ASSERT(aStackParent
, "Null stack parent");
860 MOZ_ASSERT(!aStart
, "aStart must always be zero.");
863 nsresult rv
= nsHtml5TreeOperation::FosterParentText(
864 static_cast<nsIContent
*>(aStackParent
),
865 aBuffer
, // XXX aStart always ignored???
866 aLength
, static_cast<nsIContent
*>(aTable
), mBuilder
);
868 MarkAsBrokenAndRequestSuspensionWithBuilder(rv
);
873 auto bufferCopy
= mozilla::MakeUniqueFallible
<char16_t
[]>(aLength
);
875 // Just assigning mBroken instead of generating tree op. The caller
876 // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
877 mBroken
= NS_ERROR_OUT_OF_MEMORY
;
882 memcpy(bufferCopy
.get(), aBuffer
, aLength
* sizeof(char16_t
));
884 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
885 if (MOZ_UNLIKELY(!treeOp
)) {
886 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
889 opFosterParentText
operation(aStackParent
, bufferCopy
.release(), aTable
,
891 treeOp
->Init(mozilla::AsVariant(operation
));
894 void nsHtml5TreeBuilder::insertFosterParentedChild(
895 nsIContentHandle
* aChild
, nsIContentHandle
* aTable
,
896 nsIContentHandle
* aStackParent
) {
897 MOZ_ASSERT(aChild
, "Null child");
898 MOZ_ASSERT(aTable
, "Null table");
899 MOZ_ASSERT(aStackParent
, "Null stack parent");
902 nsresult rv
= nsHtml5TreeOperation::FosterParent(
903 static_cast<nsIContent
*>(aChild
),
904 static_cast<nsIContent
*>(aStackParent
),
905 static_cast<nsIContent
*>(aTable
), mBuilder
);
907 MarkAsBrokenAndRequestSuspensionWithBuilder(rv
);
912 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
913 if (MOZ_UNLIKELY(!treeOp
)) {
914 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
917 opFosterParent
operation(aChild
, aStackParent
, aTable
);
918 treeOp
->Init(mozilla::AsVariant(operation
));
921 void nsHtml5TreeBuilder::appendCharacters(nsIContentHandle
* aParent
,
922 char16_t
* aBuffer
, int32_t aStart
,
924 MOZ_ASSERT(aBuffer
, "Null buffer");
925 MOZ_ASSERT(aParent
, "Null parent");
926 MOZ_ASSERT(!aStart
, "aStart must always be zero.");
929 nsresult rv
= nsHtml5TreeOperation::AppendText(
930 aBuffer
, // XXX aStart always ignored???
931 aLength
, static_cast<nsIContent
*>(aParent
), mBuilder
);
933 MarkAsBrokenAndRequestSuspensionWithBuilder(rv
);
938 auto bufferCopy
= mozilla::MakeUniqueFallible
<char16_t
[]>(aLength
);
940 // Just assigning mBroken instead of generating tree op. The caller
941 // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
942 mBroken
= NS_ERROR_OUT_OF_MEMORY
;
947 memcpy(bufferCopy
.get(), aBuffer
, aLength
* sizeof(char16_t
));
949 if (mImportScanner
.ShouldScan()) {
950 nsTArray
<nsString
> imports
=
951 mImportScanner
.Scan(mozilla::Span(aBuffer
, aLength
));
952 for (nsString
& url
: imports
) {
953 mSpeculativeLoadQueue
.AppendElement()->InitImportStyle(std::move(url
));
957 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
958 if (MOZ_UNLIKELY(!treeOp
)) {
959 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
962 opAppendText
operation(aParent
, bufferCopy
.release(), aLength
);
963 treeOp
->Init(mozilla::AsVariant(operation
));
966 void nsHtml5TreeBuilder::appendComment(nsIContentHandle
* aParent
,
967 char16_t
* aBuffer
, int32_t aStart
,
969 MOZ_ASSERT(aBuffer
, "Null buffer");
970 MOZ_ASSERT(aParent
, "Null parent");
971 MOZ_ASSERT(!aStart
, "aStart must always be zero.");
974 nsresult rv
= nsHtml5TreeOperation::AppendComment(
975 static_cast<nsIContent
*>(aParent
),
976 aBuffer
, // XXX aStart always ignored???
979 MarkAsBrokenAndRequestSuspensionWithBuilder(rv
);
984 auto bufferCopy
= mozilla::MakeUniqueFallible
<char16_t
[]>(aLength
);
986 // Just assigning mBroken instead of generating tree op. The caller
987 // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
988 mBroken
= NS_ERROR_OUT_OF_MEMORY
;
993 memcpy(bufferCopy
.get(), aBuffer
, aLength
* sizeof(char16_t
));
995 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
996 if (MOZ_UNLIKELY(!treeOp
)) {
997 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1000 opAppendComment
operation(aParent
, bufferCopy
.release(), aLength
);
1001 treeOp
->Init(mozilla::AsVariant(operation
));
1004 void nsHtml5TreeBuilder::appendCommentToDocument(char16_t
* aBuffer
,
1007 MOZ_ASSERT(aBuffer
, "Null buffer");
1008 MOZ_ASSERT(!aStart
, "aStart must always be zero.");
1011 nsresult rv
= nsHtml5TreeOperation::AppendCommentToDocument(
1012 aBuffer
, // XXX aStart always ignored???
1014 if (NS_FAILED(rv
)) {
1015 MarkAsBrokenAndRequestSuspensionWithBuilder(rv
);
1020 auto bufferCopy
= mozilla::MakeUniqueFallible
<char16_t
[]>(aLength
);
1022 // Just assigning mBroken instead of generating tree op. The caller
1023 // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
1024 mBroken
= NS_ERROR_OUT_OF_MEMORY
;
1025 requestSuspension();
1029 memcpy(bufferCopy
.get(), aBuffer
, aLength
* sizeof(char16_t
));
1031 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1032 if (MOZ_UNLIKELY(!treeOp
)) {
1033 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1036 opAppendCommentToDocument
data(bufferCopy
.release(), aLength
);
1037 treeOp
->Init(mozilla::AsVariant(data
));
1040 void nsHtml5TreeBuilder::addAttributesToElement(
1041 nsIContentHandle
* aElement
, nsHtml5HtmlAttributes
* aAttributes
) {
1042 MOZ_ASSERT(aElement
, "Null element");
1043 MOZ_ASSERT(aAttributes
, "Null attributes");
1045 if (aAttributes
== nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES
) {
1051 aAttributes
== tokenizer
->GetAttributes(),
1052 "Using attribute other than the tokenizer's to add to body or html.");
1053 nsresult rv
= nsHtml5TreeOperation::AddAttributes(
1054 static_cast<nsIContent
*>(aElement
), aAttributes
, mBuilder
);
1055 if (NS_FAILED(rv
)) {
1056 MarkAsBrokenAndRequestSuspensionWithBuilder(rv
);
1061 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1062 if (MOZ_UNLIKELY(!treeOp
)) {
1063 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1066 opAddAttributes
opeation(aElement
, aAttributes
);
1067 treeOp
->Init(mozilla::AsVariant(opeation
));
1070 void nsHtml5TreeBuilder::markMalformedIfScript(nsIContentHandle
* aElement
) {
1071 MOZ_ASSERT(aElement
, "Null element");
1074 nsHtml5TreeOperation::MarkMalformedIfScript(
1075 static_cast<nsIContent
*>(aElement
));
1079 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1080 if (MOZ_UNLIKELY(!treeOp
)) {
1081 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1084 opMarkMalformedIfScript
operation(aElement
);
1085 treeOp
->Init(mozilla::AsVariant(operation
));
1088 void nsHtml5TreeBuilder::start(bool fragment
) {
1089 mCurrentHtmlScriptCannotDocumentWriteOrBlock
= false;
1095 void nsHtml5TreeBuilder::end() {
1102 void nsHtml5TreeBuilder::appendDoctypeToDocument(nsAtom
* aName
,
1103 nsHtml5String aPublicId
,
1104 nsHtml5String aSystemId
) {
1105 MOZ_ASSERT(aName
, "Null name");
1106 nsString publicId
; // Not Auto, because using it to hold nsStringBuffer*
1107 nsString systemId
; // Not Auto, because using it to hold nsStringBuffer*
1108 aPublicId
.ToString(publicId
);
1109 aSystemId
.ToString(systemId
);
1111 nsresult rv
= nsHtml5TreeOperation::AppendDoctypeToDocument(
1112 aName
, publicId
, systemId
, mBuilder
);
1113 if (NS_FAILED(rv
)) {
1114 MarkAsBrokenAndRequestSuspensionWithBuilder(rv
);
1119 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1120 if (MOZ_UNLIKELY(!treeOp
)) {
1121 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1124 opAppendDoctypeToDocument
operation(aName
, publicId
, systemId
);
1125 treeOp
->Init(mozilla::AsVariant(operation
));
1126 // nsXMLContentSink can flush here, but what's the point?
1127 // It can also interrupt here, but we can't.
1130 void nsHtml5TreeBuilder::elementPushed(int32_t aNamespace
, nsAtom
* aName
,
1131 nsIContentHandle
* aElement
) {
1132 NS_ASSERTION(aNamespace
== kNameSpaceID_XHTML
||
1133 aNamespace
== kNameSpaceID_SVG
||
1134 aNamespace
== kNameSpaceID_MathML
,
1135 "Element isn't HTML, SVG or MathML!");
1136 NS_ASSERTION(aName
, "Element doesn't have local name!");
1137 NS_ASSERTION(aElement
, "No element!");
1139 * The frame constructor uses recursive algorithms, so it can't deal with
1140 * arbitrarily deep trees. This is especially a problem on Windows where
1141 * the permitted depth of the runtime stack is rather small.
1143 * The following is a protection against author incompetence--not against
1144 * malice. There are other ways to make the DOM deep anyway.
1146 * The basic idea is that when the tree builder stack gets too deep,
1147 * append operations no longer append to the node that the HTML parsing
1148 * algorithm says they should but instead text nodes are append to the last
1149 * element that was seen before a magic tree builder stack threshold was
1150 * reached and element and comment nodes aren't appended to the DOM at all.
1152 * However, for security reasons, non-child descendant text nodes inside an
1153 * SVG script or style element should not become children. Also, non-cell
1154 * table elements shouldn't be used as surrogate parents for user experience
1157 if (aNamespace
!= kNameSpaceID_XHTML
) {
1160 if (aName
== nsGkAtoms::body
|| aName
== nsGkAtoms::frameset
) {
1162 // InnerHTML and DOMParser shouldn't start layout anyway
1165 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1166 if (MOZ_UNLIKELY(!treeOp
)) {
1167 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1170 treeOp
->Init(mozilla::AsVariant(opStartLayout()));
1173 if (nsIContent::RequiresDoneCreatingElement(kNameSpaceID_XHTML
, aName
)) {
1175 nsHtml5TreeOperation::DoneCreatingElement(
1176 static_cast<nsIContent
*>(aElement
));
1178 opDoneCreatingElement
operation(aElement
);
1179 mOpQueue
.AppendElement()->Init(mozilla::AsVariant(operation
));
1183 if (mGenerateSpeculativeLoads
&& aName
== nsGkAtoms::picture
) {
1184 // See comments in nsHtml5SpeculativeLoad.h about <picture> preloading
1185 mSpeculativeLoadQueue
.AppendElement()->InitOpenPicture();
1188 if (aName
== nsGkAtoms::_template
) {
1189 if (tokenizer
->TemplatePushedOrHeadPopped()) {
1190 requestSuspension();
1195 void nsHtml5TreeBuilder::elementPopped(int32_t aNamespace
, nsAtom
* aName
,
1196 nsIContentHandle
* aElement
) {
1197 NS_ASSERTION(aNamespace
== kNameSpaceID_XHTML
||
1198 aNamespace
== kNameSpaceID_SVG
||
1199 aNamespace
== kNameSpaceID_MathML
,
1200 "Element isn't HTML, SVG or MathML!");
1201 NS_ASSERTION(aName
, "Element doesn't have local name!");
1202 NS_ASSERTION(aElement
, "No element!");
1203 if (aNamespace
== kNameSpaceID_MathML
) {
1206 // we now have only SVG and HTML
1207 if (aName
== nsGkAtoms::script
) {
1208 if (mPreventScriptExecution
) {
1210 nsHtml5TreeOperation::PreventScriptExecution(
1211 static_cast<nsIContent
*>(aElement
));
1214 opPreventScriptExecution
operation(aElement
);
1215 mOpQueue
.AppendElement()->Init(mozilla::AsVariant(operation
));
1221 if (mCurrentHtmlScriptCannotDocumentWriteOrBlock
) {
1222 NS_ASSERTION(aNamespace
== kNameSpaceID_XHTML
,
1223 "Only HTML scripts may be async/defer.");
1224 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1225 if (MOZ_UNLIKELY(!treeOp
)) {
1226 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1229 opRunScriptThatCannotDocumentWriteOrBlock
operation(aElement
);
1230 treeOp
->Init(mozilla::AsVariant(operation
));
1231 mCurrentHtmlScriptCannotDocumentWriteOrBlock
= false;
1234 requestSuspension();
1235 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1236 if (MOZ_UNLIKELY(!treeOp
)) {
1237 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1240 opRunScriptThatMayDocumentWriteOrBlock
operation(aElement
, nullptr);
1241 treeOp
->Init(mozilla::AsVariant(operation
));
1244 // Some nodes need DoneAddingChildren() called to initialize
1245 // properly (e.g. form state restoration).
1246 if (nsIContent::RequiresDoneAddingChildren(aNamespace
, aName
)) {
1248 nsHtml5TreeOperation::DoneAddingChildren(
1249 static_cast<nsIContent
*>(aElement
));
1252 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1253 if (MOZ_UNLIKELY(!treeOp
)) {
1254 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1257 opDoneAddingChildren
operation(aElement
);
1258 treeOp
->Init(mozilla::AsVariant(operation
));
1259 if (aNamespace
== kNameSpaceID_XHTML
&& aName
== nsGkAtoms::head
) {
1260 if (tokenizer
->TemplatePushedOrHeadPopped()) {
1261 requestSuspension();
1266 if (aName
== nsGkAtoms::style
||
1267 (aNamespace
== kNameSpaceID_XHTML
&& aName
== nsGkAtoms::link
)) {
1269 MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(),
1270 "Scripts must be blocked.");
1271 mBuilder
->UpdateStyleSheet(static_cast<nsIContent
*>(aElement
));
1275 if (aName
== nsGkAtoms::style
) {
1276 nsTArray
<nsString
> imports
= mImportScanner
.Stop();
1277 for (nsString
& url
: imports
) {
1278 mSpeculativeLoadQueue
.AppendElement()->InitImportStyle(std::move(url
));
1282 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1283 if (MOZ_UNLIKELY(!treeOp
)) {
1284 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1287 opUpdateStyleSheet
operation(aElement
);
1288 treeOp
->Init(mozilla::AsVariant(operation
));
1291 if (aNamespace
== kNameSpaceID_SVG
) {
1292 if (aName
== nsGkAtoms::svg
) {
1293 if (!scriptingEnabled
|| mPreventScriptExecution
) {
1297 nsHtml5TreeOperation::SvgLoad(static_cast<nsIContent
*>(aElement
));
1300 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1301 if (MOZ_UNLIKELY(!treeOp
)) {
1302 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1305 opSvgLoad
operation(aElement
);
1306 treeOp
->Init(mozilla::AsVariant(operation
));
1311 if (mGenerateSpeculativeLoads
&& aName
== nsGkAtoms::picture
) {
1312 // See comments in nsHtml5SpeculativeLoad.h about <picture> preloading
1313 mSpeculativeLoadQueue
.AppendElement()->InitEndPicture();
1318 void nsHtml5TreeBuilder::accumulateCharacters(const char16_t
* aBuf
,
1319 int32_t aStart
, int32_t aLength
) {
1320 MOZ_RELEASE_ASSERT(charBufferLen
+ aLength
<= charBuffer
.length
,
1321 "About to memcpy past the end of the buffer!");
1322 memcpy(charBuffer
+ charBufferLen
, aBuf
+ aStart
, sizeof(char16_t
) * aLength
);
1323 charBufferLen
+= aLength
;
1326 // INT32_MAX is (2^31)-1. Therefore, the highest power-of-two that fits
1327 // is 2^30. Note that this is counting char16_t units. The underlying
1328 // bytes will be twice that, but they fit even in 32-bit size_t even
1329 // if a contiguous chunk of memory of that size is pretty unlikely to
1330 // be available on a 32-bit system.
1331 #define MAX_POWER_OF_TWO_IN_INT32 0x40000000
1333 bool nsHtml5TreeBuilder::EnsureBufferSpace(int32_t aLength
) {
1334 // TODO: Unify nsHtml5Tokenizer::strBuf and nsHtml5TreeBuilder::charBuffer
1335 // so that this method becomes unnecessary.
1336 mozilla::CheckedInt
<int32_t> worstCase(charBufferLen
);
1337 worstCase
+= aLength
;
1338 if (!worstCase
.isValid()) {
1341 if (worstCase
.value() > MAX_POWER_OF_TWO_IN_INT32
) {
1345 if (worstCase
.value() < MAX_POWER_OF_TWO_IN_INT32
) {
1346 // Add one to round to the next power of two to avoid immediate
1347 // reallocation once there are a few characters in the buffer.
1350 charBuffer
= jArray
<char16_t
, int32_t>::newFallibleJArray(
1351 mozilla::RoundUpPow2(worstCase
.value()));
1355 } else if (worstCase
.value() > charBuffer
.length
) {
1356 jArray
<char16_t
, int32_t> newBuf
=
1357 jArray
<char16_t
, int32_t>::newFallibleJArray(
1358 mozilla::RoundUpPow2(worstCase
.value()));
1362 memcpy(newBuf
, charBuffer
, sizeof(char16_t
) * size_t(charBufferLen
));
1363 charBuffer
= newBuf
;
1368 nsIContentHandle
* nsHtml5TreeBuilder::AllocateContentHandle() {
1369 if (MOZ_UNLIKELY(mBuilder
)) {
1370 MOZ_ASSERT_UNREACHABLE("Must never allocate a handle with builder.");
1373 if (mHandlesUsed
== NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH
) {
1374 mOldHandles
.AppendElement(std::move(mHandles
));
1375 mHandles
= mozilla::MakeUnique
<nsIContent
*[]>(
1376 NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH
);
1380 mHandles
[mHandlesUsed
] = reinterpret_cast<nsIContent
*>(uintptr_t(0xC0DEDBAD));
1382 return &mHandles
[mHandlesUsed
++];
1385 bool nsHtml5TreeBuilder::HasScriptThatMayDocumentWriteOrBlock() {
1386 uint32_t len
= mOpQueue
.Length();
1390 return mOpQueue
.ElementAt(len
- 1).IsRunScriptThatMayDocumentWriteOrBlock();
1393 mozilla::Result
<bool, nsresult
> nsHtml5TreeBuilder::Flush(bool aDiscretionary
) {
1394 if (MOZ_UNLIKELY(mBuilder
)) {
1395 MOZ_ASSERT_UNREACHABLE("Must never flush with builder.");
1398 if (NS_SUCCEEDED(mBroken
)) {
1399 if (!aDiscretionary
|| !(charBufferLen
&& currentPtr
>= 0 &&
1400 stack
[currentPtr
]->isFosterParenting())) {
1401 // Don't flush text on discretionary flushes if the current element on
1402 // the stack is a foster-parenting element and there's pending text,
1403 // because flushing in that case would make the tree shape dependent on
1404 // where the flush points fall.
1410 bool hasOps
= !mOpQueue
.IsEmpty();
1412 // If the builder is broken and mOpQueue is not empty, there must be
1413 // one op and it must be eTreeOpMarkAsBroken.
1414 if (NS_FAILED(mBroken
)) {
1415 MOZ_ASSERT(mOpQueue
.Length() == 1,
1416 "Tree builder is broken with a non-empty op queue whose "
1418 MOZ_ASSERT(mOpQueue
[0].IsMarkAsBroken(),
1419 "Tree builder is broken but the op in queue is not marked "
1422 if (!mOpSink
->MoveOpsFrom(mOpQueue
)) {
1423 return mozilla::Err(NS_ERROR_OUT_OF_MEMORY
);
1428 // no op sink: throw away ops
1433 void nsHtml5TreeBuilder::FlushLoads() {
1434 if (MOZ_UNLIKELY(mBuilder
)) {
1435 MOZ_ASSERT_UNREACHABLE("Must never flush loads with builder.");
1438 if (!mSpeculativeLoadQueue
.IsEmpty()) {
1439 mSpeculativeLoadStage
->MoveSpeculativeLoadsFrom(mSpeculativeLoadQueue
);
1443 void nsHtml5TreeBuilder::SetDocumentCharset(NotNull
<const Encoding
*> aEncoding
,
1444 nsCharsetSource aCharsetSource
,
1445 bool aCommitEncodingSpeculation
) {
1446 MOZ_ASSERT(!mBuilder
, "How did we call this with builder?");
1447 MOZ_ASSERT(mSpeculativeLoadStage
,
1448 "How did we call this without a speculative load stage?");
1449 mSpeculativeLoadQueue
.AppendElement()->InitSetDocumentCharset(
1450 aEncoding
, aCharsetSource
, aCommitEncodingSpeculation
);
1453 void nsHtml5TreeBuilder::UpdateCharsetSource(nsCharsetSource aCharsetSource
) {
1454 MOZ_ASSERT(!mBuilder
, "How did we call this with builder?");
1455 MOZ_ASSERT(mSpeculativeLoadStage
,
1456 "How did we call this without a speculative load stage (even "
1457 "though we don't need it right here)?");
1459 mViewSource
->UpdateCharsetSource(aCharsetSource
);
1462 opUpdateCharsetSource
operation(aCharsetSource
);
1463 mOpQueue
.AppendElement()->Init(mozilla::AsVariant(operation
));
1466 void nsHtml5TreeBuilder::StreamEnded() {
1467 MOZ_ASSERT(!mBuilder
, "Must not call StreamEnded with builder.");
1468 MOZ_ASSERT(!fragment
, "Must not parse fragments off the main thread.");
1469 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1470 if (MOZ_UNLIKELY(!treeOp
)) {
1471 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1474 treeOp
->Init(mozilla::AsVariant(opStreamEnded()));
1477 void nsHtml5TreeBuilder::NeedsCharsetSwitchTo(
1478 NotNull
<const Encoding
*> aEncoding
, int32_t aCharsetSource
,
1479 int32_t aLineNumber
) {
1480 if (MOZ_UNLIKELY(mBuilder
)) {
1481 MOZ_ASSERT_UNREACHABLE("Must never switch charset with builder.");
1484 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1485 if (MOZ_UNLIKELY(!treeOp
)) {
1486 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1489 opCharsetSwitchTo
opeation(aEncoding
, aCharsetSource
, aLineNumber
);
1490 treeOp
->Init(mozilla::AsVariant(opeation
));
1493 void nsHtml5TreeBuilder::MaybeComplainAboutCharset(const char* aMsgId
,
1495 int32_t aLineNumber
) {
1496 if (MOZ_UNLIKELY(mBuilder
)) {
1497 MOZ_ASSERT_UNREACHABLE("Must never complain about charset with builder.");
1501 if (mSpeculativeLoadStage
) {
1502 mSpeculativeLoadQueue
.AppendElement()->InitMaybeComplainAboutCharset(
1503 aMsgId
, aError
, aLineNumber
);
1505 opMaybeComplainAboutCharset
opeartion(const_cast<char*>(aMsgId
), aError
,
1507 mOpQueue
.AppendElement()->Init(mozilla::AsVariant(opeartion
));
1511 void nsHtml5TreeBuilder::TryToEnableEncodingMenu() {
1512 if (MOZ_UNLIKELY(mBuilder
)) {
1513 MOZ_ASSERT_UNREACHABLE("Must never disable encoding menu with builder.");
1516 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
1517 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
1518 treeOp
->Init(mozilla::AsVariant(opEnableEncodingMenu()));
1521 void nsHtml5TreeBuilder::AddSnapshotToScript(
1522 nsAHtml5TreeBuilderState
* aSnapshot
, int32_t aLine
) {
1523 if (MOZ_UNLIKELY(mBuilder
)) {
1524 MOZ_ASSERT_UNREACHABLE("Must never use snapshots with builder.");
1527 MOZ_ASSERT(HasScriptThatMayDocumentWriteOrBlock(),
1528 "No script to add a snapshot to!");
1529 MOZ_ASSERT(aSnapshot
, "Got null snapshot.");
1530 mOpQueue
.ElementAt(mOpQueue
.Length() - 1).SetSnapshot(aSnapshot
, aLine
);
1533 void nsHtml5TreeBuilder::DropHandles() {
1534 MOZ_ASSERT(!mBuilder
, "Must not drop handles with builder.");
1535 mOldHandles
.Clear();
1539 void nsHtml5TreeBuilder::MarkAsBroken(nsresult aRv
) {
1540 if (MOZ_UNLIKELY(mBuilder
)) {
1541 MOZ_ASSERT_UNREACHABLE("Must not call this with builder.");
1545 mOpQueue
.Clear(); // Previous ops don't matter anymore
1546 opMarkAsBroken
operation(aRv
);
1547 mOpQueue
.AppendElement()->Init(mozilla::AsVariant(operation
));
1550 void nsHtml5TreeBuilder::MarkAsBrokenFromPortability(nsresult aRv
) {
1552 MarkAsBrokenAndRequestSuspensionWithBuilder(aRv
);
1556 requestSuspension();
1559 void nsHtml5TreeBuilder::StartPlainTextViewSource(const nsAutoString
& aTitle
) {
1560 MOZ_ASSERT(!mBuilder
, "Must not view source with builder.");
1562 startTag(nsHtml5ElementName::ELT_META
,
1563 nsHtml5ViewSourceUtils::NewMetaViewportAttributes(), false);
1565 startTag(nsHtml5ElementName::ELT_TITLE
,
1566 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES
, false);
1568 // XUL will add the "Source of: " prefix.
1569 uint32_t length
= aTitle
.Length();
1570 if (length
> INT32_MAX
) {
1573 characters(aTitle
.get(), 0, (int32_t)length
);
1574 endTag(nsHtml5ElementName::ELT_TITLE
);
1576 startTag(nsHtml5ElementName::ELT_LINK
,
1577 nsHtml5ViewSourceUtils::NewLinkAttributes(), false);
1579 startTag(nsHtml5ElementName::ELT_BODY
,
1580 nsHtml5ViewSourceUtils::NewBodyAttributes(), false);
1582 StartPlainTextBody();
1585 void nsHtml5TreeBuilder::StartPlainText() {
1586 MOZ_ASSERT(!mBuilder
, "Must not view source with builder.");
1587 setForceNoQuirks(true);
1588 startTag(nsHtml5ElementName::ELT_LINK
,
1589 nsHtml5PlainTextUtils::NewLinkAttributes(), false);
1591 startTag(nsHtml5ElementName::ELT_BODY
,
1592 nsHtml5PlainTextUtils::NewBodyAttributes(), false);
1594 StartPlainTextBody();
1597 void nsHtml5TreeBuilder::StartPlainTextBody() {
1598 MOZ_ASSERT(!mBuilder
, "Must not view source with builder.");
1599 startTag(nsHtml5ElementName::ELT_PRE
, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES
,
1601 needToDropLF
= false;
1604 // DocumentModeHandler
1605 void nsHtml5TreeBuilder::documentMode(nsHtml5DocumentMode m
) {
1607 mBuilder
->SetDocumentMode(m
);
1610 if (mSpeculativeLoadStage
) {
1611 mSpeculativeLoadQueue
.AppendElement()->InitSetDocumentMode(m
);
1614 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1615 if (MOZ_UNLIKELY(!treeOp
)) {
1616 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1619 treeOp
->Init(mozilla::AsVariant(m
));
1622 nsIContentHandle
* nsHtml5TreeBuilder::getDocumentFragmentForTemplate(
1623 nsIContentHandle
* aTemplate
) {
1625 return nsHtml5TreeOperation::GetDocumentFragmentForTemplate(
1626 static_cast<nsIContent
*>(aTemplate
));
1628 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement(mozilla::fallible
);
1629 if (MOZ_UNLIKELY(!treeOp
)) {
1630 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY
);
1633 nsIContentHandle
* fragHandle
= AllocateContentHandle();
1634 opGetDocumentFragmentForTemplate
operation(aTemplate
, fragHandle
);
1635 treeOp
->Init(mozilla::AsVariant(operation
));
1639 nsIContentHandle
* nsHtml5TreeBuilder::getFormPointerForContext(
1640 nsIContentHandle
* aContext
) {
1641 MOZ_ASSERT(mBuilder
, "Must have builder.");
1646 MOZ_ASSERT(NS_IsMainThread());
1648 // aContext must always be an element that already exists
1650 nsIContent
* contextNode
= static_cast<nsIContent
*>(aContext
);
1651 nsIContent
* currentAncestor
= contextNode
;
1653 // We traverse the ancestors of the context node to find the nearest
1654 // form pointer. This traversal is why aContext must not be an emtpy handle.
1655 nsIContent
* nearestForm
= nullptr;
1656 while (currentAncestor
) {
1657 if (currentAncestor
->IsHTMLElement(nsGkAtoms::form
)) {
1658 nearestForm
= currentAncestor
;
1661 currentAncestor
= currentAncestor
->GetParent();
1673 void nsHtml5TreeBuilder::EnableViewSource(nsHtml5Highlighter
* aHighlighter
) {
1674 MOZ_ASSERT(!mBuilder
, "Must not view source with builder.");
1675 mViewSource
= aHighlighter
;
1678 void nsHtml5TreeBuilder::errDeepTree() {
1679 if (MOZ_UNLIKELY(mViewSource
)) {
1680 mViewSource
->AddErrorToCurrentRun("errDeepTree");
1681 } else if (!mBuilder
) {
1682 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
1683 MOZ_ASSERT(treeOp
, "Tree op allocation failed.");
1684 opMaybeComplainAboutDeepTree
operation(tokenizer
->getLineNumber());
1685 treeOp
->Init(mozilla::AsVariant(operation
));
1689 void nsHtml5TreeBuilder::errStrayStartTag(nsAtom
* aName
) {
1690 if (MOZ_UNLIKELY(mViewSource
)) {
1691 mViewSource
->AddErrorToCurrentRun("errStrayStartTag2", aName
);
1695 void nsHtml5TreeBuilder::errStrayEndTag(nsAtom
* aName
) {
1696 if (MOZ_UNLIKELY(mViewSource
)) {
1697 mViewSource
->AddErrorToCurrentRun("errStrayEndTag", aName
);
1701 void nsHtml5TreeBuilder::errUnclosedElements(int32_t aIndex
, nsAtom
* aName
) {
1702 if (MOZ_UNLIKELY(mViewSource
)) {
1703 mViewSource
->AddErrorToCurrentRun("errUnclosedElements", aName
);
1707 void nsHtml5TreeBuilder::errUnclosedElementsImplied(int32_t aIndex
,
1709 if (MOZ_UNLIKELY(mViewSource
)) {
1710 mViewSource
->AddErrorToCurrentRun("errUnclosedElementsImplied", aName
);
1714 void nsHtml5TreeBuilder::errUnclosedElementsCell(int32_t aIndex
) {
1715 if (MOZ_UNLIKELY(mViewSource
)) {
1716 mViewSource
->AddErrorToCurrentRun("errUnclosedElementsCell");
1720 void nsHtml5TreeBuilder::errStrayDoctype() {
1721 if (MOZ_UNLIKELY(mViewSource
)) {
1722 mViewSource
->AddErrorToCurrentRun("errStrayDoctype");
1726 void nsHtml5TreeBuilder::errAlmostStandardsDoctype() {
1727 if (MOZ_UNLIKELY(mViewSource
) && !forceNoQuirks
) {
1728 mViewSource
->AddErrorToCurrentRun("errAlmostStandardsDoctype");
1732 void nsHtml5TreeBuilder::errQuirkyDoctype() {
1733 if (MOZ_UNLIKELY(mViewSource
) && !forceNoQuirks
) {
1734 mViewSource
->AddErrorToCurrentRun("errQuirkyDoctype");
1738 void nsHtml5TreeBuilder::errNonSpaceInTrailer() {
1739 if (MOZ_UNLIKELY(mViewSource
)) {
1740 mViewSource
->AddErrorToCurrentRun("errNonSpaceInTrailer");
1744 void nsHtml5TreeBuilder::errNonSpaceAfterFrameset() {
1745 if (MOZ_UNLIKELY(mViewSource
)) {
1746 mViewSource
->AddErrorToCurrentRun("errNonSpaceAfterFrameset");
1750 void nsHtml5TreeBuilder::errNonSpaceInFrameset() {
1751 if (MOZ_UNLIKELY(mViewSource
)) {
1752 mViewSource
->AddErrorToCurrentRun("errNonSpaceInFrameset");
1756 void nsHtml5TreeBuilder::errNonSpaceAfterBody() {
1757 if (MOZ_UNLIKELY(mViewSource
)) {
1758 mViewSource
->AddErrorToCurrentRun("errNonSpaceAfterBody");
1762 void nsHtml5TreeBuilder::errNonSpaceInColgroupInFragment() {
1763 if (MOZ_UNLIKELY(mViewSource
)) {
1764 mViewSource
->AddErrorToCurrentRun("errNonSpaceInColgroupInFragment");
1768 void nsHtml5TreeBuilder::errNonSpaceInNoscriptInHead() {
1769 if (MOZ_UNLIKELY(mViewSource
)) {
1770 mViewSource
->AddErrorToCurrentRun("errNonSpaceInNoscriptInHead");
1774 void nsHtml5TreeBuilder::errFooBetweenHeadAndBody(nsAtom
* aName
) {
1775 if (MOZ_UNLIKELY(mViewSource
)) {
1776 mViewSource
->AddErrorToCurrentRun("errFooBetweenHeadAndBody", aName
);
1780 void nsHtml5TreeBuilder::errStartTagWithoutDoctype() {
1781 if (MOZ_UNLIKELY(mViewSource
) && !forceNoQuirks
) {
1782 mViewSource
->AddErrorToCurrentRun("errStartTagWithoutDoctype");
1786 void nsHtml5TreeBuilder::errNoSelectInTableScope() {
1787 if (MOZ_UNLIKELY(mViewSource
)) {
1788 mViewSource
->AddErrorToCurrentRun("errNoSelectInTableScope");
1792 void nsHtml5TreeBuilder::errStartSelectWhereEndSelectExpected() {
1793 if (MOZ_UNLIKELY(mViewSource
)) {
1794 mViewSource
->AddErrorToCurrentRun("errStartSelectWhereEndSelectExpected");
1798 void nsHtml5TreeBuilder::errStartTagWithSelectOpen(nsAtom
* aName
) {
1799 if (MOZ_UNLIKELY(mViewSource
)) {
1800 mViewSource
->AddErrorToCurrentRun("errStartTagWithSelectOpen", aName
);
1804 void nsHtml5TreeBuilder::errBadStartTagInNoscriptInHead(nsAtom
* aName
) {
1805 if (MOZ_UNLIKELY(mViewSource
)) {
1806 mViewSource
->AddErrorToCurrentRun("errBadStartTagInNoscriptInHead", aName
);
1810 void nsHtml5TreeBuilder::errImage() {
1811 if (MOZ_UNLIKELY(mViewSource
)) {
1812 mViewSource
->AddErrorToCurrentRun("errImage");
1816 void nsHtml5TreeBuilder::errIsindex() {
1817 if (MOZ_UNLIKELY(mViewSource
)) {
1818 mViewSource
->AddErrorToCurrentRun("errIsindex");
1822 void nsHtml5TreeBuilder::errFooSeenWhenFooOpen(nsAtom
* aName
) {
1823 if (MOZ_UNLIKELY(mViewSource
)) {
1824 mViewSource
->AddErrorToCurrentRun("errFooSeenWhenFooOpen2", aName
);
1828 void nsHtml5TreeBuilder::errHeadingWhenHeadingOpen() {
1829 if (MOZ_UNLIKELY(mViewSource
)) {
1830 mViewSource
->AddErrorToCurrentRun("errHeadingWhenHeadingOpen");
1834 void nsHtml5TreeBuilder::errFramesetStart() {
1835 if (MOZ_UNLIKELY(mViewSource
)) {
1836 mViewSource
->AddErrorToCurrentRun("errFramesetStart");
1840 void nsHtml5TreeBuilder::errNoCellToClose() {
1841 if (MOZ_UNLIKELY(mViewSource
)) {
1842 mViewSource
->AddErrorToCurrentRun("errNoCellToClose");
1846 void nsHtml5TreeBuilder::errStartTagInTable(nsAtom
* aName
) {
1847 if (MOZ_UNLIKELY(mViewSource
)) {
1848 mViewSource
->AddErrorToCurrentRun("errStartTagInTable", aName
);
1852 void nsHtml5TreeBuilder::errFormWhenFormOpen() {
1853 if (MOZ_UNLIKELY(mViewSource
)) {
1854 mViewSource
->AddErrorToCurrentRun("errFormWhenFormOpen");
1858 void nsHtml5TreeBuilder::errTableSeenWhileTableOpen() {
1859 if (MOZ_UNLIKELY(mViewSource
)) {
1860 mViewSource
->AddErrorToCurrentRun("errTableSeenWhileTableOpen");
1864 void nsHtml5TreeBuilder::errStartTagInTableBody(nsAtom
* aName
) {
1865 if (MOZ_UNLIKELY(mViewSource
)) {
1866 mViewSource
->AddErrorToCurrentRun("errStartTagInTableBody", aName
);
1870 void nsHtml5TreeBuilder::errEndTagSeenWithoutDoctype() {
1871 if (MOZ_UNLIKELY(mViewSource
) && !forceNoQuirks
) {
1872 mViewSource
->AddErrorToCurrentRun("errEndTagSeenWithoutDoctype");
1876 void nsHtml5TreeBuilder::errEndTagAfterBody() {
1877 if (MOZ_UNLIKELY(mViewSource
)) {
1878 mViewSource
->AddErrorToCurrentRun("errEndTagAfterBody");
1882 void nsHtml5TreeBuilder::errEndTagSeenWithSelectOpen(nsAtom
* aName
) {
1883 if (MOZ_UNLIKELY(mViewSource
)) {
1884 mViewSource
->AddErrorToCurrentRun("errEndTagSeenWithSelectOpen", aName
);
1888 void nsHtml5TreeBuilder::errGarbageInColgroup() {
1889 if (MOZ_UNLIKELY(mViewSource
)) {
1890 mViewSource
->AddErrorToCurrentRun("errGarbageInColgroup");
1894 void nsHtml5TreeBuilder::errEndTagBr() {
1895 if (MOZ_UNLIKELY(mViewSource
)) {
1896 mViewSource
->AddErrorToCurrentRun("errEndTagBr");
1900 void nsHtml5TreeBuilder::errNoElementToCloseButEndTagSeen(nsAtom
* aName
) {
1901 if (MOZ_UNLIKELY(mViewSource
)) {
1902 mViewSource
->AddErrorToCurrentRun("errNoElementToCloseButEndTagSeen",
1907 void nsHtml5TreeBuilder::errHtmlStartTagInForeignContext(nsAtom
* aName
) {
1908 if (MOZ_UNLIKELY(mViewSource
)) {
1909 mViewSource
->AddErrorToCurrentRun("errHtmlStartTagInForeignContext", aName
);
1913 void nsHtml5TreeBuilder::errNoTableRowToClose() {
1914 if (MOZ_UNLIKELY(mViewSource
)) {
1915 mViewSource
->AddErrorToCurrentRun("errNoTableRowToClose");
1919 void nsHtml5TreeBuilder::errNonSpaceInTable() {
1920 if (MOZ_UNLIKELY(mViewSource
)) {
1921 mViewSource
->AddErrorToCurrentRun("errNonSpaceInTable");
1925 void nsHtml5TreeBuilder::errUnclosedChildrenInRuby() {
1926 if (MOZ_UNLIKELY(mViewSource
)) {
1927 mViewSource
->AddErrorToCurrentRun("errUnclosedChildrenInRuby");
1931 void nsHtml5TreeBuilder::errStartTagSeenWithoutRuby(nsAtom
* aName
) {
1932 if (MOZ_UNLIKELY(mViewSource
)) {
1933 mViewSource
->AddErrorToCurrentRun("errStartTagSeenWithoutRuby", aName
);
1937 void nsHtml5TreeBuilder::errSelfClosing() {
1938 if (MOZ_UNLIKELY(mViewSource
)) {
1939 mViewSource
->AddErrorToCurrentSlash("errSelfClosing");
1943 void nsHtml5TreeBuilder::errNoCheckUnclosedElementsOnStack() {
1944 if (MOZ_UNLIKELY(mViewSource
)) {
1945 mViewSource
->AddErrorToCurrentRun("errNoCheckUnclosedElementsOnStack");
1949 void nsHtml5TreeBuilder::errEndTagDidNotMatchCurrentOpenElement(
1950 nsAtom
* aName
, nsAtom
* aOther
) {
1951 if (MOZ_UNLIKELY(mViewSource
)) {
1952 mViewSource
->AddErrorToCurrentRun("errEndTagDidNotMatchCurrentOpenElement",
1957 void nsHtml5TreeBuilder::errEndTagViolatesNestingRules(nsAtom
* aName
) {
1958 if (MOZ_UNLIKELY(mViewSource
)) {
1959 mViewSource
->AddErrorToCurrentRun("errEndTagViolatesNestingRules", aName
);
1963 void nsHtml5TreeBuilder::errEndWithUnclosedElements(nsAtom
* aName
) {
1964 if (MOZ_UNLIKELY(mViewSource
)) {
1965 mViewSource
->AddErrorToCurrentRun("errEndWithUnclosedElements", aName
);
1969 void nsHtml5TreeBuilder::errListUnclosedStartTags(int32_t aIgnored
) {
1970 if (MOZ_UNLIKELY(mViewSource
)) {
1971 mViewSource
->AddErrorToCurrentRun("errListUnclosedStartTags");