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 "nsIPresShell.h"
9 #include "nsNodeUtils.h"
10 #include "nsIFrame.h"
11 #include "mozilla/Likely.h"
12 #include "mozilla/UniquePtr.h"
13 
nsHtml5TreeBuilder(nsHtml5OplessBuilder * aBuilder)14 nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsHtml5OplessBuilder* aBuilder)
15   : scriptingEnabled(false)
16   , fragment(false)
17   , contextName(nullptr)
18   , contextNamespace(kNameSpaceID_None)
19   , contextNode(nullptr)
20   , formPointer(nullptr)
21   , headPointer(nullptr)
22   , mBuilder(aBuilder)
23   , mViewSource(nullptr)
24   , mOpSink(nullptr)
25   , mHandles(nullptr)
26   , mHandlesUsed(0)
27   , mSpeculativeLoadStage(nullptr)
28   , mBroken(NS_OK)
29   , mCurrentHtmlScriptIsAsyncOrDefer(false)
30   , mPreventScriptExecution(false)
31 #ifdef DEBUG
32   , mActive(false)
33 #endif
34 {
35   MOZ_COUNT_CTOR(nsHtml5TreeBuilder);
36 }
37 
nsHtml5TreeBuilder(nsAHtml5TreeOpSink * aOpSink,nsHtml5TreeOpStage * aStage)38 nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsAHtml5TreeOpSink* aOpSink,
39                                        nsHtml5TreeOpStage* aStage)
40   : scriptingEnabled(false)
41   , fragment(false)
42   , contextName(nullptr)
43   , contextNamespace(kNameSpaceID_None)
44   , contextNode(nullptr)
45   , formPointer(nullptr)
46   , headPointer(nullptr)
47   , mBuilder(nullptr)
48   , mViewSource(nullptr)
49   , mOpSink(aOpSink)
50   , mHandles(new nsIContent*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH])
51   , mHandlesUsed(0)
52   , mSpeculativeLoadStage(aStage)
53   , mBroken(NS_OK)
54   , mCurrentHtmlScriptIsAsyncOrDefer(false)
55   , mPreventScriptExecution(false)
56 #ifdef DEBUG
57   , mActive(false)
58 #endif
59 {
60   MOZ_COUNT_CTOR(nsHtml5TreeBuilder);
61 }
62 
~nsHtml5TreeBuilder()63 nsHtml5TreeBuilder::~nsHtml5TreeBuilder()
64 {
65   MOZ_COUNT_DTOR(nsHtml5TreeBuilder);
66   NS_ASSERTION(!mActive, "nsHtml5TreeBuilder deleted without ever calling end() on it!");
67   mOpQueue.Clear();
68 }
69 
70 nsIContentHandle*
createElement(int32_t aNamespace,nsIAtom * aName,nsHtml5HtmlAttributes * aAttributes,nsIContentHandle * aIntendedParent)71 nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
72                                   nsHtml5HtmlAttributes* aAttributes,
73                                   nsIContentHandle* aIntendedParent)
74 {
75   NS_PRECONDITION(aAttributes, "Got null attributes.");
76   NS_PRECONDITION(aName, "Got null name.");
77   NS_PRECONDITION(aNamespace == kNameSpaceID_XHTML ||
78                   aNamespace == kNameSpaceID_SVG ||
79                   aNamespace == kNameSpaceID_MathML,
80                   "Bogus namespace.");
81 
82   if (mBuilder) {
83     nsCOMPtr<nsIAtom> name = nsHtml5TreeOperation::Reget(aName);
84 
85     nsIContent* intendedParent = aIntendedParent ?
86       static_cast<nsIContent*>(aIntendedParent) : nullptr;
87 
88     // intendedParent == nullptr is a special case where the
89     // intended parent is the document.
90     nsNodeInfoManager* nodeInfoManager = intendedParent ?
91        intendedParent->OwnerDoc()->NodeInfoManager() :
92        mBuilder->GetNodeInfoManager();
93 
94     nsIContent* elem =
95       nsHtml5TreeOperation::CreateElement(aNamespace,
96                                           name,
97                                           aAttributes,
98                                           mozilla::dom::FROM_PARSER_FRAGMENT,
99                                           nodeInfoManager,
100                                           mBuilder);
101     if (MOZ_UNLIKELY(aAttributes != tokenizer->GetAttributes() &&
102                      aAttributes != nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES)) {
103       delete aAttributes;
104     }
105     return elem;
106   }
107 
108   nsIContentHandle* content = AllocateContentHandle();
109   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
110   NS_ASSERTION(treeOp, "Tree op allocation failed.");
111   treeOp->Init(aNamespace,
112                aName,
113                aAttributes,
114                content,
115                aIntendedParent,
116                !!mSpeculativeLoadStage);
117   // mSpeculativeLoadStage is non-null only in the off-the-main-thread
118   // tree builder, which handles the network stream
119 
120   // Start wall of code for speculative loading and line numbers
121 
122   if (mSpeculativeLoadStage) {
123     switch (aNamespace) {
124       case kNameSpaceID_XHTML:
125         if (nsHtml5Atoms::img == aName) {
126           nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC);
127           nsString* srcset =
128             aAttributes->getValue(nsHtml5AttributeName::ATTR_SRCSET);
129           nsString* crossOrigin =
130             aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
131           nsString* referrerPolicy =
132             aAttributes->getValue(nsHtml5AttributeName::ATTR_REFERRERPOLICY);
133           nsString* sizes =
134             aAttributes->getValue(nsHtml5AttributeName::ATTR_SIZES);
135           mSpeculativeLoadQueue.AppendElement()->
136             InitImage(url ? *url : NullString(),
137                       crossOrigin ? *crossOrigin : NullString(),
138                       referrerPolicy ? *referrerPolicy : NullString(),
139                       srcset ? *srcset : NullString(),
140                       sizes ? *sizes : NullString());
141         } else if (nsHtml5Atoms::source == aName) {
142           nsString* srcset =
143             aAttributes->getValue(nsHtml5AttributeName::ATTR_SRCSET);
144           // Sources without srcset cannot be selected. The source could also be
145           // for a media element, but in that context doesn't use srcset.  See
146           // comments in nsHtml5SpeculativeLoad.h about <picture> preloading
147           if (srcset) {
148             nsString* sizes =
149               aAttributes->getValue(nsHtml5AttributeName::ATTR_SIZES);
150             nsString* type =
151               aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
152             nsString* media =
153               aAttributes->getValue(nsHtml5AttributeName::ATTR_MEDIA);
154             mSpeculativeLoadQueue.AppendElement()->
155               InitPictureSource(*srcset,
156                                 sizes ? *sizes : NullString(),
157                                 type ? *type : NullString(),
158                                 media ? *media : NullString());
159           }
160         } else if (nsHtml5Atoms::script == aName) {
161           nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
162           NS_ASSERTION(treeOp, "Tree op allocation failed.");
163           treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, content, tokenizer->getLineNumber());
164 
165           nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC);
166           if (url) {
167             nsString* charset = aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
168             nsString* type = aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
169             nsString* crossOrigin =
170               aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
171             nsString* integrity =
172               aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
173             mSpeculativeLoadQueue.AppendElement()->
174               InitScript(*url,
175                          (charset) ? *charset : EmptyString(),
176                          (type) ? *type : EmptyString(),
177                          (crossOrigin) ? *crossOrigin : NullString(),
178                          (integrity) ? *integrity : NullString(),
179                          mode == NS_HTML5TREE_BUILDER_IN_HEAD);
180             mCurrentHtmlScriptIsAsyncOrDefer =
181               aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC) ||
182               aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER);
183           }
184         } else if (nsHtml5Atoms::link == aName) {
185           nsString* rel = aAttributes->getValue(nsHtml5AttributeName::ATTR_REL);
186           // Not splitting on space here is bogus but the old parser didn't even
187           // do a case-insensitive check.
188           if (rel) {
189             if (rel->LowerCaseEqualsASCII("stylesheet")) {
190               nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
191               if (url) {
192                 nsString* charset = aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
193                 nsString* crossOrigin =
194                   aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
195                 nsString* integrity =
196                   aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
197                 mSpeculativeLoadQueue.AppendElement()->
198                   InitStyle(*url,
199                             (charset) ? *charset : EmptyString(),
200                             (crossOrigin) ? *crossOrigin : NullString(),
201                             (integrity) ? *integrity : NullString());
202               }
203             } else if (rel->LowerCaseEqualsASCII("preconnect")) {
204               nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
205               if (url) {
206                 nsString* crossOrigin =
207                   aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
208                 mSpeculativeLoadQueue.AppendElement()->
209                   InitPreconnect(*url, (crossOrigin) ? *crossOrigin : NullString());
210               }
211             }
212           }
213         } else if (nsHtml5Atoms::video == aName) {
214           nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_POSTER);
215           if (url) {
216             mSpeculativeLoadQueue.AppendElement()->InitImage(*url, NullString(),
217                                                              NullString(),
218                                                              NullString(),
219                                                              NullString());
220           }
221         } else if (nsHtml5Atoms::style == aName) {
222           nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
223           NS_ASSERTION(treeOp, "Tree op allocation failed.");
224           treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
225         } else if (nsHtml5Atoms::html == aName) {
226           nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST);
227           if (url) {
228             mSpeculativeLoadQueue.AppendElement()->InitManifest(*url);
229           } else {
230             mSpeculativeLoadQueue.AppendElement()->InitManifest(EmptyString());
231           }
232         } else if (nsHtml5Atoms::base == aName) {
233           nsString* url =
234               aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
235           if (url) {
236             mSpeculativeLoadQueue.AppendElement()->InitBase(*url);
237           }
238         } else if (nsHtml5Atoms::meta == aName) {
239           if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
240                       "content-security-policy",
241                       aAttributes->getValue(nsHtml5AttributeName::ATTR_HTTP_EQUIV))) {
242             nsString* csp = aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
243             if (csp) {
244               mSpeculativeLoadQueue.AppendElement()->InitMetaCSP(*csp);
245             }
246           }
247           else if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
248                       "referrer",
249                       aAttributes->getValue(nsHtml5AttributeName::ATTR_NAME))) {
250             nsString* referrerPolicy = aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
251             if (referrerPolicy) {
252               mSpeculativeLoadQueue.AppendElement()->InitMetaReferrerPolicy(*referrerPolicy);
253             }
254           }
255         }
256         break;
257       case kNameSpaceID_SVG:
258         if (nsHtml5Atoms::image == aName) {
259           nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
260           if (url) {
261             mSpeculativeLoadQueue.AppendElement()->InitImage(*url, NullString(),
262                                                              NullString(),
263                                                              NullString(),
264                                                              NullString());
265           }
266         } else if (nsHtml5Atoms::script == aName) {
267           nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
268           NS_ASSERTION(treeOp, "Tree op allocation failed.");
269           treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, content, tokenizer->getLineNumber());
270 
271           nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
272           if (url) {
273             nsString* type = aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
274             nsString* crossOrigin =
275               aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
276             nsString* integrity =
277               aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
278             mSpeculativeLoadQueue.AppendElement()->
279               InitScript(*url,
280                          EmptyString(),
281                          (type) ? *type : EmptyString(),
282                          (crossOrigin) ? *crossOrigin : NullString(),
283                          (integrity) ? *integrity : NullString(),
284                          mode == NS_HTML5TREE_BUILDER_IN_HEAD);
285           }
286         } else if (nsHtml5Atoms::style == aName) {
287           nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
288           NS_ASSERTION(treeOp, "Tree op allocation failed.");
289           treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
290 
291           nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
292           if (url) {
293             nsString* crossOrigin =
294               aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
295             nsString* integrity =
296               aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
297             mSpeculativeLoadQueue.AppendElement()->
298               InitStyle(*url, EmptyString(),
299                         (crossOrigin) ? *crossOrigin : NullString(),
300                         (integrity) ? *integrity : NullString());
301           }
302         }
303         break;
304     }
305   } else if (aNamespace != kNameSpaceID_MathML) {
306     // No speculative loader--just line numbers and defer/async check
307     if (nsHtml5Atoms::style == aName) {
308       nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
309       NS_ASSERTION(treeOp, "Tree op allocation failed.");
310       treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
311     } else if (nsHtml5Atoms::script == aName) {
312       nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
313       NS_ASSERTION(treeOp, "Tree op allocation failed.");
314       treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, content, tokenizer->getLineNumber());
315       if (aNamespace == kNameSpaceID_XHTML) {
316         mCurrentHtmlScriptIsAsyncOrDefer =
317           aAttributes->contains(nsHtml5AttributeName::ATTR_SRC) &&
318           (aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC) ||
319            aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER));
320       }
321     } else if (aNamespace == kNameSpaceID_XHTML) {
322       if (nsHtml5Atoms::html == aName) {
323         nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST);
324         nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
325         NS_ASSERTION(treeOp, "Tree op allocation failed.");
326         if (url) {
327           treeOp->Init(eTreeOpProcessOfflineManifest, *url);
328         } else {
329           treeOp->Init(eTreeOpProcessOfflineManifest, EmptyString());
330         }
331       } else if (nsHtml5Atoms::base == aName && mViewSource) {
332         nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
333         if (url) {
334           mViewSource->AddBase(*url);
335         }
336       }
337     }
338   }
339 
340   // End wall of code for speculative loading
341 
342   return content;
343 }
344 
345 nsIContentHandle*
createElement(int32_t aNamespace,nsIAtom * aName,nsHtml5HtmlAttributes * aAttributes,nsIContentHandle * aFormElement,nsIContentHandle * aIntendedParent)346 nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
347                                   nsHtml5HtmlAttributes* aAttributes,
348                                   nsIContentHandle* aFormElement,
349                                   nsIContentHandle* aIntendedParent)
350 {
351   nsIContentHandle* content = createElement(aNamespace, aName, aAttributes,
352                                             aIntendedParent);
353   if (aFormElement) {
354     if (mBuilder) {
355       nsHtml5TreeOperation::SetFormElement(static_cast<nsIContent*>(content),
356         static_cast<nsIContent*>(aFormElement));
357     } else {
358       nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
359       NS_ASSERTION(treeOp, "Tree op allocation failed.");
360       treeOp->Init(eTreeOpSetFormElement, content, aFormElement);
361     }
362   }
363   return content;
364 }
365 
366 nsIContentHandle*
createHtmlElementSetAsRoot(nsHtml5HtmlAttributes * aAttributes)367 nsHtml5TreeBuilder::createHtmlElementSetAsRoot(nsHtml5HtmlAttributes* aAttributes)
368 {
369   nsIContentHandle* content = createElement(kNameSpaceID_XHTML,
370                                             nsHtml5Atoms::html,
371                                             aAttributes,
372                                             nullptr);
373   if (mBuilder) {
374     nsresult rv = nsHtml5TreeOperation::AppendToDocument(static_cast<nsIContent*>(content),
375                                                          mBuilder);
376     if (NS_FAILED(rv)) {
377       MarkAsBrokenAndRequestSuspension(rv);
378     }
379   } else {
380     nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
381     NS_ASSERTION(treeOp, "Tree op allocation failed.");
382     treeOp->Init(eTreeOpAppendToDocument, content);
383   }
384   return content;
385 }
386 
387 nsIContentHandle*
createAndInsertFosterParentedElement(int32_t aNamespace,nsIAtom * aName,nsHtml5HtmlAttributes * aAttributes,nsIContentHandle * aFormElement,nsIContentHandle * aTable,nsIContentHandle * aStackParent)388 nsHtml5TreeBuilder::createAndInsertFosterParentedElement(int32_t aNamespace, nsIAtom* aName,
389                                                          nsHtml5HtmlAttributes* aAttributes,
390                                                          nsIContentHandle* aFormElement,
391                                                          nsIContentHandle* aTable,
392                                                          nsIContentHandle* aStackParent)
393 {
394   NS_PRECONDITION(aTable, "Null table");
395   NS_PRECONDITION(aStackParent, "Null stack parent");
396 
397   if (mBuilder) {
398     // Get the foster parent to use as the intended parent when creating
399     // the child element.
400     nsIContent* fosterParent = nsHtml5TreeOperation::GetFosterParent(
401       static_cast<nsIContent*>(aTable),
402       static_cast<nsIContent*>(aStackParent));
403 
404     nsIContentHandle* child = createElement(aNamespace, aName, aAttributes,
405       aFormElement, fosterParent);
406 
407     insertFosterParentedChild(child, aTable, aStackParent);
408 
409     return child;
410   }
411 
412   // Tree op to get the foster parent that we use as the intended parent
413   // when creating the child element.
414   nsHtml5TreeOperation* fosterParentTreeOp = mOpQueue.AppendElement();
415   NS_ASSERTION(fosterParentTreeOp, "Tree op allocation failed.");
416   nsIContentHandle* fosterParentHandle = AllocateContentHandle();
417   fosterParentTreeOp->Init(eTreeOpGetFosterParent, aTable,
418                            aStackParent, fosterParentHandle);
419 
420   // Create the element with the correct intended parent.
421   nsIContentHandle* child = createElement(aNamespace, aName, aAttributes,
422     aFormElement, fosterParentHandle);
423 
424   // Insert the child into the foster parent.
425   insertFosterParentedChild(child, aTable, aStackParent);
426 
427   return child;
428 }
429 
430 void
detachFromParent(nsIContentHandle * aElement)431 nsHtml5TreeBuilder::detachFromParent(nsIContentHandle* aElement)
432 {
433   NS_PRECONDITION(aElement, "Null element");
434 
435   if (mBuilder) {
436     nsHtml5TreeOperation::Detach(static_cast<nsIContent*>(aElement),
437                                  mBuilder);
438     return;
439   }
440 
441   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
442   NS_ASSERTION(treeOp, "Tree op allocation failed.");
443   treeOp->Init(eTreeOpDetach, aElement);
444 }
445 
446 void
appendElement(nsIContentHandle * aChild,nsIContentHandle * aParent)447 nsHtml5TreeBuilder::appendElement(nsIContentHandle* aChild, nsIContentHandle* aParent)
448 {
449   NS_PRECONDITION(aChild, "Null child");
450   NS_PRECONDITION(aParent, "Null parent");
451   if (deepTreeSurrogateParent) {
452     return;
453   }
454 
455   if (mBuilder) {
456     nsresult rv = nsHtml5TreeOperation::Append(static_cast<nsIContent*>(aChild),
457                                                static_cast<nsIContent*>(aParent),
458                                                mBuilder);
459     if (NS_FAILED(rv)) {
460       MarkAsBrokenAndRequestSuspension(rv);
461     }
462     return;
463   }
464 
465   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
466   NS_ASSERTION(treeOp, "Tree op allocation failed.");
467   treeOp->Init(eTreeOpAppend, aChild, aParent);
468 }
469 
470 void
appendChildrenToNewParent(nsIContentHandle * aOldParent,nsIContentHandle * aNewParent)471 nsHtml5TreeBuilder::appendChildrenToNewParent(nsIContentHandle* aOldParent, nsIContentHandle* aNewParent)
472 {
473   NS_PRECONDITION(aOldParent, "Null old parent");
474   NS_PRECONDITION(aNewParent, "Null new parent");
475 
476   if (mBuilder) {
477     nsresult rv = nsHtml5TreeOperation::AppendChildrenToNewParent(
478       static_cast<nsIContent*>(aOldParent),
479       static_cast<nsIContent*>(aNewParent),
480       mBuilder);
481     if (NS_FAILED(rv)) {
482       MarkAsBrokenAndRequestSuspension(rv);
483     }
484     return;
485   }
486 
487   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
488   NS_ASSERTION(treeOp, "Tree op allocation failed.");
489   treeOp->Init(eTreeOpAppendChildrenToNewParent, aOldParent, aNewParent);
490 }
491 
492 void
insertFosterParentedCharacters(char16_t * aBuffer,int32_t aStart,int32_t aLength,nsIContentHandle * aTable,nsIContentHandle * aStackParent)493 nsHtml5TreeBuilder::insertFosterParentedCharacters(char16_t* aBuffer, int32_t aStart, int32_t aLength, nsIContentHandle* aTable, nsIContentHandle* aStackParent)
494 {
495   NS_PRECONDITION(aBuffer, "Null buffer");
496   NS_PRECONDITION(aTable, "Null table");
497   NS_PRECONDITION(aStackParent, "Null stack parent");
498   MOZ_ASSERT(!aStart, "aStart must always be zero.");
499 
500   if (mBuilder) {
501     nsresult rv = nsHtml5TreeOperation::FosterParentText(
502       static_cast<nsIContent*>(aStackParent),
503       aBuffer, // XXX aStart always ignored???
504       aLength,
505       static_cast<nsIContent*>(aTable),
506       mBuilder);
507     if (NS_FAILED(rv)) {
508       MarkAsBrokenAndRequestSuspension(rv);
509     }
510     return;
511   }
512 
513   char16_t* bufferCopy = new (mozilla::fallible) char16_t[aLength];
514   if (!bufferCopy) {
515     // Just assigning mBroken instead of generating tree op. The caller
516     // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
517     mBroken = NS_ERROR_OUT_OF_MEMORY;
518     requestSuspension();
519     return;
520   }
521 
522   memcpy(bufferCopy, aBuffer, aLength * sizeof(char16_t));
523 
524   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
525   NS_ASSERTION(treeOp, "Tree op allocation failed.");
526   treeOp->Init(eTreeOpFosterParentText, bufferCopy, aLength, aStackParent, aTable);
527 }
528 
529 void
insertFosterParentedChild(nsIContentHandle * aChild,nsIContentHandle * aTable,nsIContentHandle * aStackParent)530 nsHtml5TreeBuilder::insertFosterParentedChild(nsIContentHandle* aChild, nsIContentHandle* aTable, nsIContentHandle* aStackParent)
531 {
532   NS_PRECONDITION(aChild, "Null child");
533   NS_PRECONDITION(aTable, "Null table");
534   NS_PRECONDITION(aStackParent, "Null stack parent");
535 
536   if (mBuilder) {
537     nsresult rv = nsHtml5TreeOperation::FosterParent(
538       static_cast<nsIContent*>(aChild),
539       static_cast<nsIContent*>(aStackParent),
540       static_cast<nsIContent*>(aTable),
541       mBuilder);
542     if (NS_FAILED(rv)) {
543       MarkAsBrokenAndRequestSuspension(rv);
544     }
545     return;
546   }
547 
548   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
549   NS_ASSERTION(treeOp, "Tree op allocation failed.");
550   treeOp->Init(eTreeOpFosterParent, aChild, aStackParent, aTable);
551 }
552 
553 void
appendCharacters(nsIContentHandle * aParent,char16_t * aBuffer,int32_t aStart,int32_t aLength)554 nsHtml5TreeBuilder::appendCharacters(nsIContentHandle* aParent, char16_t* aBuffer, int32_t aStart, int32_t aLength)
555 {
556   NS_PRECONDITION(aBuffer, "Null buffer");
557   NS_PRECONDITION(aParent, "Null parent");
558   MOZ_ASSERT(!aStart, "aStart must always be zero.");
559 
560   if (mBuilder) {
561     nsresult rv = nsHtml5TreeOperation::AppendText(
562       aBuffer, // XXX aStart always ignored???
563       aLength,
564       static_cast<nsIContent*>(deepTreeSurrogateParent ?
565                                deepTreeSurrogateParent : aParent),
566       mBuilder);
567     if (NS_FAILED(rv)) {
568       MarkAsBrokenAndRequestSuspension(rv);
569     }
570     return;
571   }
572 
573   char16_t* bufferCopy = new (mozilla::fallible) char16_t[aLength];
574   if (!bufferCopy) {
575     // Just assigning mBroken instead of generating tree op. The caller
576     // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
577     mBroken = NS_ERROR_OUT_OF_MEMORY;
578     requestSuspension();
579     return;
580   }
581 
582   memcpy(bufferCopy, aBuffer, aLength * sizeof(char16_t));
583 
584   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
585   NS_ASSERTION(treeOp, "Tree op allocation failed.");
586   treeOp->Init(eTreeOpAppendText, bufferCopy, aLength,
587       deepTreeSurrogateParent ? deepTreeSurrogateParent : aParent);
588 }
589 
590 void
appendIsindexPrompt(nsIContentHandle * aParent)591 nsHtml5TreeBuilder::appendIsindexPrompt(nsIContentHandle* aParent)
592 {
593   NS_PRECONDITION(aParent, "Null parent");
594 
595   if (mBuilder) {
596     nsresult rv = nsHtml5TreeOperation::AppendIsindexPrompt(
597       static_cast<nsIContent*>(aParent),
598       mBuilder);
599     if (NS_FAILED(rv)) {
600       MarkAsBrokenAndRequestSuspension(rv);
601     }
602     return;
603   }
604 
605   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
606   NS_ASSERTION(treeOp, "Tree op allocation failed.");
607   treeOp->Init(eTreeOpAppendIsindexPrompt, aParent);
608 }
609 
610 void
appendComment(nsIContentHandle * aParent,char16_t * aBuffer,int32_t aStart,int32_t aLength)611 nsHtml5TreeBuilder::appendComment(nsIContentHandle* aParent, char16_t* aBuffer, int32_t aStart, int32_t aLength)
612 {
613   NS_PRECONDITION(aBuffer, "Null buffer");
614   NS_PRECONDITION(aParent, "Null parent");
615   MOZ_ASSERT(!aStart, "aStart must always be zero.");
616 
617   if (deepTreeSurrogateParent) {
618     return;
619   }
620 
621   if (mBuilder) {
622     nsresult rv = nsHtml5TreeOperation::AppendComment(
623       static_cast<nsIContent*>(aParent),
624       aBuffer, // XXX aStart always ignored???
625       aLength,
626       mBuilder);
627     if (NS_FAILED(rv)) {
628       MarkAsBrokenAndRequestSuspension(rv);
629     }
630     return;
631   }
632 
633   char16_t* bufferCopy = new (mozilla::fallible) char16_t[aLength];
634   if (!bufferCopy) {
635     // Just assigning mBroken instead of generating tree op. The caller
636     // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
637     mBroken = NS_ERROR_OUT_OF_MEMORY;
638     requestSuspension();
639     return;
640   }
641 
642   memcpy(bufferCopy, aBuffer, aLength * sizeof(char16_t));
643 
644   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
645   NS_ASSERTION(treeOp, "Tree op allocation failed.");
646   treeOp->Init(eTreeOpAppendComment, bufferCopy, aLength, aParent);
647 }
648 
649 void
appendCommentToDocument(char16_t * aBuffer,int32_t aStart,int32_t aLength)650 nsHtml5TreeBuilder::appendCommentToDocument(char16_t* aBuffer, int32_t aStart, int32_t aLength)
651 {
652   NS_PRECONDITION(aBuffer, "Null buffer");
653   MOZ_ASSERT(!aStart, "aStart must always be zero.");
654 
655   if (mBuilder) {
656     nsresult rv = nsHtml5TreeOperation::AppendCommentToDocument(
657       aBuffer, // XXX aStart always ignored???
658       aLength,
659       mBuilder);
660     if (NS_FAILED(rv)) {
661       MarkAsBrokenAndRequestSuspension(rv);
662     }
663     return;
664   }
665 
666   char16_t* bufferCopy = new (mozilla::fallible) char16_t[aLength];
667   if (!bufferCopy) {
668     // Just assigning mBroken instead of generating tree op. The caller
669     // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
670     mBroken = NS_ERROR_OUT_OF_MEMORY;
671     requestSuspension();
672     return;
673   }
674 
675   memcpy(bufferCopy, aBuffer, aLength * sizeof(char16_t));
676 
677   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
678   NS_ASSERTION(treeOp, "Tree op allocation failed.");
679   treeOp->Init(eTreeOpAppendCommentToDocument, bufferCopy, aLength);
680 }
681 
682 void
addAttributesToElement(nsIContentHandle * aElement,nsHtml5HtmlAttributes * aAttributes)683 nsHtml5TreeBuilder::addAttributesToElement(nsIContentHandle* aElement, nsHtml5HtmlAttributes* aAttributes)
684 {
685   NS_PRECONDITION(aElement, "Null element");
686   NS_PRECONDITION(aAttributes, "Null attributes");
687 
688   if (aAttributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
689     return;
690   }
691 
692   if (mBuilder) {
693     MOZ_ASSERT(aAttributes == tokenizer->GetAttributes(),
694       "Using attribute other than the tokenizer's to add to body or html.");
695     nsresult rv = nsHtml5TreeOperation::AddAttributes(
696       static_cast<nsIContent*>(aElement),
697       aAttributes,
698       mBuilder);
699     if (NS_FAILED(rv)) {
700       MarkAsBrokenAndRequestSuspension(rv);
701     }
702     return;
703   }
704 
705   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
706   NS_ASSERTION(treeOp, "Tree op allocation failed.");
707   treeOp->Init(aElement, aAttributes);
708 }
709 
710 void
markMalformedIfScript(nsIContentHandle * aElement)711 nsHtml5TreeBuilder::markMalformedIfScript(nsIContentHandle* aElement)
712 {
713   NS_PRECONDITION(aElement, "Null element");
714 
715   if (mBuilder) {
716     nsHtml5TreeOperation::MarkMalformedIfScript(
717       static_cast<nsIContent*>(aElement));
718     return;
719   }
720 
721   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
722   NS_ASSERTION(treeOp, "Tree op allocation failed.");
723   treeOp->Init(eTreeOpMarkMalformedIfScript, aElement);
724 }
725 
726 void
start(bool fragment)727 nsHtml5TreeBuilder::start(bool fragment)
728 {
729   mCurrentHtmlScriptIsAsyncOrDefer = false;
730   deepTreeSurrogateParent = nullptr;
731 #ifdef DEBUG
732   mActive = true;
733 #endif
734 }
735 
736 void
end()737 nsHtml5TreeBuilder::end()
738 {
739   mOpQueue.Clear();
740 #ifdef DEBUG
741   mActive = false;
742 #endif
743 }
744 
745 void
appendDoctypeToDocument(nsIAtom * aName,nsString * aPublicId,nsString * aSystemId)746 nsHtml5TreeBuilder::appendDoctypeToDocument(nsIAtom* aName, nsString* aPublicId, nsString* aSystemId)
747 {
748   NS_PRECONDITION(aName, "Null name");
749 
750   if (mBuilder) {
751     nsCOMPtr<nsIAtom> name = nsHtml5TreeOperation::Reget(aName);
752     nsresult rv =
753       nsHtml5TreeOperation::AppendDoctypeToDocument(name,
754                                                     *aPublicId,
755                                                     *aSystemId,
756                                                     mBuilder);
757     if (NS_FAILED(rv)) {
758       MarkAsBrokenAndRequestSuspension(rv);
759     }
760     return;
761   }
762 
763   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
764   NS_ASSERTION(treeOp, "Tree op allocation failed.");
765   treeOp->Init(aName, *aPublicId, *aSystemId);
766   // nsXMLContentSink can flush here, but what's the point?
767   // It can also interrupt here, but we can't.
768 }
769 
770 void
elementPushed(int32_t aNamespace,nsIAtom * aName,nsIContentHandle * aElement)771 nsHtml5TreeBuilder::elementPushed(int32_t aNamespace, nsIAtom* aName, nsIContentHandle* aElement)
772 {
773   NS_ASSERTION(aNamespace == kNameSpaceID_XHTML || aNamespace == kNameSpaceID_SVG || aNamespace == kNameSpaceID_MathML, "Element isn't HTML, SVG or MathML!");
774   NS_ASSERTION(aName, "Element doesn't have local name!");
775   NS_ASSERTION(aElement, "No element!");
776   /*
777    * The frame constructor uses recursive algorithms, so it can't deal with
778    * arbitrarily deep trees. This is especially a problem on Windows where
779    * the permitted depth of the runtime stack is rather small.
780    *
781    * The following is a protection against author incompetence--not against
782    * malice. There are other ways to make the DOM deep anyway.
783    *
784    * The basic idea is that when the tree builder stack gets too deep,
785    * append operations no longer append to the node that the HTML parsing
786    * algorithm says they should but instead text nodes are append to the last
787    * element that was seen before a magic tree builder stack threshold was
788    * reached and element and comment nodes aren't appended to the DOM at all.
789    *
790    * However, for security reasons, non-child descendant text nodes inside an
791    * SVG script or style element should not become children. Also, non-cell
792    * table elements shouldn't be used as surrogate parents for user experience
793    * reasons.
794    */
795   if (!deepTreeSurrogateParent && currentPtr >= MAX_REFLOW_DEPTH &&
796       !(aName == nsHtml5Atoms::script ||
797         aName == nsHtml5Atoms::table ||
798         aName == nsHtml5Atoms::thead ||
799         aName == nsHtml5Atoms::tfoot ||
800         aName == nsHtml5Atoms::tbody ||
801         aName == nsHtml5Atoms::tr ||
802         aName == nsHtml5Atoms::colgroup ||
803         aName == nsHtml5Atoms::style)) {
804     deepTreeSurrogateParent = aElement;
805   }
806   if (aNamespace != kNameSpaceID_XHTML) {
807     return;
808   }
809   if (aName == nsHtml5Atoms::body || aName == nsHtml5Atoms::frameset) {
810     if (mBuilder) {
811       // InnerHTML and DOMParser shouldn't start layout anyway
812       return;
813     }
814     nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
815     NS_ASSERTION(treeOp, "Tree op allocation failed.");
816     treeOp->Init(eTreeOpStartLayout);
817     return;
818   }
819   if (aName == nsHtml5Atoms::input ||
820       aName == nsHtml5Atoms::button) {
821     if (mBuilder) {
822       nsHtml5TreeOperation::DoneCreatingElement(static_cast<nsIContent*>(aElement));
823     } else {
824       mOpQueue.AppendElement()->Init(eTreeOpDoneCreatingElement, aElement);
825     }
826     return;
827   }
828   if (aName == nsHtml5Atoms::audio ||
829       aName == nsHtml5Atoms::video ||
830       aName == nsHtml5Atoms::menuitem) {
831     if (mBuilder) {
832       nsHtml5TreeOperation::DoneCreatingElement(static_cast<nsIContent*>(aElement));
833     } else {
834       mOpQueue.AppendElement()->Init(eTreeOpDoneCreatingElement, aElement);
835     }
836     return;
837   }
838   if (mSpeculativeLoadStage && aName == nsHtml5Atoms::picture) {
839     // mSpeculativeLoadStage is non-null only in the off-the-main-thread
840     // tree builder, which handles the network stream
841     //
842     // See comments in nsHtml5SpeculativeLoad.h about <picture> preloading
843     mSpeculativeLoadQueue.AppendElement()->InitOpenPicture();
844   }
845 }
846 
847 void
elementPopped(int32_t aNamespace,nsIAtom * aName,nsIContentHandle * aElement)848 nsHtml5TreeBuilder::elementPopped(int32_t aNamespace, nsIAtom* aName, nsIContentHandle* aElement)
849 {
850   NS_ASSERTION(aNamespace == kNameSpaceID_XHTML || aNamespace == kNameSpaceID_SVG || aNamespace == kNameSpaceID_MathML, "Element isn't HTML, SVG or MathML!");
851   NS_ASSERTION(aName, "Element doesn't have local name!");
852   NS_ASSERTION(aElement, "No element!");
853   if (deepTreeSurrogateParent && currentPtr <= MAX_REFLOW_DEPTH) {
854     deepTreeSurrogateParent = nullptr;
855   }
856   if (aNamespace == kNameSpaceID_MathML) {
857     return;
858   }
859   // we now have only SVG and HTML
860   if (aName == nsHtml5Atoms::script) {
861     if (mPreventScriptExecution) {
862       if (mBuilder) {
863         nsHtml5TreeOperation::PreventScriptExecution(static_cast<nsIContent*>(aElement));
864         return;
865       }
866       mOpQueue.AppendElement()->Init(eTreeOpPreventScriptExecution, aElement);
867       return;
868     }
869     if (mBuilder) {
870       return;
871     }
872     if (mCurrentHtmlScriptIsAsyncOrDefer) {
873       NS_ASSERTION(aNamespace == kNameSpaceID_XHTML,
874                    "Only HTML scripts may be async/defer.");
875       nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
876       NS_ASSERTION(treeOp, "Tree op allocation failed.");
877       treeOp->Init(eTreeOpRunScriptAsyncDefer, aElement);
878       mCurrentHtmlScriptIsAsyncOrDefer = false;
879       return;
880     }
881     requestSuspension();
882     nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
883     NS_ASSERTION(treeOp, "Tree op allocation failed.");
884     treeOp->InitScript(aElement);
885     return;
886   }
887   if (aName == nsHtml5Atoms::title) {
888     if (mBuilder) {
889       nsHtml5TreeOperation::DoneAddingChildren(static_cast<nsIContent*>(aElement));
890       return;
891     }
892     nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
893     NS_ASSERTION(treeOp, "Tree op allocation failed.");
894     treeOp->Init(eTreeOpDoneAddingChildren, aElement);
895     return;
896   }
897   if (aName == nsHtml5Atoms::style || (aNamespace == kNameSpaceID_XHTML && aName == nsHtml5Atoms::link)) {
898     if (mBuilder) {
899       MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(),
900         "Scripts must be blocked.");
901       mBuilder->UpdateStyleSheet(static_cast<nsIContent*>(aElement));
902       return;
903     }
904     nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
905     NS_ASSERTION(treeOp, "Tree op allocation failed.");
906     treeOp->Init(eTreeOpUpdateStyleSheet, aElement);
907     return;
908   }
909   if (aNamespace == kNameSpaceID_SVG) {
910     if (aName == nsHtml5Atoms::svg) {
911       if (mBuilder) {
912         nsHtml5TreeOperation::SvgLoad(static_cast<nsIContent*>(aElement));
913         return;
914       }
915       nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
916       NS_ASSERTION(treeOp, "Tree op allocation failed.");
917       treeOp->Init(eTreeOpSvgLoad, aElement);
918     }
919     return;
920   }
921   // we now have only HTML
922   // Some HTML nodes need DoneAddingChildren() called to initialize
923   // properly (e.g. form state restoration).
924   // XXX expose ElementName group here and do switch
925   if (aName == nsHtml5Atoms::object ||
926       aName == nsHtml5Atoms::applet ||
927       aName == nsHtml5Atoms::select ||
928       aName == nsHtml5Atoms::textarea ||
929       aName == nsHtml5Atoms::output) {
930     if (mBuilder) {
931       nsHtml5TreeOperation::DoneAddingChildren(static_cast<nsIContent*>(aElement));
932       return;
933     }
934     nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
935     NS_ASSERTION(treeOp, "Tree op allocation failed.");
936     treeOp->Init(eTreeOpDoneAddingChildren, aElement);
937     return;
938   }
939   if (aName == nsHtml5Atoms::meta && !fragment && !mBuilder) {
940     nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
941     NS_ASSERTION(treeOp, "Tree op allocation failed.");
942     treeOp->Init(eTreeOpProcessMeta, aElement);
943     return;
944   }
945   if (mSpeculativeLoadStage && aName == nsHtml5Atoms::picture) {
946     // mSpeculativeLoadStage is non-null only in the off-the-main-thread
947     // tree builder, which handles the network stream
948     //
949     // See comments in nsHtml5SpeculativeLoad.h about <picture> preloading
950     mSpeculativeLoadQueue.AppendElement()->InitEndPicture();
951   }
952   return;
953 }
954 
955 void
accumulateCharacters(const char16_t * aBuf,int32_t aStart,int32_t aLength)956 nsHtml5TreeBuilder::accumulateCharacters(const char16_t* aBuf, int32_t aStart, int32_t aLength)
957 {
958   MOZ_RELEASE_ASSERT(charBufferLen + aLength <= charBuffer.length,
959                      "About to memcpy past the end of the buffer!");
960   memcpy(charBuffer + charBufferLen, aBuf + aStart, sizeof(char16_t) * aLength);
961   charBufferLen += aLength;
962 }
963 
964 // INT32_MAX is (2^31)-1. Therefore, the highest power-of-two that fits
965 // is 2^30. Note that this is counting char16_t units. The underlying
966 // bytes will be twice that, but they fit even in 32-bit size_t even
967 // if a contiguous chunk of memory of that size is pretty unlikely to
968 // be available on a 32-bit system.
969 #define MAX_POWER_OF_TWO_IN_INT32 0x40000000
970 
971 bool
EnsureBufferSpace(int32_t aLength)972 nsHtml5TreeBuilder::EnsureBufferSpace(int32_t aLength)
973 {
974   // TODO: Unify nsHtml5Tokenizer::strBuf and nsHtml5TreeBuilder::charBuffer
975   // so that this method becomes unnecessary.
976   CheckedInt<int32_t> worstCase(charBufferLen);
977   worstCase += aLength;
978   if (!worstCase.isValid()) {
979     return false;
980   }
981   if (worstCase.value() > MAX_POWER_OF_TWO_IN_INT32) {
982     return false;
983   }
984   if (!charBuffer) {
985     if (worstCase.value() < MAX_POWER_OF_TWO_IN_INT32) {
986       // Add one to round to the next power of two to avoid immediate
987       // reallocation once there are a few characters in the buffer.
988       worstCase += 1;
989     }
990     charBuffer = jArray<char16_t,int32_t>::newFallibleJArray(mozilla::RoundUpPow2(worstCase.value()));
991     if (!charBuffer) {
992       return false;
993     }
994   } else if (worstCase.value() > charBuffer.length) {
995     jArray<char16_t,int32_t> newBuf = jArray<char16_t,int32_t>::newFallibleJArray(mozilla::RoundUpPow2(worstCase.value()));
996     if (!newBuf) {
997       return false;
998     }
999     memcpy(newBuf, charBuffer, sizeof(char16_t) * size_t(charBufferLen));
1000     charBuffer = newBuf;
1001   }
1002   return true;
1003 }
1004 
1005 nsIContentHandle*
AllocateContentHandle()1006 nsHtml5TreeBuilder::AllocateContentHandle()
1007 {
1008   if (MOZ_UNLIKELY(mBuilder)) {
1009     MOZ_ASSERT_UNREACHABLE("Must never allocate a handle with builder.");
1010     return nullptr;
1011   }
1012   if (mHandlesUsed == NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH) {
1013     mOldHandles.AppendElement(Move(mHandles));
1014     mHandles = MakeUnique<nsIContent*[]>(NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH);
1015     mHandlesUsed = 0;
1016   }
1017 #ifdef DEBUG
1018   mHandles[mHandlesUsed] = reinterpret_cast<nsIContent*>(uintptr_t(0xC0DEDBAD));
1019 #endif
1020   return &mHandles[mHandlesUsed++];
1021 }
1022 
1023 bool
HasScript()1024 nsHtml5TreeBuilder::HasScript()
1025 {
1026   uint32_t len = mOpQueue.Length();
1027   if (!len) {
1028     return false;
1029   }
1030   return mOpQueue.ElementAt(len - 1).IsRunScript();
1031 }
1032 
1033 bool
Flush(bool aDiscretionary)1034 nsHtml5TreeBuilder::Flush(bool aDiscretionary)
1035 {
1036   if (MOZ_UNLIKELY(mBuilder)) {
1037     MOZ_ASSERT_UNREACHABLE("Must never flush with builder.");
1038     return false;
1039   }
1040   if (NS_SUCCEEDED(mBroken)) {
1041     if (!aDiscretionary ||
1042         !(charBufferLen &&
1043           currentPtr >= 0 &&
1044           stack[currentPtr]->isFosterParenting())) {
1045       // Don't flush text on discretionary flushes if the current element on
1046       // the stack is a foster-parenting element and there's pending text,
1047       // because flushing in that case would make the tree shape dependent on
1048       // where the flush points fall.
1049       flushCharacters();
1050     }
1051     FlushLoads();
1052   }
1053   if (mOpSink) {
1054     bool hasOps = !mOpQueue.IsEmpty();
1055     if (hasOps) {
1056       // If the builder is broken and mOpQueue is not empty, there must be
1057       // one op and it must be eTreeOpMarkAsBroken.
1058       if (NS_FAILED(mBroken)) {
1059         MOZ_ASSERT(mOpQueue.Length() == 1,
1060           "Tree builder is broken with a non-empty op queue whose length isn't 1.");
1061         MOZ_ASSERT(mOpQueue[0].IsMarkAsBroken(),
1062           "Tree builder is broken but the op in queue is not marked as broken.");
1063       }
1064       mOpSink->MoveOpsFrom(mOpQueue);
1065     }
1066     return hasOps;
1067   }
1068   // no op sink: throw away ops
1069   mOpQueue.Clear();
1070   return false;
1071 }
1072 
1073 void
FlushLoads()1074 nsHtml5TreeBuilder::FlushLoads()
1075 {
1076   if (MOZ_UNLIKELY(mBuilder)) {
1077     MOZ_ASSERT_UNREACHABLE("Must never flush loads with builder.");
1078     return;
1079   }
1080   if (!mSpeculativeLoadQueue.IsEmpty()) {
1081     mSpeculativeLoadStage->MoveSpeculativeLoadsFrom(mSpeculativeLoadQueue);
1082   }
1083 }
1084 
1085 void
SetDocumentCharset(nsACString & aCharset,int32_t aCharsetSource)1086 nsHtml5TreeBuilder::SetDocumentCharset(nsACString& aCharset,
1087                                        int32_t aCharsetSource)
1088 {
1089   if (mBuilder) {
1090     mBuilder->SetDocumentCharsetAndSource(aCharset, aCharsetSource);
1091   } else if (mSpeculativeLoadStage) {
1092     mSpeculativeLoadQueue.AppendElement()->InitSetDocumentCharset(
1093       aCharset, aCharsetSource);
1094   } else {
1095     mOpQueue.AppendElement()->Init(
1096       eTreeOpSetDocumentCharset, aCharset, aCharsetSource);
1097   }
1098 }
1099 
1100 void
StreamEnded()1101 nsHtml5TreeBuilder::StreamEnded()
1102 {
1103   MOZ_ASSERT(!mBuilder, "Must not call StreamEnded with builder.");
1104   MOZ_ASSERT(!fragment, "Must not parse fragments off the main thread.");
1105   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
1106   NS_ASSERTION(treeOp, "Tree op allocation failed.");
1107   treeOp->Init(eTreeOpStreamEnded);
1108 }
1109 
1110 void
NeedsCharsetSwitchTo(const nsACString & aCharset,int32_t aCharsetSource,int32_t aLineNumber)1111 nsHtml5TreeBuilder::NeedsCharsetSwitchTo(const nsACString& aCharset,
1112                                          int32_t aCharsetSource,
1113                                          int32_t aLineNumber)
1114 {
1115   if (MOZ_UNLIKELY(mBuilder)) {
1116     MOZ_ASSERT_UNREACHABLE("Must never switch charset with builder.");
1117     return;
1118   }
1119   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
1120   NS_ASSERTION(treeOp, "Tree op allocation failed.");
1121   treeOp->Init(eTreeOpNeedsCharsetSwitchTo,
1122                aCharset,
1123                aCharsetSource,
1124                aLineNumber);
1125 }
1126 
1127 void
MaybeComplainAboutCharset(const char * aMsgId,bool aError,int32_t aLineNumber)1128 nsHtml5TreeBuilder::MaybeComplainAboutCharset(const char* aMsgId,
1129                                               bool aError,
1130                                               int32_t aLineNumber)
1131 {
1132   if (MOZ_UNLIKELY(mBuilder)) {
1133     MOZ_ASSERT_UNREACHABLE("Must never complain about charset with builder.");
1134     return;
1135   }
1136   mOpQueue.AppendElement()->Init(aMsgId, aError, aLineNumber);
1137 }
1138 
1139 void
AddSnapshotToScript(nsAHtml5TreeBuilderState * aSnapshot,int32_t aLine)1140 nsHtml5TreeBuilder::AddSnapshotToScript(nsAHtml5TreeBuilderState* aSnapshot, int32_t aLine)
1141 {
1142   if (MOZ_UNLIKELY(mBuilder)) {
1143     MOZ_ASSERT_UNREACHABLE("Must never use snapshots with builder.");
1144     return;
1145   }
1146   NS_PRECONDITION(HasScript(), "No script to add a snapshot to!");
1147   NS_PRECONDITION(aSnapshot, "Got null snapshot.");
1148   mOpQueue.ElementAt(mOpQueue.Length() - 1).SetSnapshot(aSnapshot, aLine);
1149 }
1150 
1151 void
DropHandles()1152 nsHtml5TreeBuilder::DropHandles()
1153 {
1154   MOZ_ASSERT(!mBuilder, "Must not drop handles with builder.");
1155   mOldHandles.Clear();
1156   mHandlesUsed = 0;
1157 }
1158 
1159 void
MarkAsBroken(nsresult aRv)1160 nsHtml5TreeBuilder::MarkAsBroken(nsresult aRv)
1161 {
1162   if (MOZ_UNLIKELY(mBuilder)) {
1163     MOZ_ASSERT_UNREACHABLE("Must not call this with builder.");
1164     return;
1165   }
1166   mBroken = aRv;
1167   mOpQueue.Clear(); // Previous ops don't matter anymore
1168   mOpQueue.AppendElement()->Init(aRv);
1169 }
1170 
1171 void
MarkAsBrokenFromPortability(nsresult aRv)1172 nsHtml5TreeBuilder::MarkAsBrokenFromPortability(nsresult aRv)
1173 {
1174   if (mBuilder) {
1175     MarkAsBrokenAndRequestSuspension(aRv);
1176     return;
1177   }
1178   mBroken = aRv;
1179   requestSuspension();
1180 }
1181 
1182 void
StartPlainTextViewSource(const nsAutoString & aTitle)1183 nsHtml5TreeBuilder::StartPlainTextViewSource(const nsAutoString& aTitle)
1184 {
1185   MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
1186   startTag(nsHtml5ElementName::ELT_TITLE,
1187            nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES,
1188            false);
1189 
1190   // XUL will add the "Source of: " prefix.
1191   uint32_t length = aTitle.Length();
1192   if (length > INT32_MAX) {
1193     length = INT32_MAX;
1194   }
1195   characters(aTitle.get(), 0, (int32_t)length);
1196   endTag(nsHtml5ElementName::ELT_TITLE);
1197 
1198   startTag(nsHtml5ElementName::ELT_LINK,
1199            nsHtml5ViewSourceUtils::NewLinkAttributes(),
1200            false);
1201 
1202   startTag(nsHtml5ElementName::ELT_BODY,
1203            nsHtml5ViewSourceUtils::NewBodyAttributes(),
1204            false);
1205 
1206   StartPlainTextBody();
1207 }
1208 
1209 void
StartPlainText()1210 nsHtml5TreeBuilder::StartPlainText()
1211 {
1212   MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
1213   startTag(nsHtml5ElementName::ELT_LINK,
1214            nsHtml5PlainTextUtils::NewLinkAttributes(),
1215            false);
1216 
1217   StartPlainTextBody();
1218 }
1219 
1220 void
StartPlainTextBody()1221 nsHtml5TreeBuilder::StartPlainTextBody()
1222 {
1223   MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
1224   startTag(nsHtml5ElementName::ELT_PRE,
1225            nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES,
1226            false);
1227   needToDropLF = false;
1228 }
1229 
1230 // DocumentModeHandler
1231 void
documentMode(nsHtml5DocumentMode m)1232 nsHtml5TreeBuilder::documentMode(nsHtml5DocumentMode m)
1233 {
1234   if (mBuilder) {
1235     mBuilder->SetDocumentMode(m);
1236     return;
1237   }
1238   if (mSpeculativeLoadStage) {
1239     mSpeculativeLoadQueue.AppendElement()->InitSetDocumentMode(m);
1240     return;
1241   }
1242   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
1243   NS_ASSERTION(treeOp, "Tree op allocation failed.");
1244   treeOp->Init(m);
1245 }
1246 
1247 nsIContentHandle*
getDocumentFragmentForTemplate(nsIContentHandle * aTemplate)1248 nsHtml5TreeBuilder::getDocumentFragmentForTemplate(nsIContentHandle* aTemplate)
1249 {
1250   if (mBuilder) {
1251     return nsHtml5TreeOperation::GetDocumentFragmentForTemplate(static_cast<nsIContent*>(aTemplate));
1252   }
1253   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
1254   NS_ASSERTION(treeOp, "Tree op allocation failed.");
1255   nsIContentHandle* fragHandle = AllocateContentHandle();
1256   treeOp->Init(eTreeOpGetDocumentFragmentForTemplate, aTemplate, fragHandle);
1257   return fragHandle;
1258 }
1259 
1260 nsIContentHandle*
getFormPointerForContext(nsIContentHandle * aContext)1261 nsHtml5TreeBuilder::getFormPointerForContext(nsIContentHandle* aContext)
1262 {
1263   MOZ_ASSERT(mBuilder, "Must have builder.");
1264   if (!aContext) {
1265     return nullptr;
1266   }
1267 
1268   MOZ_ASSERT(NS_IsMainThread());
1269 
1270   // aContext must always be an element that already exists
1271   // in the document.
1272   nsIContent* contextNode = static_cast<nsIContent*>(aContext);
1273   nsIContent* currentAncestor = contextNode;
1274 
1275   // We traverse the ancestors of the context node to find the nearest
1276   // form pointer. This traversal is why aContext must not be an emtpy handle.
1277   nsIContent* nearestForm = nullptr;
1278   while (currentAncestor) {
1279     if (currentAncestor->IsHTMLElement(nsGkAtoms::form)) {
1280       nearestForm = currentAncestor;
1281       break;
1282     }
1283     currentAncestor = currentAncestor->GetParent();
1284   }
1285 
1286   if (!nearestForm) {
1287     return nullptr;
1288   }
1289 
1290   return nearestForm;
1291 }
1292 
1293 // Error reporting
1294 
1295 void
EnableViewSource(nsHtml5Highlighter * aHighlighter)1296 nsHtml5TreeBuilder::EnableViewSource(nsHtml5Highlighter* aHighlighter)
1297 {
1298   MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
1299   mViewSource = aHighlighter;
1300 }
1301 
1302 void
errStrayStartTag(nsIAtom * aName)1303 nsHtml5TreeBuilder::errStrayStartTag(nsIAtom* aName)
1304 {
1305   if (MOZ_UNLIKELY(mViewSource)) {
1306     mViewSource->AddErrorToCurrentRun("errStrayStartTag2", aName);
1307   }
1308 }
1309 
1310 void
errStrayEndTag(nsIAtom * aName)1311 nsHtml5TreeBuilder::errStrayEndTag(nsIAtom* aName)
1312 {
1313   if (MOZ_UNLIKELY(mViewSource)) {
1314     mViewSource->AddErrorToCurrentRun("errStrayEndTag", aName);
1315   }
1316 }
1317 
1318 void
errUnclosedElements(int32_t aIndex,nsIAtom * aName)1319 nsHtml5TreeBuilder::errUnclosedElements(int32_t aIndex, nsIAtom* aName)
1320 {
1321   if (MOZ_UNLIKELY(mViewSource)) {
1322     mViewSource->AddErrorToCurrentRun("errUnclosedElements", aName);
1323   }
1324 }
1325 
1326 void
errUnclosedElementsImplied(int32_t aIndex,nsIAtom * aName)1327 nsHtml5TreeBuilder::errUnclosedElementsImplied(int32_t aIndex, nsIAtom* aName)
1328 {
1329   if (MOZ_UNLIKELY(mViewSource)) {
1330     mViewSource->AddErrorToCurrentRun("errUnclosedElementsImplied",
1331         aName);
1332   }
1333 }
1334 
1335 void
errUnclosedElementsCell(int32_t aIndex)1336 nsHtml5TreeBuilder::errUnclosedElementsCell(int32_t aIndex)
1337 {
1338   if (MOZ_UNLIKELY(mViewSource)) {
1339     mViewSource->AddErrorToCurrentRun("errUnclosedElementsCell");
1340   }
1341 }
1342 
1343 void
errStrayDoctype()1344 nsHtml5TreeBuilder::errStrayDoctype()
1345 {
1346   if (MOZ_UNLIKELY(mViewSource)) {
1347     mViewSource->AddErrorToCurrentRun("errStrayDoctype");
1348   }
1349 }
1350 
1351 void
errAlmostStandardsDoctype()1352 nsHtml5TreeBuilder::errAlmostStandardsDoctype()
1353 {
1354   if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) {
1355     mViewSource->AddErrorToCurrentRun("errAlmostStandardsDoctype");
1356   }
1357 }
1358 
1359 void
errQuirkyDoctype()1360 nsHtml5TreeBuilder::errQuirkyDoctype()
1361 {
1362   if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) {
1363     mViewSource->AddErrorToCurrentRun("errQuirkyDoctype");
1364   }
1365 }
1366 
1367 void
errNonSpaceInTrailer()1368 nsHtml5TreeBuilder::errNonSpaceInTrailer()
1369 {
1370   if (MOZ_UNLIKELY(mViewSource)) {
1371     mViewSource->AddErrorToCurrentRun("errNonSpaceInTrailer");
1372   }
1373 }
1374 
1375 void
errNonSpaceAfterFrameset()1376 nsHtml5TreeBuilder::errNonSpaceAfterFrameset()
1377 {
1378   if (MOZ_UNLIKELY(mViewSource)) {
1379     mViewSource->AddErrorToCurrentRun("errNonSpaceAfterFrameset");
1380   }
1381 }
1382 
1383 void
errNonSpaceInFrameset()1384 nsHtml5TreeBuilder::errNonSpaceInFrameset()
1385 {
1386   if (MOZ_UNLIKELY(mViewSource)) {
1387     mViewSource->AddErrorToCurrentRun("errNonSpaceInFrameset");
1388   }
1389 }
1390 
1391 void
errNonSpaceAfterBody()1392 nsHtml5TreeBuilder::errNonSpaceAfterBody()
1393 {
1394   if (MOZ_UNLIKELY(mViewSource)) {
1395     mViewSource->AddErrorToCurrentRun("errNonSpaceAfterBody");
1396   }
1397 }
1398 
1399 void
errNonSpaceInColgroupInFragment()1400 nsHtml5TreeBuilder::errNonSpaceInColgroupInFragment()
1401 {
1402   if (MOZ_UNLIKELY(mViewSource)) {
1403     mViewSource->AddErrorToCurrentRun("errNonSpaceInColgroupInFragment");
1404   }
1405 }
1406 
1407 void
errNonSpaceInNoscriptInHead()1408 nsHtml5TreeBuilder::errNonSpaceInNoscriptInHead()
1409 {
1410   if (MOZ_UNLIKELY(mViewSource)) {
1411     mViewSource->AddErrorToCurrentRun("errNonSpaceInNoscriptInHead");
1412   }
1413 }
1414 
1415 void
errFooBetweenHeadAndBody(nsIAtom * aName)1416 nsHtml5TreeBuilder::errFooBetweenHeadAndBody(nsIAtom* aName)
1417 {
1418   if (MOZ_UNLIKELY(mViewSource)) {
1419     mViewSource->AddErrorToCurrentRun("errFooBetweenHeadAndBody", aName);
1420   }
1421 }
1422 
1423 void
errStartTagWithoutDoctype()1424 nsHtml5TreeBuilder::errStartTagWithoutDoctype()
1425 {
1426   if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) {
1427     mViewSource->AddErrorToCurrentRun("errStartTagWithoutDoctype");
1428   }
1429 }
1430 
1431 void
errNoSelectInTableScope()1432 nsHtml5TreeBuilder::errNoSelectInTableScope()
1433 {
1434   if (MOZ_UNLIKELY(mViewSource)) {
1435     mViewSource->AddErrorToCurrentRun("errNoSelectInTableScope");
1436   }
1437 }
1438 
1439 void
errStartSelectWhereEndSelectExpected()1440 nsHtml5TreeBuilder::errStartSelectWhereEndSelectExpected()
1441 {
1442   if (MOZ_UNLIKELY(mViewSource)) {
1443     mViewSource->AddErrorToCurrentRun(
1444         "errStartSelectWhereEndSelectExpected");
1445   }
1446 }
1447 
1448 void
errStartTagWithSelectOpen(nsIAtom * aName)1449 nsHtml5TreeBuilder::errStartTagWithSelectOpen(nsIAtom* aName)
1450 {
1451   if (MOZ_UNLIKELY(mViewSource)) {
1452     mViewSource->AddErrorToCurrentRun("errStartTagWithSelectOpen", aName);
1453   }
1454 }
1455 
1456 void
errBadStartTagInHead(nsIAtom * aName)1457 nsHtml5TreeBuilder::errBadStartTagInHead(nsIAtom* aName)
1458 {
1459   if (MOZ_UNLIKELY(mViewSource)) {
1460     mViewSource->AddErrorToCurrentRun("errBadStartTagInHead2", aName);
1461   }
1462 }
1463 
1464 void
errImage()1465 nsHtml5TreeBuilder::errImage()
1466 {
1467   if (MOZ_UNLIKELY(mViewSource)) {
1468     mViewSource->AddErrorToCurrentRun("errImage");
1469   }
1470 }
1471 
1472 void
errIsindex()1473 nsHtml5TreeBuilder::errIsindex()
1474 {
1475   if (MOZ_UNLIKELY(mViewSource)) {
1476     mViewSource->AddErrorToCurrentRun("errIsindex");
1477   }
1478 }
1479 
1480 void
errFooSeenWhenFooOpen(nsIAtom * aName)1481 nsHtml5TreeBuilder::errFooSeenWhenFooOpen(nsIAtom* aName)
1482 {
1483   if (MOZ_UNLIKELY(mViewSource)) {
1484     mViewSource->AddErrorToCurrentRun("errFooSeenWhenFooOpen", aName);
1485   }
1486 }
1487 
1488 void
errHeadingWhenHeadingOpen()1489 nsHtml5TreeBuilder::errHeadingWhenHeadingOpen()
1490 {
1491   if (MOZ_UNLIKELY(mViewSource)) {
1492     mViewSource->AddErrorToCurrentRun("errHeadingWhenHeadingOpen");
1493   }
1494 }
1495 
1496 void
errFramesetStart()1497 nsHtml5TreeBuilder::errFramesetStart()
1498 {
1499   if (MOZ_UNLIKELY(mViewSource)) {
1500     mViewSource->AddErrorToCurrentRun("errFramesetStart");
1501   }
1502 }
1503 
1504 void
errNoCellToClose()1505 nsHtml5TreeBuilder::errNoCellToClose()
1506 {
1507   if (MOZ_UNLIKELY(mViewSource)) {
1508     mViewSource->AddErrorToCurrentRun("errNoCellToClose");
1509   }
1510 }
1511 
1512 void
errStartTagInTable(nsIAtom * aName)1513 nsHtml5TreeBuilder::errStartTagInTable(nsIAtom* aName)
1514 {
1515   if (MOZ_UNLIKELY(mViewSource)) {
1516     mViewSource->AddErrorToCurrentRun("errStartTagInTable", aName);
1517   }
1518 }
1519 
1520 void
errFormWhenFormOpen()1521 nsHtml5TreeBuilder::errFormWhenFormOpen()
1522 {
1523   if (MOZ_UNLIKELY(mViewSource)) {
1524     mViewSource->AddErrorToCurrentRun("errFormWhenFormOpen");
1525   }
1526 }
1527 
1528 void
errTableSeenWhileTableOpen()1529 nsHtml5TreeBuilder::errTableSeenWhileTableOpen()
1530 {
1531   if (MOZ_UNLIKELY(mViewSource)) {
1532     mViewSource->AddErrorToCurrentRun("errTableSeenWhileTableOpen");
1533   }
1534 }
1535 
1536 void
errStartTagInTableBody(nsIAtom * aName)1537 nsHtml5TreeBuilder::errStartTagInTableBody(nsIAtom* aName)
1538 {
1539   if (MOZ_UNLIKELY(mViewSource)) {
1540     mViewSource->AddErrorToCurrentRun("errStartTagInTableBody", aName);
1541   }
1542 }
1543 
1544 void
errEndTagSeenWithoutDoctype()1545 nsHtml5TreeBuilder::errEndTagSeenWithoutDoctype()
1546 {
1547   if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) {
1548     mViewSource->AddErrorToCurrentRun("errEndTagSeenWithoutDoctype");
1549   }
1550 }
1551 
1552 void
errEndTagAfterBody()1553 nsHtml5TreeBuilder::errEndTagAfterBody()
1554 {
1555   if (MOZ_UNLIKELY(mViewSource)) {
1556     mViewSource->AddErrorToCurrentRun("errEndTagAfterBody");
1557   }
1558 }
1559 
1560 void
errEndTagSeenWithSelectOpen(nsIAtom * aName)1561 nsHtml5TreeBuilder::errEndTagSeenWithSelectOpen(nsIAtom* aName)
1562 {
1563   if (MOZ_UNLIKELY(mViewSource)) {
1564     mViewSource->AddErrorToCurrentRun("errEndTagSeenWithSelectOpen",
1565         aName);
1566   }
1567 }
1568 
1569 void
errGarbageInColgroup()1570 nsHtml5TreeBuilder::errGarbageInColgroup()
1571 {
1572   if (MOZ_UNLIKELY(mViewSource)) {
1573     mViewSource->AddErrorToCurrentRun("errGarbageInColgroup");
1574   }
1575 }
1576 
1577 void
errEndTagBr()1578 nsHtml5TreeBuilder::errEndTagBr()
1579 {
1580   if (MOZ_UNLIKELY(mViewSource)) {
1581     mViewSource->AddErrorToCurrentRun("errEndTagBr");
1582   }
1583 }
1584 
1585 void
errNoElementToCloseButEndTagSeen(nsIAtom * aName)1586 nsHtml5TreeBuilder::errNoElementToCloseButEndTagSeen(nsIAtom* aName)
1587 {
1588   if (MOZ_UNLIKELY(mViewSource)) {
1589     mViewSource->AddErrorToCurrentRun(
1590         "errNoElementToCloseButEndTagSeen", aName);
1591   }
1592 }
1593 
1594 void
errHtmlStartTagInForeignContext(nsIAtom * aName)1595 nsHtml5TreeBuilder::errHtmlStartTagInForeignContext(nsIAtom* aName)
1596 {
1597   if (MOZ_UNLIKELY(mViewSource)) {
1598     mViewSource->AddErrorToCurrentRun("errHtmlStartTagInForeignContext",
1599         aName);
1600   }
1601 }
1602 
1603 void
errTableClosedWhileCaptionOpen()1604 nsHtml5TreeBuilder::errTableClosedWhileCaptionOpen()
1605 {
1606   if (MOZ_UNLIKELY(mViewSource)) {
1607     mViewSource->AddErrorToCurrentRun("errTableClosedWhileCaptionOpen");
1608   }
1609 }
1610 
1611 void
errNoTableRowToClose()1612 nsHtml5TreeBuilder::errNoTableRowToClose()
1613 {
1614   if (MOZ_UNLIKELY(mViewSource)) {
1615     mViewSource->AddErrorToCurrentRun("errNoTableRowToClose");
1616   }
1617 }
1618 
1619 void
errNonSpaceInTable()1620 nsHtml5TreeBuilder::errNonSpaceInTable()
1621 {
1622   if (MOZ_UNLIKELY(mViewSource)) {
1623     mViewSource->AddErrorToCurrentRun("errNonSpaceInTable");
1624   }
1625 }
1626 
1627 void
errUnclosedChildrenInRuby()1628 nsHtml5TreeBuilder::errUnclosedChildrenInRuby()
1629 {
1630   if (MOZ_UNLIKELY(mViewSource)) {
1631     mViewSource->AddErrorToCurrentRun("errUnclosedChildrenInRuby");
1632   }
1633 }
1634 
1635 void
errStartTagSeenWithoutRuby(nsIAtom * aName)1636 nsHtml5TreeBuilder::errStartTagSeenWithoutRuby(nsIAtom* aName)
1637 {
1638   if (MOZ_UNLIKELY(mViewSource)) {
1639     mViewSource->AddErrorToCurrentRun("errStartTagSeenWithoutRuby",
1640         aName);
1641   }
1642 }
1643 
1644 void
errSelfClosing()1645 nsHtml5TreeBuilder::errSelfClosing()
1646 {
1647   if (MOZ_UNLIKELY(mViewSource)) {
1648     mViewSource->AddErrorToCurrentSlash("errSelfClosing");
1649   }
1650 }
1651 
1652 void
errNoCheckUnclosedElementsOnStack()1653 nsHtml5TreeBuilder::errNoCheckUnclosedElementsOnStack()
1654 {
1655   if (MOZ_UNLIKELY(mViewSource)) {
1656     mViewSource->AddErrorToCurrentRun(
1657         "errNoCheckUnclosedElementsOnStack");
1658   }
1659 }
1660 
1661 void
errEndTagDidNotMatchCurrentOpenElement(nsIAtom * aName,nsIAtom * aOther)1662 nsHtml5TreeBuilder::errEndTagDidNotMatchCurrentOpenElement(nsIAtom* aName,
1663                                                            nsIAtom* aOther)
1664 {
1665   if (MOZ_UNLIKELY(mViewSource)) {
1666     mViewSource->AddErrorToCurrentRun(
1667         "errEndTagDidNotMatchCurrentOpenElement", aName, aOther);
1668   }
1669 }
1670 
1671 void
errEndTagViolatesNestingRules(nsIAtom * aName)1672 nsHtml5TreeBuilder::errEndTagViolatesNestingRules(nsIAtom* aName)
1673 {
1674   if (MOZ_UNLIKELY(mViewSource)) {
1675     mViewSource->AddErrorToCurrentRun("errEndTagViolatesNestingRules", aName);
1676   }
1677 }
1678 
1679 void
errEndWithUnclosedElements(nsIAtom * aName)1680 nsHtml5TreeBuilder::errEndWithUnclosedElements(nsIAtom* aName)
1681 {
1682   if (MOZ_UNLIKELY(mViewSource)) {
1683     mViewSource->AddErrorToCurrentRun("errEndWithUnclosedElements", aName);
1684   }
1685 }
1686