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/. */
6
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"
13
nsHtml5TreeBuilder(nsHtml5OplessBuilder * aBuilder)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
45 ,
46 mActive(false)
47 #endif
48 {
49 MOZ_COUNT_CTOR(nsHtml5TreeBuilder);
50 }
51
nsHtml5TreeBuilder(nsAHtml5TreeOpSink * aOpSink,nsHtml5TreeOpStage * aStage)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
84 ,
85 mActive(false)
86 #endif
87 {
88 MOZ_COUNT_CTOR(nsHtml5TreeBuilder);
89 }
90
~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();
96 }
97
createElement(int32_t aNamespace,nsAtom * aName,nsHtml5HtmlAttributes * aAttributes,nsIContentHandle * aIntendedParent,nsHtml5ContentCreatorFunction aCreator)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.");
107
108 if (mBuilder) {
109 nsIContent* intendedParent =
110 aIntendedParent ? static_cast<nsIContent*>(aIntendedParent) : nullptr;
111
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();
117
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);
131 }
132 if (MOZ_UNLIKELY(aAttributes != tokenizer->GetAttributes() &&
133 aAttributes != nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES)) {
134 delete aAttributes;
135 }
136 return elem;
137 }
138
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;
144 }
145
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));
163 }
164
165 // mSpeculativeLoadStage is non-null only in the off-the-main-thread
166 // tree builder, which handles the network stream
167
168 // Start wall of code for speculative loading and line numbers
169
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);
191 }
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);
207 }
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;
215 }
216 opSetScriptLineNumberAndFreeze operation(content,
217 tokenizer->getLineNumber());
218 treeOp->Init(mozilla::AsVariant(operation));
219
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;
244 }
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);
268 }
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);
277 }
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);
295
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);
328 }
329 // Other "as" values will be supported later.
330 }
331 }
332 }
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);
339 }
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;
348 }
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);
360 }
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);
370 }
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);
381 }
382 }
383 }
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);
391 }
392 if (url) {
393 mSpeculativeLoadQueue.AppendElement()->InitImage(
394 url, nullptr, nullptr, nullptr, nullptr, nullptr, false);
395 }
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;
403 }
404 opSetScriptLineNumberAndFreeze operation(content,
405 tokenizer->getLineNumber());
406 treeOp->Init(mozilla::AsVariant(operation));
407
408 nsHtml5String url =
409 aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
410 if (!url) {
411 url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
412 }
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);
426 }
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;
435 }
436 opSetStyleLineNumber operation(content, tokenizer->getLineNumber());
437 treeOp->Init(mozilla::AsVariant(operation));
438 }
439 break;
440 }
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;
448 }
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;
456 }
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));
465 }
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;
476 }
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));
486 }
487 } else if (nsGkAtoms::base == aName && mViewSource) {
488 nsHtml5String url =
489 aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
490 if (url) {
491 mViewSource->AddBase(url);
492 }
493 }
494 }
495 }
496
497 // End wall of code for speculative loading
498
499 return content;
500 }
501
createElement(int32_t aNamespace,nsAtom * aName,nsHtml5HtmlAttributes * aAttributes,nsIContentHandle * aFormElement,nsIContentHandle * aIntendedParent,nsHtml5ContentCreatorFunction aCreator)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;
518 }
519 opSetFormElement operation(content, aFormElement);
520 treeOp->Init(mozilla::AsVariant(operation));
521 }
522 }
523 return content;
524 }
525
createHtmlElementSetAsRoot(nsHtml5HtmlAttributes * aAttributes)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);
538 }
539 } else {
540 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
541 if (MOZ_UNLIKELY(!treeOp)) {
542 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
543 return nullptr;
544 }
545 opAppendToDocument operation(content);
546 treeOp->Init(mozilla::AsVariant(operation));
547 }
548 return content;
549 }
550
createAndInsertFosterParentedElement(int32_t aNamespace,nsAtom * aName,nsHtml5HtmlAttributes * aAttributes,nsIContentHandle * aFormElement,nsIContentHandle * aTable,nsIContentHandle * aStackParent,nsHtml5ContentCreatorFunction aCreator)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");
557
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));
564
565 nsIContentHandle* child = createElement(
566 aNamespace, aName, aAttributes, aFormElement, fosterParent, aCreator);
567
568 insertFosterParentedChild(child, aTable, aStackParent);
569
570 return child;
571 }
572
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));
580
581 // Create the element with the correct intended parent.
582 nsIContentHandle* child =
583 createElement(aNamespace, aName, aAttributes, aFormElement,
584 fosterParentHandle, aCreator);
585
586 // Insert the child into the foster parent.
587 insertFosterParentedChild(child, aTable, aStackParent);
588
589 return child;
590 }
591
detachFromParent(nsIContentHandle * aElement)592 void nsHtml5TreeBuilder::detachFromParent(nsIContentHandle* aElement) {
593 MOZ_ASSERT(aElement, "Null element");
594
595 if (mBuilder) {
596 nsHtml5TreeOperation::Detach(static_cast<nsIContent*>(aElement), mBuilder);
597 return;
598 }
599
600 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
601 if (MOZ_UNLIKELY(!treeOp)) {
602 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
603 return;
604 }
605 opDetach operation(aElement);
606 treeOp->Init(mozilla::AsVariant(operation));
607 }
608
appendElement(nsIContentHandle * aChild,nsIContentHandle * aParent)609 void nsHtml5TreeBuilder::appendElement(nsIContentHandle* aChild,
610 nsIContentHandle* aParent) {
611 MOZ_ASSERT(aChild, "Null child");
612 MOZ_ASSERT(aParent, "Null parent");
613
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);
620 }
621 return;
622 }
623
624 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
625 if (MOZ_UNLIKELY(!treeOp)) {
626 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
627 return;
628 }
629
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));
635 }
636
appendChildrenToNewParent(nsIContentHandle * aOldParent,nsIContentHandle * aNewParent)637 void nsHtml5TreeBuilder::appendChildrenToNewParent(
638 nsIContentHandle* aOldParent, nsIContentHandle* aNewParent) {
639 MOZ_ASSERT(aOldParent, "Null old parent");
640 MOZ_ASSERT(aNewParent, "Null new parent");
641
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);
648 }
649 return;
650 }
651
652 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
653 if (MOZ_UNLIKELY(!treeOp)) {
654 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
655 return;
656 }
657 opAppendChildrenToNewParent operation(aOldParent, aNewParent);
658 treeOp->Init(mozilla::AsVariant(operation));
659 }
660
insertFosterParentedCharacters(char16_t * aBuffer,int32_t aStart,int32_t aLength,nsIContentHandle * aTable,nsIContentHandle * aStackParent)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.");
668
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);
676 }
677 return;
678 }
679
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;
687 }
688
689 memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t));
690
691 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
692 if (MOZ_UNLIKELY(!treeOp)) {
693 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
694 return;
695 }
696 opFosterParentText operation(aStackParent, bufferCopy.release(), aTable,
697 aLength);
698 treeOp->Init(mozilla::AsVariant(operation));
699 }
700
insertFosterParentedChild(nsIContentHandle * aChild,nsIContentHandle * aTable,nsIContentHandle * aStackParent)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");
707
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);
715 }
716 return;
717 }
718
719 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
720 if (MOZ_UNLIKELY(!treeOp)) {
721 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
722 return;
723 }
724 opFosterParent operation(aChild, aStackParent, aTable);
725 treeOp->Init(mozilla::AsVariant(operation));
726 }
727
appendCharacters(nsIContentHandle * aParent,char16_t * aBuffer,int32_t aStart,int32_t aLength)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.");
734
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);
741 }
742 return;
743 }
744
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;
752 }
753
754 memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t));
755
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));
760 }
761 }
762
763 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
764 if (MOZ_UNLIKELY(!treeOp)) {
765 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
766 return;
767 }
768 opAppendText operation(aParent, bufferCopy.release(), aLength);
769 treeOp->Init(mozilla::AsVariant(operation));
770 }
771
appendComment(nsIContentHandle * aParent,char16_t * aBuffer,int32_t aStart,int32_t aLength)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.");
778
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);
786 }
787 return;
788 }
789
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;
797 }
798
799 memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t));
800
801 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
802 if (MOZ_UNLIKELY(!treeOp)) {
803 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
804 return;
805 }
806 opAppendComment operation(aParent, bufferCopy.release(), aLength);
807 treeOp->Init(mozilla::AsVariant(operation));
808 }
809
appendCommentToDocument(char16_t * aBuffer,int32_t aStart,int32_t aLength)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.");
815
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);
822 }
823 return;
824 }
825
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;
833 }
834
835 memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t));
836
837 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
838 if (MOZ_UNLIKELY(!treeOp)) {
839 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
840 return;
841 }
842 opAppendCommentToDocument data(bufferCopy.release(), aLength);
843 treeOp->Init(mozilla::AsVariant(data));
844 }
845
addAttributesToElement(nsIContentHandle * aElement,nsHtml5HtmlAttributes * aAttributes)846 void nsHtml5TreeBuilder::addAttributesToElement(
847 nsIContentHandle* aElement, nsHtml5HtmlAttributes* aAttributes) {
848 MOZ_ASSERT(aElement, "Null element");
849 MOZ_ASSERT(aAttributes, "Null attributes");
850
851 if (aAttributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
852 return;
853 }
854
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);
863 }
864 return;
865 }
866
867 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
868 if (MOZ_UNLIKELY(!treeOp)) {
869 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
870 return;
871 }
872 opAddAttributes opeation(aElement, aAttributes);
873 treeOp->Init(mozilla::AsVariant(opeation));
874 }
875
markMalformedIfScript(nsIContentHandle * aElement)876 void nsHtml5TreeBuilder::markMalformedIfScript(nsIContentHandle* aElement) {
877 MOZ_ASSERT(aElement, "Null element");
878
879 if (mBuilder) {
880 nsHtml5TreeOperation::MarkMalformedIfScript(
881 static_cast<nsIContent*>(aElement));
882 return;
883 }
884
885 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
886 if (MOZ_UNLIKELY(!treeOp)) {
887 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
888 return;
889 }
890 opMarkMalformedIfScript operation(aElement);
891 treeOp->Init(mozilla::AsVariant(operation));
892 }
893
start(bool fragment)894 void nsHtml5TreeBuilder::start(bool fragment) {
895 mCurrentHtmlScriptIsAsyncOrDefer = false;
896 #ifdef DEBUG
897 mActive = true;
898 #endif
899 }
900
end()901 void nsHtml5TreeBuilder::end() {
902 mOpQueue.Clear();
903 #ifdef DEBUG
904 mActive = false;
905 #endif
906 }
907
appendDoctypeToDocument(nsAtom * aName,nsHtml5String aPublicId,nsHtml5String aSystemId)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);
921 }
922 return;
923 }
924
925 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
926 if (MOZ_UNLIKELY(!treeOp)) {
927 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
928 return;
929 }
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.
934 }
935
elementPushed(int32_t aNamespace,nsAtom * aName,nsIContentHandle * aElement)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!");
944 /*
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.
948 *
949 * The following is a protection against author incompetence--not against
950 * malice. There are other ways to make the DOM deep anyway.
951 *
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.
957 *
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.
962 */
963 if (aNamespace != kNameSpaceID_XHTML) {
964 return;
965 }
966 if (aName == nsGkAtoms::body || aName == nsGkAtoms::frameset) {
967 if (mBuilder) {
968 // InnerHTML and DOMParser shouldn't start layout anyway
969 return;
970 }
971 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
972 if (MOZ_UNLIKELY(!treeOp)) {
973 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
974 return;
975 }
976 treeOp->Init(mozilla::AsVariant(opStartLayout()));
977 return;
978 }
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));
986 }
987 return;
988 }
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
992 //
993 // See comments in nsHtml5SpeculativeLoad.h about <picture> preloading
994 mSpeculativeLoadQueue.AppendElement()->InitOpenPicture();
995 }
996 }
997
elementPopped(int32_t aNamespace,nsAtom * aName,nsIContentHandle * aElement)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;
1008 }
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;
1016 }
1017 opPreventScriptExecution operation(aElement);
1018 mOpQueue.AppendElement()->Init(mozilla::AsVariant(operation));
1019 return;
1020 }
1021 if (mBuilder) {
1022 return;
1023 }
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;
1031 }
1032 opRunScriptAsyncDefer operation(aElement);
1033 treeOp->Init(mozilla::AsVariant(operation));
1034 mCurrentHtmlScriptIsAsyncOrDefer = false;
1035 return;
1036 }
1037 requestSuspension();
1038 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1039 if (MOZ_UNLIKELY(!treeOp)) {
1040 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1041 return;
1042 }
1043 opRunScript operation(aElement, nullptr);
1044 treeOp->Init(mozilla::AsVariant(operation));
1045 return;
1046 }
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;
1054 }
1055 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1056 if (MOZ_UNLIKELY(!treeOp)) {
1057 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1058 return;
1059 }
1060 opDoneAddingChildren operation(aElement);
1061 treeOp->Init(mozilla::AsVariant(operation));
1062 return;
1063 }
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;
1071 }
1072
1073 if (aName == nsGkAtoms::style) {
1074 nsTArray<nsString> imports = mImportScanner.Stop();
1075 for (nsString& url : imports) {
1076 mSpeculativeLoadQueue.AppendElement()->InitImportStyle(std::move(url));
1077 }
1078 }
1079
1080 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1081 if (MOZ_UNLIKELY(!treeOp)) {
1082 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1083 return;
1084 }
1085 opUpdateStyleSheet operation(aElement);
1086 treeOp->Init(mozilla::AsVariant(operation));
1087 return;
1088 }
1089 if (aNamespace == kNameSpaceID_SVG) {
1090 if (aName == nsGkAtoms::svg) {
1091 if (!scriptingEnabled || mPreventScriptExecution) {
1092 return;
1093 }
1094 if (mBuilder) {
1095 nsHtml5TreeOperation::SvgLoad(static_cast<nsIContent*>(aElement));
1096 return;
1097 }
1098 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1099 if (MOZ_UNLIKELY(!treeOp)) {
1100 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1101 return;
1102 }
1103 opSvgLoad operation(aElement);
1104 treeOp->Init(mozilla::AsVariant(operation));
1105 }
1106 return;
1107 }
1108
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
1112 //
1113 // See comments in nsHtml5SpeculativeLoad.h about <picture> preloading
1114 mSpeculativeLoadQueue.AppendElement()->InitEndPicture();
1115 }
1116 }
1117
accumulateCharacters(const char16_t * aBuf,int32_t aStart,int32_t aLength)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;
1124 }
1125
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
1132
EnsureBufferSpace(int32_t aLength)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;
1140 }
1141 if (worstCase.value() > MAX_POWER_OF_TWO_IN_INT32) {
1142 return false;
1143 }
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;
1149 }
1150 charBuffer = jArray<char16_t, int32_t>::newFallibleJArray(
1151 mozilla::RoundUpPow2(worstCase.value()));
1152 if (!charBuffer) {
1153 return false;
1154 }
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;
1161 }
1162 memcpy(newBuf, charBuffer, sizeof(char16_t) * size_t(charBufferLen));
1163 charBuffer = newBuf;
1164 }
1165 return true;
1166 }
1167
AllocateContentHandle()1168 nsIContentHandle* nsHtml5TreeBuilder::AllocateContentHandle() {
1169 if (MOZ_UNLIKELY(mBuilder)) {
1170 MOZ_ASSERT_UNREACHABLE("Must never allocate a handle with builder.");
1171 return nullptr;
1172 }
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;
1178 }
1179 #ifdef DEBUG
1180 mHandles[mHandlesUsed] = reinterpret_cast<nsIContent*>(uintptr_t(0xC0DEDBAD));
1181 #endif
1182 return &mHandles[mHandlesUsed++];
1183 }
1184
HasScript()1185 bool nsHtml5TreeBuilder::HasScript() {
1186 uint32_t len = mOpQueue.Length();
1187 if (!len) {
1188 return false;
1189 }
1190 return mOpQueue.ElementAt(len - 1).IsRunScript();
1191 }
1192
Flush(bool aDiscretionary)1193 bool nsHtml5TreeBuilder::Flush(bool aDiscretionary) {
1194 if (MOZ_UNLIKELY(mBuilder)) {
1195 MOZ_ASSERT_UNREACHABLE("Must never flush with builder.");
1196 return false;
1197 }
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();
1206 }
1207 FlushLoads();
1208 }
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.");
1221 }
1222 mOpSink->MoveOpsFrom(mOpQueue);
1223 }
1224 return hasOps;
1225 }
1226 // no op sink: throw away ops
1227 mOpQueue.Clear();
1228 return false;
1229 }
1230
FlushLoads()1231 void nsHtml5TreeBuilder::FlushLoads() {
1232 if (MOZ_UNLIKELY(mBuilder)) {
1233 MOZ_ASSERT_UNREACHABLE("Must never flush loads with builder.");
1234 return;
1235 }
1236 if (!mSpeculativeLoadQueue.IsEmpty()) {
1237 mSpeculativeLoadStage->MoveSpeculativeLoadsFrom(mSpeculativeLoadQueue);
1238 }
1239 }
1240
SetDocumentCharset(NotNull<const Encoding * > aEncoding,int32_t aCharsetSource)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));
1251 }
1252 }
1253
StreamEnded()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;
1261 }
1262 treeOp->Init(mozilla::AsVariant(opStreamEnded()));
1263 }
1264
NeedsCharsetSwitchTo(NotNull<const Encoding * > aEncoding,int32_t aCharsetSource,int32_t aLineNumber)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;
1271 }
1272 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1273 if (MOZ_UNLIKELY(!treeOp)) {
1274 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1275 return;
1276 }
1277 opCharsetSwitchTo opeation(aEncoding, aCharsetSource, aLineNumber);
1278 treeOp->Init(mozilla::AsVariant(opeation));
1279 }
1280
MaybeComplainAboutCharset(const char * aMsgId,bool aError,int32_t aLineNumber)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;
1287 }
1288 opMaybeComplainAboutCharset opeartion(const_cast<char*>(aMsgId), aError,
1289 aLineNumber);
1290 mOpQueue.AppendElement()->Init(mozilla::AsVariant(opeartion));
1291 }
1292
TryToEnableEncodingMenu()1293 void nsHtml5TreeBuilder::TryToEnableEncodingMenu() {
1294 if (MOZ_UNLIKELY(mBuilder)) {
1295 MOZ_ASSERT_UNREACHABLE("Must never disable encoding menu with builder.");
1296 return;
1297 }
1298 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
1299 NS_ASSERTION(treeOp, "Tree op allocation failed.");
1300 treeOp->Init(mozilla::AsVariant(opEnableEncodingMenu()));
1301 }
1302
AddSnapshotToScript(nsAHtml5TreeBuilderState * aSnapshot,int32_t aLine)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;
1308 }
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);
1312 }
1313
DropHandles()1314 void nsHtml5TreeBuilder::DropHandles() {
1315 MOZ_ASSERT(!mBuilder, "Must not drop handles with builder.");
1316 mOldHandles.Clear();
1317 mHandlesUsed = 0;
1318 }
1319
MarkAsBroken(nsresult aRv)1320 void nsHtml5TreeBuilder::MarkAsBroken(nsresult aRv) {
1321 if (MOZ_UNLIKELY(mBuilder)) {
1322 MOZ_ASSERT_UNREACHABLE("Must not call this with builder.");
1323 return;
1324 }
1325 mBroken = aRv;
1326 mOpQueue.Clear(); // Previous ops don't matter anymore
1327 opMarkAsBroken operation(aRv);
1328 mOpQueue.AppendElement()->Init(mozilla::AsVariant(operation));
1329 }
1330
MarkAsBrokenFromPortability(nsresult aRv)1331 void nsHtml5TreeBuilder::MarkAsBrokenFromPortability(nsresult aRv) {
1332 if (mBuilder) {
1333 MarkAsBrokenAndRequestSuspensionWithBuilder(aRv);
1334 return;
1335 }
1336 mBroken = aRv;
1337 requestSuspension();
1338 }
1339
StartPlainTextViewSource(const nsAutoString & aTitle)1340 void nsHtml5TreeBuilder::StartPlainTextViewSource(const nsAutoString& aTitle) {
1341 MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
1342
1343 startTag(nsHtml5ElementName::ELT_META,
1344 nsHtml5ViewSourceUtils::NewMetaViewportAttributes(), false);
1345
1346 startTag(nsHtml5ElementName::ELT_TITLE,
1347 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES, false);
1348
1349 // XUL will add the "Source of: " prefix.
1350 uint32_t length = aTitle.Length();
1351 if (length > INT32_MAX) {
1352 length = INT32_MAX;
1353 }
1354 characters(aTitle.get(), 0, (int32_t)length);
1355 endTag(nsHtml5ElementName::ELT_TITLE);
1356
1357 startTag(nsHtml5ElementName::ELT_LINK,
1358 nsHtml5ViewSourceUtils::NewLinkAttributes(), false);
1359
1360 startTag(nsHtml5ElementName::ELT_BODY,
1361 nsHtml5ViewSourceUtils::NewBodyAttributes(), false);
1362
1363 StartPlainTextBody();
1364 }
1365
StartPlainText()1366 void nsHtml5TreeBuilder::StartPlainText() {
1367 MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
1368 startTag(nsHtml5ElementName::ELT_LINK,
1369 nsHtml5PlainTextUtils::NewLinkAttributes(), false);
1370
1371 startTag(nsHtml5ElementName::ELT_BODY,
1372 nsHtml5PlainTextUtils::NewBodyAttributes(), false);
1373
1374 StartPlainTextBody();
1375 }
1376
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;
1382 }
1383
1384 // DocumentModeHandler
documentMode(nsHtml5DocumentMode m)1385 void nsHtml5TreeBuilder::documentMode(nsHtml5DocumentMode m) {
1386 if (mBuilder) {
1387 mBuilder->SetDocumentMode(m);
1388 return;
1389 }
1390 if (mSpeculativeLoadStage) {
1391 mSpeculativeLoadQueue.AppendElement()->InitSetDocumentMode(m);
1392 return;
1393 }
1394 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1395 if (MOZ_UNLIKELY(!treeOp)) {
1396 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1397 return;
1398 }
1399 treeOp->Init(mozilla::AsVariant(m));
1400 }
1401
getDocumentFragmentForTemplate(nsIContentHandle * aTemplate)1402 nsIContentHandle* nsHtml5TreeBuilder::getDocumentFragmentForTemplate(
1403 nsIContentHandle* aTemplate) {
1404 if (mBuilder) {
1405 return nsHtml5TreeOperation::GetDocumentFragmentForTemplate(
1406 static_cast<nsIContent*>(aTemplate));
1407 }
1408 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1409 if (MOZ_UNLIKELY(!treeOp)) {
1410 MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1411 return nullptr;
1412 }
1413 nsIContentHandle* fragHandle = AllocateContentHandle();
1414 opGetDocumentFragmentForTemplate operation(aTemplate, fragHandle);
1415 treeOp->Init(mozilla::AsVariant(operation));
1416 return fragHandle;
1417 }
1418
getFormPointerForContext(nsIContentHandle * aContext)1419 nsIContentHandle* nsHtml5TreeBuilder::getFormPointerForContext(
1420 nsIContentHandle* aContext) {
1421 MOZ_ASSERT(mBuilder, "Must have builder.");
1422 if (!aContext) {
1423 return nullptr;
1424 }
1425
1426 MOZ_ASSERT(NS_IsMainThread());
1427
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;
1432
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;
1440 }
1441 currentAncestor = currentAncestor->GetParent();
1442 }
1443
1444 if (!nearestForm) {
1445 return nullptr;
1446 }
1447
1448 return nearestForm;
1449 }
1450
1451 // Error reporting
1452
EnableViewSource(nsHtml5Highlighter * aHighlighter)1453 void nsHtml5TreeBuilder::EnableViewSource(nsHtml5Highlighter* aHighlighter) {
1454 MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
1455 mViewSource = aHighlighter;
1456 }
1457
errDeepTree()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));
1466 }
1467 }
1468
errStrayStartTag(nsAtom * aName)1469 void nsHtml5TreeBuilder::errStrayStartTag(nsAtom* aName) {
1470 if (MOZ_UNLIKELY(mViewSource)) {
1471 mViewSource->AddErrorToCurrentRun("errStrayStartTag2", aName);
1472 }
1473 }
1474
errStrayEndTag(nsAtom * aName)1475 void nsHtml5TreeBuilder::errStrayEndTag(nsAtom* aName) {
1476 if (MOZ_UNLIKELY(mViewSource)) {
1477 mViewSource->AddErrorToCurrentRun("errStrayEndTag", aName);
1478 }
1479 }
1480
errUnclosedElements(int32_t aIndex,nsAtom * aName)1481 void nsHtml5TreeBuilder::errUnclosedElements(int32_t aIndex, nsAtom* aName) {
1482 if (MOZ_UNLIKELY(mViewSource)) {
1483 mViewSource->AddErrorToCurrentRun("errUnclosedElements", aName);
1484 }
1485 }
1486
errUnclosedElementsImplied(int32_t aIndex,nsAtom * aName)1487 void nsHtml5TreeBuilder::errUnclosedElementsImplied(int32_t aIndex,
1488 nsAtom* aName) {
1489 if (MOZ_UNLIKELY(mViewSource)) {
1490 mViewSource->AddErrorToCurrentRun("errUnclosedElementsImplied", aName);
1491 }
1492 }
1493
errUnclosedElementsCell(int32_t aIndex)1494 void nsHtml5TreeBuilder::errUnclosedElementsCell(int32_t aIndex) {
1495 if (MOZ_UNLIKELY(mViewSource)) {
1496 mViewSource->AddErrorToCurrentRun("errUnclosedElementsCell");
1497 }
1498 }
1499
errStrayDoctype()1500 void nsHtml5TreeBuilder::errStrayDoctype() {
1501 if (MOZ_UNLIKELY(mViewSource)) {
1502 mViewSource->AddErrorToCurrentRun("errStrayDoctype");
1503 }
1504 }
1505
errAlmostStandardsDoctype()1506 void nsHtml5TreeBuilder::errAlmostStandardsDoctype() {
1507 if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) {
1508 mViewSource->AddErrorToCurrentRun("errAlmostStandardsDoctype");
1509 }
1510 }
1511
errQuirkyDoctype()1512 void nsHtml5TreeBuilder::errQuirkyDoctype() {
1513 if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) {
1514 mViewSource->AddErrorToCurrentRun("errQuirkyDoctype");
1515 }
1516 }
1517
errNonSpaceInTrailer()1518 void nsHtml5TreeBuilder::errNonSpaceInTrailer() {
1519 if (MOZ_UNLIKELY(mViewSource)) {
1520 mViewSource->AddErrorToCurrentRun("errNonSpaceInTrailer");
1521 }
1522 }
1523
errNonSpaceAfterFrameset()1524 void nsHtml5TreeBuilder::errNonSpaceAfterFrameset() {
1525 if (MOZ_UNLIKELY(mViewSource)) {
1526 mViewSource->AddErrorToCurrentRun("errNonSpaceAfterFrameset");
1527 }
1528 }
1529
errNonSpaceInFrameset()1530 void nsHtml5TreeBuilder::errNonSpaceInFrameset() {
1531 if (MOZ_UNLIKELY(mViewSource)) {
1532 mViewSource->AddErrorToCurrentRun("errNonSpaceInFrameset");
1533 }
1534 }
1535
errNonSpaceAfterBody()1536 void nsHtml5TreeBuilder::errNonSpaceAfterBody() {
1537 if (MOZ_UNLIKELY(mViewSource)) {
1538 mViewSource->AddErrorToCurrentRun("errNonSpaceAfterBody");
1539 }
1540 }
1541
errNonSpaceInColgroupInFragment()1542 void nsHtml5TreeBuilder::errNonSpaceInColgroupInFragment() {
1543 if (MOZ_UNLIKELY(mViewSource)) {
1544 mViewSource->AddErrorToCurrentRun("errNonSpaceInColgroupInFragment");
1545 }
1546 }
1547
errNonSpaceInNoscriptInHead()1548 void nsHtml5TreeBuilder::errNonSpaceInNoscriptInHead() {
1549 if (MOZ_UNLIKELY(mViewSource)) {
1550 mViewSource->AddErrorToCurrentRun("errNonSpaceInNoscriptInHead");
1551 }
1552 }
1553
errFooBetweenHeadAndBody(nsAtom * aName)1554 void nsHtml5TreeBuilder::errFooBetweenHeadAndBody(nsAtom* aName) {
1555 if (MOZ_UNLIKELY(mViewSource)) {
1556 mViewSource->AddErrorToCurrentRun("errFooBetweenHeadAndBody", aName);
1557 }
1558 }
1559
errStartTagWithoutDoctype()1560 void nsHtml5TreeBuilder::errStartTagWithoutDoctype() {
1561 if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) {
1562 mViewSource->AddErrorToCurrentRun("errStartTagWithoutDoctype");
1563 }
1564 }
1565
errNoSelectInTableScope()1566 void nsHtml5TreeBuilder::errNoSelectInTableScope() {
1567 if (MOZ_UNLIKELY(mViewSource)) {
1568 mViewSource->AddErrorToCurrentRun("errNoSelectInTableScope");
1569 }
1570 }
1571
errStartSelectWhereEndSelectExpected()1572 void nsHtml5TreeBuilder::errStartSelectWhereEndSelectExpected() {
1573 if (MOZ_UNLIKELY(mViewSource)) {
1574 mViewSource->AddErrorToCurrentRun("errStartSelectWhereEndSelectExpected");
1575 }
1576 }
1577
errStartTagWithSelectOpen(nsAtom * aName)1578 void nsHtml5TreeBuilder::errStartTagWithSelectOpen(nsAtom* aName) {
1579 if (MOZ_UNLIKELY(mViewSource)) {
1580 mViewSource->AddErrorToCurrentRun("errStartTagWithSelectOpen", aName);
1581 }
1582 }
1583
errBadStartTagInNoscriptInHead(nsAtom * aName)1584 void nsHtml5TreeBuilder::errBadStartTagInNoscriptInHead(nsAtom* aName) {
1585 if (MOZ_UNLIKELY(mViewSource)) {
1586 mViewSource->AddErrorToCurrentRun("errBadStartTagInNoscriptInHead", aName);
1587 }
1588 }
1589
errImage()1590 void nsHtml5TreeBuilder::errImage() {
1591 if (MOZ_UNLIKELY(mViewSource)) {
1592 mViewSource->AddErrorToCurrentRun("errImage");
1593 }
1594 }
1595
errIsindex()1596 void nsHtml5TreeBuilder::errIsindex() {
1597 if (MOZ_UNLIKELY(mViewSource)) {
1598 mViewSource->AddErrorToCurrentRun("errIsindex");
1599 }
1600 }
1601
errFooSeenWhenFooOpen(nsAtom * aName)1602 void nsHtml5TreeBuilder::errFooSeenWhenFooOpen(nsAtom* aName) {
1603 if (MOZ_UNLIKELY(mViewSource)) {
1604 mViewSource->AddErrorToCurrentRun("errFooSeenWhenFooOpen2", aName);
1605 }
1606 }
1607
errHeadingWhenHeadingOpen()1608 void nsHtml5TreeBuilder::errHeadingWhenHeadingOpen() {
1609 if (MOZ_UNLIKELY(mViewSource)) {
1610 mViewSource->AddErrorToCurrentRun("errHeadingWhenHeadingOpen");
1611 }
1612 }
1613
errFramesetStart()1614 void nsHtml5TreeBuilder::errFramesetStart() {
1615 if (MOZ_UNLIKELY(mViewSource)) {
1616 mViewSource->AddErrorToCurrentRun("errFramesetStart");
1617 }
1618 }
1619
errNoCellToClose()1620 void nsHtml5TreeBuilder::errNoCellToClose() {
1621 if (MOZ_UNLIKELY(mViewSource)) {
1622 mViewSource->AddErrorToCurrentRun("errNoCellToClose");
1623 }
1624 }
1625
errStartTagInTable(nsAtom * aName)1626 void nsHtml5TreeBuilder::errStartTagInTable(nsAtom* aName) {
1627 if (MOZ_UNLIKELY(mViewSource)) {
1628 mViewSource->AddErrorToCurrentRun("errStartTagInTable", aName);
1629 }
1630 }
1631
errFormWhenFormOpen()1632 void nsHtml5TreeBuilder::errFormWhenFormOpen() {
1633 if (MOZ_UNLIKELY(mViewSource)) {
1634 mViewSource->AddErrorToCurrentRun("errFormWhenFormOpen");
1635 }
1636 }
1637
errTableSeenWhileTableOpen()1638 void nsHtml5TreeBuilder::errTableSeenWhileTableOpen() {
1639 if (MOZ_UNLIKELY(mViewSource)) {
1640 mViewSource->AddErrorToCurrentRun("errTableSeenWhileTableOpen");
1641 }
1642 }
1643
errStartTagInTableBody(nsAtom * aName)1644 void nsHtml5TreeBuilder::errStartTagInTableBody(nsAtom* aName) {
1645 if (MOZ_UNLIKELY(mViewSource)) {
1646 mViewSource->AddErrorToCurrentRun("errStartTagInTableBody", aName);
1647 }
1648 }
1649
errEndTagSeenWithoutDoctype()1650 void nsHtml5TreeBuilder::errEndTagSeenWithoutDoctype() {
1651 if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) {
1652 mViewSource->AddErrorToCurrentRun("errEndTagSeenWithoutDoctype");
1653 }
1654 }
1655
errEndTagAfterBody()1656 void nsHtml5TreeBuilder::errEndTagAfterBody() {
1657 if (MOZ_UNLIKELY(mViewSource)) {
1658 mViewSource->AddErrorToCurrentRun("errEndTagAfterBody");
1659 }
1660 }
1661
errEndTagSeenWithSelectOpen(nsAtom * aName)1662 void nsHtml5TreeBuilder::errEndTagSeenWithSelectOpen(nsAtom* aName) {
1663 if (MOZ_UNLIKELY(mViewSource)) {
1664 mViewSource->AddErrorToCurrentRun("errEndTagSeenWithSelectOpen", aName);
1665 }
1666 }
1667
errGarbageInColgroup()1668 void nsHtml5TreeBuilder::errGarbageInColgroup() {
1669 if (MOZ_UNLIKELY(mViewSource)) {
1670 mViewSource->AddErrorToCurrentRun("errGarbageInColgroup");
1671 }
1672 }
1673
errEndTagBr()1674 void nsHtml5TreeBuilder::errEndTagBr() {
1675 if (MOZ_UNLIKELY(mViewSource)) {
1676 mViewSource->AddErrorToCurrentRun("errEndTagBr");
1677 }
1678 }
1679
errNoElementToCloseButEndTagSeen(nsAtom * aName)1680 void nsHtml5TreeBuilder::errNoElementToCloseButEndTagSeen(nsAtom* aName) {
1681 if (MOZ_UNLIKELY(mViewSource)) {
1682 mViewSource->AddErrorToCurrentRun("errNoElementToCloseButEndTagSeen",
1683 aName);
1684 }
1685 }
1686
errHtmlStartTagInForeignContext(nsAtom * aName)1687 void nsHtml5TreeBuilder::errHtmlStartTagInForeignContext(nsAtom* aName) {
1688 if (MOZ_UNLIKELY(mViewSource)) {
1689 mViewSource->AddErrorToCurrentRun("errHtmlStartTagInForeignContext", aName);
1690 }
1691 }
1692
errNoTableRowToClose()1693 void nsHtml5TreeBuilder::errNoTableRowToClose() {
1694 if (MOZ_UNLIKELY(mViewSource)) {
1695 mViewSource->AddErrorToCurrentRun("errNoTableRowToClose");
1696 }
1697 }
1698
errNonSpaceInTable()1699 void nsHtml5TreeBuilder::errNonSpaceInTable() {
1700 if (MOZ_UNLIKELY(mViewSource)) {
1701 mViewSource->AddErrorToCurrentRun("errNonSpaceInTable");
1702 }
1703 }
1704
errUnclosedChildrenInRuby()1705 void nsHtml5TreeBuilder::errUnclosedChildrenInRuby() {
1706 if (MOZ_UNLIKELY(mViewSource)) {
1707 mViewSource->AddErrorToCurrentRun("errUnclosedChildrenInRuby");
1708 }
1709 }
1710
errStartTagSeenWithoutRuby(nsAtom * aName)1711 void nsHtml5TreeBuilder::errStartTagSeenWithoutRuby(nsAtom* aName) {
1712 if (MOZ_UNLIKELY(mViewSource)) {
1713 mViewSource->AddErrorToCurrentRun("errStartTagSeenWithoutRuby", aName);
1714 }
1715 }
1716
errSelfClosing()1717 void nsHtml5TreeBuilder::errSelfClosing() {
1718 if (MOZ_UNLIKELY(mViewSource)) {
1719 mViewSource->AddErrorToCurrentSlash("errSelfClosing");
1720 }
1721 }
1722
errNoCheckUnclosedElementsOnStack()1723 void nsHtml5TreeBuilder::errNoCheckUnclosedElementsOnStack() {
1724 if (MOZ_UNLIKELY(mViewSource)) {
1725 mViewSource->AddErrorToCurrentRun("errNoCheckUnclosedElementsOnStack");
1726 }
1727 }
1728
errEndTagDidNotMatchCurrentOpenElement(nsAtom * aName,nsAtom * aOther)1729 void nsHtml5TreeBuilder::errEndTagDidNotMatchCurrentOpenElement(
1730 nsAtom* aName, nsAtom* aOther) {
1731 if (MOZ_UNLIKELY(mViewSource)) {
1732 mViewSource->AddErrorToCurrentRun("errEndTagDidNotMatchCurrentOpenElement",
1733 aName, aOther);
1734 }
1735 }
1736
errEndTagViolatesNestingRules(nsAtom * aName)1737 void nsHtml5TreeBuilder::errEndTagViolatesNestingRules(nsAtom* aName) {
1738 if (MOZ_UNLIKELY(mViewSource)) {
1739 mViewSource->AddErrorToCurrentRun("errEndTagViolatesNestingRules", aName);
1740 }
1741 }
1742
errEndWithUnclosedElements(nsAtom * aName)1743 void nsHtml5TreeBuilder::errEndWithUnclosedElements(nsAtom* aName) {
1744 if (MOZ_UNLIKELY(mViewSource)) {
1745 mViewSource->AddErrorToCurrentRun("errEndWithUnclosedElements", aName);
1746 }
1747 }
1748