Bug 1728955: part 3) Add logging to `nsBaseClipboard`. r=masayuki
[gecko.git] / parser / html / nsHtml5TreeBuilderCppSupplement.h
blob77349642ef781b44045c776bb2710d6e84bf042b
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/. */
7 #include "nsError.h"
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)
15 : mode(0),
16 originalMode(0),
17 framesetOk(false),
18 tokenizer(nullptr),
19 scriptingEnabled(false),
20 needToDropLF(false),
21 fragment(false),
22 contextName(nullptr),
23 contextNamespace(kNameSpaceID_None),
24 contextNode(nullptr),
25 templateModePtr(0),
26 stackNodesIdx(0),
27 numStackNodes(0),
28 currentPtr(0),
29 listPtr(0),
30 formPointer(nullptr),
31 headPointer(nullptr),
32 charBufferLen(0),
33 quirks(false),
34 isSrcdocDocument(false),
35 mBuilder(aBuilder),
36 mViewSource(nullptr),
37 mOpSink(nullptr),
38 mHandles(nullptr),
39 mHandlesUsed(0),
40 mSpeculativeLoadStage(nullptr),
41 mBroken(NS_OK),
42 mCurrentHtmlScriptIsAsyncOrDefer(false),
43 mPreventScriptExecution(false)
44 #ifdef DEBUG
46 mActive(false)
47 #endif
49 MOZ_COUNT_CTOR(nsHtml5TreeBuilder);
52 nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsAHtml5TreeOpSink* aOpSink,
53 nsHtml5TreeOpStage* aStage)
54 : mode(0),
55 originalMode(0),
56 framesetOk(false),
57 tokenizer(nullptr),
58 scriptingEnabled(false),
59 needToDropLF(false),
60 fragment(false),
61 contextName(nullptr),
62 contextNamespace(kNameSpaceID_None),
63 contextNode(nullptr),
64 templateModePtr(0),
65 stackNodesIdx(0),
66 numStackNodes(0),
67 currentPtr(0),
68 listPtr(0),
69 formPointer(nullptr),
70 headPointer(nullptr),
71 charBufferLen(0),
72 quirks(false),
73 isSrcdocDocument(false),
74 mBuilder(nullptr),
75 mViewSource(nullptr),
76 mOpSink(aOpSink),
77 mHandles(new nsIContent*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH]),
78 mHandlesUsed(0),
79 mSpeculativeLoadStage(aStage),
80 mBroken(NS_OK),
81 mCurrentHtmlScriptIsAsyncOrDefer(false),
82 mPreventScriptExecution(false)
83 #ifdef DEBUG
85 mActive(false)
86 #endif
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!");
95 mOpQueue.Clear();
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,
106 "Bogus namespace.");
108 if (mBuilder) {
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();
118 nsIContent* elem;
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);
127 } else {
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)) {
134 delete aAttributes;
136 return elem;
139 nsIContentHandle* content = AllocateContentHandle();
140 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
141 if (MOZ_UNLIKELY(!treeOp)) {
142 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
143 return nullptr;
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));
158 } else {
159 // kNameSpaceID_MathML
160 opCreateMathMLElement operation(content, aName, aAttributes,
161 aIntendedParent);
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")) {
178 nsHtml5String url =
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
198 if (srcset) {
199 nsHtml5String sizes =
200 aAttributes->getValue(nsHtml5AttributeName::ATTR_SIZES);
201 nsHtml5String type =
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);
214 return nullptr;
216 opSetScriptLineNumberAndFreeze operation(content,
217 tokenizer->getLineNumber());
218 treeOp->Init(mozilla::AsVariant(operation));
220 nsHtml5String url =
221 aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC);
222 if (url) {
223 nsHtml5String charset =
224 aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
225 nsHtml5String type =
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);
233 bool async =
234 aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC);
235 bool defer =
236 aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER);
237 bool noModule =
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) {
246 nsHtml5String rel =
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.
250 if (rel) {
251 if (rel.LowerCaseEqualsASCII("stylesheet")) {
252 nsHtml5String url =
253 aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
254 if (url) {
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,
267 false);
269 } else if (rel.LowerCaseEqualsASCII("preconnect")) {
270 nsHtml5String url =
271 aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
272 if (url) {
273 nsHtml5String crossOrigin = aAttributes->getValue(
274 nsHtml5AttributeName::ATTR_CROSSORIGIN);
275 mSpeculativeLoadQueue.AppendElement()->InitPreconnect(
276 url, crossOrigin);
278 } else if (StaticPrefs::network_preload() &&
279 rel.LowerCaseEqualsASCII("preload")) {
280 nsHtml5String url =
281 aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
282 if (url) {
283 nsHtml5String as =
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")) {
304 nsHtml5String type =
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,
313 integrity, true);
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,
321 true);
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) {
334 nsHtml5String url =
335 aAttributes->getValue(nsHtml5AttributeName::ATTR_POSTER);
336 if (url) {
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);
347 return nullptr;
349 opSetStyleLineNumber operation(content, tokenizer->getLineNumber());
350 treeOp->Init(mozilla::AsVariant(operation));
351 } else if (nsGkAtoms::html == aName) {
352 nsHtml5String url =
353 aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST);
354 mSpeculativeLoadQueue.AppendElement()->InitManifest(url);
355 } else if (nsGkAtoms::base == aName) {
356 nsHtml5String url =
357 aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
358 if (url) {
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))) {
366 nsHtml5String csp =
367 aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
368 if (csp) {
369 mSpeculativeLoadQueue.AppendElement()->InitMetaCSP(csp);
371 } else if (nsHtml5Portability::
372 lowerCaseLiteralEqualsIgnoreAsciiCaseString(
373 "referrer",
374 aAttributes->getValue(
375 nsHtml5AttributeName::ATTR_NAME))) {
376 nsHtml5String referrerPolicy =
377 aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
378 if (referrerPolicy) {
379 mSpeculativeLoadQueue.AppendElement()->InitMetaReferrerPolicy(
380 referrerPolicy);
384 break;
385 case kNameSpaceID_SVG:
386 if (nsGkAtoms::image == aName) {
387 nsHtml5String url =
388 aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
389 if (!url) {
390 url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
392 if (url) {
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);
402 return nullptr;
404 opSetScriptLineNumberAndFreeze operation(content,
405 tokenizer->getLineNumber());
406 treeOp->Init(mozilla::AsVariant(operation));
408 nsHtml5String url =
409 aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
410 if (!url) {
411 url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
413 if (url) {
414 nsHtml5String type =
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);
434 return nullptr;
436 opSetStyleLineNumber operation(content, tokenizer->getLineNumber());
437 treeOp->Init(mozilla::AsVariant(operation));
439 break;
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);
447 return nullptr;
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);
455 return nullptr;
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) {
468 nsHtml5String url =
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);
475 return nullptr;
477 if (url) {
478 nsString
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));
483 } else {
484 opProcessOfflineManifest operation(ToNewUnicode(u""_ns));
485 treeOp->Init(mozilla::AsVariant(operation));
487 } else if (nsGkAtoms::base == aName && mViewSource) {
488 nsHtml5String url =
489 aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
490 if (url) {
491 mViewSource->AddBase(url);
497 // End wall of code for speculative loading
499 return content;
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);
508 if (aFormElement) {
509 if (mBuilder) {
510 nsHtml5TreeOperation::SetFormElement(
511 static_cast<nsIContent*>(content),
512 static_cast<nsIContent*>(aFormElement));
513 } else {
514 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
515 if (MOZ_UNLIKELY(!treeOp)) {
516 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
517 return nullptr;
519 opSetFormElement operation(content, aFormElement);
520 treeOp->Init(mozilla::AsVariant(operation));
523 return content;
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);
533 if (mBuilder) {
534 nsresult rv = nsHtml5TreeOperation::AppendToDocument(
535 static_cast<nsIContent*>(content), mBuilder);
536 if (NS_FAILED(rv)) {
537 MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
539 } else {
540 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
541 if (MOZ_UNLIKELY(!treeOp)) {
542 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
543 return nullptr;
545 opAppendToDocument operation(content);
546 treeOp->Init(mozilla::AsVariant(operation));
548 return content;
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");
558 if (mBuilder) {
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);
570 return child;
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);
589 return child;
592 void nsHtml5TreeBuilder::detachFromParent(nsIContentHandle* aElement) {
593 MOZ_ASSERT(aElement, "Null element");
595 if (mBuilder) {
596 nsHtml5TreeOperation::Detach(static_cast<nsIContent*>(aElement), mBuilder);
597 return;
600 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
601 if (MOZ_UNLIKELY(!treeOp)) {
602 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
603 return;
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");
614 if (mBuilder) {
615 nsresult rv = nsHtml5TreeOperation::Append(
616 static_cast<nsIContent*>(aChild), static_cast<nsIContent*>(aParent),
617 mozilla::dom::FROM_PARSER_FRAGMENT, mBuilder);
618 if (NS_FAILED(rv)) {
619 MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
621 return;
624 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
625 if (MOZ_UNLIKELY(!treeOp)) {
626 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
627 return;
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");
642 if (mBuilder) {
643 nsresult rv = nsHtml5TreeOperation::AppendChildrenToNewParent(
644 static_cast<nsIContent*>(aOldParent),
645 static_cast<nsIContent*>(aNewParent), mBuilder);
646 if (NS_FAILED(rv)) {
647 MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
649 return;
652 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
653 if (MOZ_UNLIKELY(!treeOp)) {
654 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
655 return;
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.");
669 if (mBuilder) {
670 nsresult rv = nsHtml5TreeOperation::FosterParentText(
671 static_cast<nsIContent*>(aStackParent),
672 aBuffer, // XXX aStart always ignored???
673 aLength, static_cast<nsIContent*>(aTable), mBuilder);
674 if (NS_FAILED(rv)) {
675 MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
677 return;
680 auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength);
681 if (!bufferCopy) {
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;
685 requestSuspension();
686 return;
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);
694 return;
696 opFosterParentText operation(aStackParent, bufferCopy.release(), aTable,
697 aLength);
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");
708 if (mBuilder) {
709 nsresult rv = nsHtml5TreeOperation::FosterParent(
710 static_cast<nsIContent*>(aChild),
711 static_cast<nsIContent*>(aStackParent),
712 static_cast<nsIContent*>(aTable), mBuilder);
713 if (NS_FAILED(rv)) {
714 MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
716 return;
719 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
720 if (MOZ_UNLIKELY(!treeOp)) {
721 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
722 return;
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,
730 int32_t aLength) {
731 MOZ_ASSERT(aBuffer, "Null buffer");
732 MOZ_ASSERT(aParent, "Null parent");
733 MOZ_ASSERT(!aStart, "aStart must always be zero.");
735 if (mBuilder) {
736 nsresult rv = nsHtml5TreeOperation::AppendText(
737 aBuffer, // XXX aStart always ignored???
738 aLength, static_cast<nsIContent*>(aParent), mBuilder);
739 if (NS_FAILED(rv)) {
740 MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
742 return;
745 auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength);
746 if (!bufferCopy) {
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;
750 requestSuspension();
751 return;
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);
766 return;
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,
774 int32_t aLength) {
775 MOZ_ASSERT(aBuffer, "Null buffer");
776 MOZ_ASSERT(aParent, "Null parent");
777 MOZ_ASSERT(!aStart, "aStart must always be zero.");
779 if (mBuilder) {
780 nsresult rv = nsHtml5TreeOperation::AppendComment(
781 static_cast<nsIContent*>(aParent),
782 aBuffer, // XXX aStart always ignored???
783 aLength, mBuilder);
784 if (NS_FAILED(rv)) {
785 MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
787 return;
790 auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength);
791 if (!bufferCopy) {
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;
795 requestSuspension();
796 return;
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);
804 return;
806 opAppendComment operation(aParent, bufferCopy.release(), aLength);
807 treeOp->Init(mozilla::AsVariant(operation));
810 void nsHtml5TreeBuilder::appendCommentToDocument(char16_t* aBuffer,
811 int32_t aStart,
812 int32_t aLength) {
813 MOZ_ASSERT(aBuffer, "Null buffer");
814 MOZ_ASSERT(!aStart, "aStart must always be zero.");
816 if (mBuilder) {
817 nsresult rv = nsHtml5TreeOperation::AppendCommentToDocument(
818 aBuffer, // XXX aStart always ignored???
819 aLength, mBuilder);
820 if (NS_FAILED(rv)) {
821 MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
823 return;
826 auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength);
827 if (!bufferCopy) {
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;
831 requestSuspension();
832 return;
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);
840 return;
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) {
852 return;
855 if (mBuilder) {
856 MOZ_ASSERT(
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);
861 if (NS_FAILED(rv)) {
862 MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
864 return;
867 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
868 if (MOZ_UNLIKELY(!treeOp)) {
869 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
870 return;
872 opAddAttributes opeation(aElement, aAttributes);
873 treeOp->Init(mozilla::AsVariant(opeation));
876 void nsHtml5TreeBuilder::markMalformedIfScript(nsIContentHandle* aElement) {
877 MOZ_ASSERT(aElement, "Null element");
879 if (mBuilder) {
880 nsHtml5TreeOperation::MarkMalformedIfScript(
881 static_cast<nsIContent*>(aElement));
882 return;
885 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
886 if (MOZ_UNLIKELY(!treeOp)) {
887 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
888 return;
890 opMarkMalformedIfScript operation(aElement);
891 treeOp->Init(mozilla::AsVariant(operation));
894 void nsHtml5TreeBuilder::start(bool fragment) {
895 mCurrentHtmlScriptIsAsyncOrDefer = false;
896 #ifdef DEBUG
897 mActive = true;
898 #endif
901 void nsHtml5TreeBuilder::end() {
902 mOpQueue.Clear();
903 #ifdef DEBUG
904 mActive = false;
905 #endif
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);
916 if (mBuilder) {
917 nsresult rv = nsHtml5TreeOperation::AppendDoctypeToDocument(
918 aName, publicId, systemId, mBuilder);
919 if (NS_FAILED(rv)) {
920 MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
922 return;
925 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
926 if (MOZ_UNLIKELY(!treeOp)) {
927 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
928 return;
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
961 * reasons.
963 if (aNamespace != kNameSpaceID_XHTML) {
964 return;
966 if (aName == nsGkAtoms::body || aName == nsGkAtoms::frameset) {
967 if (mBuilder) {
968 // InnerHTML and DOMParser shouldn't start layout anyway
969 return;
971 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
972 if (MOZ_UNLIKELY(!treeOp)) {
973 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
974 return;
976 treeOp->Init(mozilla::AsVariant(opStartLayout()));
977 return;
979 if (nsIContent::RequiresDoneCreatingElement(kNameSpaceID_XHTML, aName)) {
980 if (mBuilder) {
981 nsHtml5TreeOperation::DoneCreatingElement(
982 static_cast<nsIContent*>(aElement));
983 } else {
984 opDoneCreatingElement operation(aElement);
985 mOpQueue.AppendElement()->Init(mozilla::AsVariant(operation));
987 return;
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) {
1007 return;
1009 // we now have only SVG and HTML
1010 if (aName == nsGkAtoms::script) {
1011 if (mPreventScriptExecution) {
1012 if (mBuilder) {
1013 nsHtml5TreeOperation::PreventScriptExecution(
1014 static_cast<nsIContent*>(aElement));
1015 return;
1017 opPreventScriptExecution operation(aElement);
1018 mOpQueue.AppendElement()->Init(mozilla::AsVariant(operation));
1019 return;
1021 if (mBuilder) {
1022 return;
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);
1030 return;
1032 opRunScriptAsyncDefer operation(aElement);
1033 treeOp->Init(mozilla::AsVariant(operation));
1034 mCurrentHtmlScriptIsAsyncOrDefer = false;
1035 return;
1037 requestSuspension();
1038 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1039 if (MOZ_UNLIKELY(!treeOp)) {
1040 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1041 return;
1043 opRunScript operation(aElement, nullptr);
1044 treeOp->Init(mozilla::AsVariant(operation));
1045 return;
1047 // Some nodes need DoneAddingChildren() called to initialize
1048 // properly (e.g. form state restoration).
1049 if (nsIContent::RequiresDoneAddingChildren(aNamespace, aName)) {
1050 if (mBuilder) {
1051 nsHtml5TreeOperation::DoneAddingChildren(
1052 static_cast<nsIContent*>(aElement));
1053 return;
1055 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1056 if (MOZ_UNLIKELY(!treeOp)) {
1057 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1058 return;
1060 opDoneAddingChildren operation(aElement);
1061 treeOp->Init(mozilla::AsVariant(operation));
1062 return;
1064 if (aName == nsGkAtoms::style ||
1065 (aNamespace == kNameSpaceID_XHTML && aName == nsGkAtoms::link)) {
1066 if (mBuilder) {
1067 MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(),
1068 "Scripts must be blocked.");
1069 mBuilder->UpdateStyleSheet(static_cast<nsIContent*>(aElement));
1070 return;
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);
1083 return;
1085 opUpdateStyleSheet operation(aElement);
1086 treeOp->Init(mozilla::AsVariant(operation));
1087 return;
1089 if (aNamespace == kNameSpaceID_SVG) {
1090 if (aName == nsGkAtoms::svg) {
1091 if (!scriptingEnabled || mPreventScriptExecution) {
1092 return;
1094 if (mBuilder) {
1095 nsHtml5TreeOperation::SvgLoad(static_cast<nsIContent*>(aElement));
1096 return;
1098 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1099 if (MOZ_UNLIKELY(!treeOp)) {
1100 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1101 return;
1103 opSvgLoad operation(aElement);
1104 treeOp->Init(mozilla::AsVariant(operation));
1106 return;
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()) {
1139 return false;
1141 if (worstCase.value() > MAX_POWER_OF_TWO_IN_INT32) {
1142 return false;
1144 if (!charBuffer) {
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.
1148 worstCase += 1;
1150 charBuffer = jArray<char16_t, int32_t>::newFallibleJArray(
1151 mozilla::RoundUpPow2(worstCase.value()));
1152 if (!charBuffer) {
1153 return false;
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()));
1159 if (!newBuf) {
1160 return false;
1162 memcpy(newBuf, charBuffer, sizeof(char16_t) * size_t(charBufferLen));
1163 charBuffer = newBuf;
1165 return true;
1168 nsIContentHandle* nsHtml5TreeBuilder::AllocateContentHandle() {
1169 if (MOZ_UNLIKELY(mBuilder)) {
1170 MOZ_ASSERT_UNREACHABLE("Must never allocate a handle with builder.");
1171 return nullptr;
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);
1177 mHandlesUsed = 0;
1179 #ifdef DEBUG
1180 mHandles[mHandlesUsed] = reinterpret_cast<nsIContent*>(uintptr_t(0xC0DEDBAD));
1181 #endif
1182 return &mHandles[mHandlesUsed++];
1185 bool nsHtml5TreeBuilder::HasScript() {
1186 uint32_t len = mOpQueue.Length();
1187 if (!len) {
1188 return false;
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.");
1196 return false;
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.
1205 flushCharacters();
1207 FlushLoads();
1209 if (mOpSink) {
1210 bool hasOps = !mOpQueue.IsEmpty();
1211 if (hasOps) {
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 "
1217 "length isn't 1.");
1218 MOZ_ASSERT(mOpQueue[0].IsMarkAsBroken(),
1219 "Tree builder is broken but the op in queue is not marked "
1220 "as broken.");
1222 mOpSink->MoveOpsFrom(mOpQueue);
1224 return hasOps;
1226 // no op sink: throw away ops
1227 mOpQueue.Clear();
1228 return false;
1231 void nsHtml5TreeBuilder::FlushLoads() {
1232 if (MOZ_UNLIKELY(mBuilder)) {
1233 MOZ_ASSERT_UNREACHABLE("Must never flush loads with builder.");
1234 return;
1236 if (!mSpeculativeLoadQueue.IsEmpty()) {
1237 mSpeculativeLoadStage->MoveSpeculativeLoadsFrom(mSpeculativeLoadQueue);
1241 void nsHtml5TreeBuilder::SetDocumentCharset(NotNull<const Encoding*> aEncoding,
1242 int32_t aCharsetSource) {
1243 if (mBuilder) {
1244 mBuilder->SetDocumentCharsetAndSource(aEncoding, aCharsetSource);
1245 } else if (mSpeculativeLoadStage) {
1246 mSpeculativeLoadQueue.AppendElement()->InitSetDocumentCharset(
1247 aEncoding, aCharsetSource);
1248 } else {
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);
1260 return;
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.");
1270 return;
1272 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1273 if (MOZ_UNLIKELY(!treeOp)) {
1274 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1275 return;
1277 opCharsetSwitchTo opeation(aEncoding, aCharsetSource, aLineNumber);
1278 treeOp->Init(mozilla::AsVariant(opeation));
1281 void nsHtml5TreeBuilder::MaybeComplainAboutCharset(const char* aMsgId,
1282 bool aError,
1283 int32_t aLineNumber) {
1284 if (MOZ_UNLIKELY(mBuilder)) {
1285 MOZ_ASSERT_UNREACHABLE("Must never complain about charset with builder.");
1286 return;
1288 opMaybeComplainAboutCharset opeartion(const_cast<char*>(aMsgId), aError,
1289 aLineNumber);
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.");
1296 return;
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.");
1307 return;
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();
1317 mHandlesUsed = 0;
1320 void nsHtml5TreeBuilder::MarkAsBroken(nsresult aRv) {
1321 if (MOZ_UNLIKELY(mBuilder)) {
1322 MOZ_ASSERT_UNREACHABLE("Must not call this with builder.");
1323 return;
1325 mBroken = aRv;
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) {
1332 if (mBuilder) {
1333 MarkAsBrokenAndRequestSuspensionWithBuilder(aRv);
1334 return;
1336 mBroken = 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) {
1352 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,
1380 false);
1381 needToDropLF = false;
1384 // DocumentModeHandler
1385 void nsHtml5TreeBuilder::documentMode(nsHtml5DocumentMode m) {
1386 if (mBuilder) {
1387 mBuilder->SetDocumentMode(m);
1388 return;
1390 if (mSpeculativeLoadStage) {
1391 mSpeculativeLoadQueue.AppendElement()->InitSetDocumentMode(m);
1392 return;
1394 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1395 if (MOZ_UNLIKELY(!treeOp)) {
1396 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1397 return;
1399 treeOp->Init(mozilla::AsVariant(m));
1402 nsIContentHandle* nsHtml5TreeBuilder::getDocumentFragmentForTemplate(
1403 nsIContentHandle* aTemplate) {
1404 if (mBuilder) {
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);
1411 return nullptr;
1413 nsIContentHandle* fragHandle = AllocateContentHandle();
1414 opGetDocumentFragmentForTemplate operation(aTemplate, fragHandle);
1415 treeOp->Init(mozilla::AsVariant(operation));
1416 return fragHandle;
1419 nsIContentHandle* nsHtml5TreeBuilder::getFormPointerForContext(
1420 nsIContentHandle* aContext) {
1421 MOZ_ASSERT(mBuilder, "Must have builder.");
1422 if (!aContext) {
1423 return nullptr;
1426 MOZ_ASSERT(NS_IsMainThread());
1428 // aContext must always be an element that already exists
1429 // in the document.
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;
1439 break;
1441 currentAncestor = currentAncestor->GetParent();
1444 if (!nearestForm) {
1445 return nullptr;
1448 return nearestForm;
1451 // Error reporting
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,
1488 nsAtom* aName) {
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",
1683 aName);
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",
1733 aName, aOther);
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");