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