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