Fri, 16 Jan 2015 18:13:44 +0100
Integrate suggestion from review to improve consistency with existing code.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=78: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsError.h"
8 #include "nsIPresShell.h"
9 #include "nsNodeUtils.h"
10 #include "nsIFrame.h"
11 #include "mozilla/Likely.h"
13 class nsPresContext;
15 nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsHtml5OplessBuilder* aBuilder)
16 : scriptingEnabled(false)
17 , fragment(false)
18 , contextNode(nullptr)
19 , formPointer(nullptr)
20 , headPointer(nullptr)
21 , mBuilder(aBuilder)
22 , mViewSource(nullptr)
23 , mOpSink(nullptr)
24 , mHandles(nullptr)
25 , mHandlesUsed(0)
26 , mSpeculativeLoadStage(nullptr)
27 , mCurrentHtmlScriptIsAsyncOrDefer(false)
28 , mPreventScriptExecution(false)
29 #ifdef DEBUG
30 , mActive(false)
31 #endif
32 {
33 MOZ_COUNT_CTOR(nsHtml5TreeBuilder);
34 }
36 nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsAHtml5TreeOpSink* aOpSink,
37 nsHtml5TreeOpStage* aStage)
38 : scriptingEnabled(false)
39 , fragment(false)
40 , contextNode(nullptr)
41 , formPointer(nullptr)
42 , headPointer(nullptr)
43 , mBuilder(nullptr)
44 , mViewSource(nullptr)
45 , mOpSink(aOpSink)
46 , mHandles(new nsIContent*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH])
47 , mHandlesUsed(0)
48 , mSpeculativeLoadStage(aStage)
49 , mCurrentHtmlScriptIsAsyncOrDefer(false)
50 , mPreventScriptExecution(false)
51 #ifdef DEBUG
52 , mActive(false)
53 #endif
54 {
55 MOZ_COUNT_CTOR(nsHtml5TreeBuilder);
56 }
58 nsHtml5TreeBuilder::~nsHtml5TreeBuilder()
59 {
60 MOZ_COUNT_DTOR(nsHtml5TreeBuilder);
61 NS_ASSERTION(!mActive, "nsHtml5TreeBuilder deleted without ever calling end() on it!");
62 mOpQueue.Clear();
63 }
65 nsIContentHandle*
66 nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName, nsHtml5HtmlAttributes* aAttributes)
67 {
68 NS_PRECONDITION(aAttributes, "Got null attributes.");
69 NS_PRECONDITION(aName, "Got null name.");
70 NS_PRECONDITION(aNamespace == kNameSpaceID_XHTML ||
71 aNamespace == kNameSpaceID_SVG ||
72 aNamespace == kNameSpaceID_MathML,
73 "Bogus namespace.");
75 if (mBuilder) {
76 nsCOMPtr<nsIAtom> name = nsHtml5TreeOperation::Reget(aName);
77 nsIContent* elem =
78 nsHtml5TreeOperation::CreateElement(aNamespace,
79 name,
80 aAttributes,
81 mozilla::dom::FROM_PARSER_FRAGMENT,
82 mBuilder);
83 if (MOZ_UNLIKELY(aAttributes != tokenizer->GetAttributes() &&
84 aAttributes != nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES)) {
85 delete aAttributes;
86 }
87 return elem;
88 }
90 nsIContentHandle* content = AllocateContentHandle();
91 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
92 NS_ASSERTION(treeOp, "Tree op allocation failed.");
93 treeOp->Init(aNamespace,
94 aName,
95 aAttributes,
96 content,
97 !!mSpeculativeLoadStage);
98 // mSpeculativeLoadStage is non-null only in the off-the-main-thread
99 // tree builder, which handles the network stream
101 // Start wall of code for speculative loading and line numbers
103 if (mSpeculativeLoadStage) {
104 switch (aNamespace) {
105 case kNameSpaceID_XHTML:
106 if (nsHtml5Atoms::img == aName) {
107 nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC);
108 if (url) {
109 nsString* crossOrigin =
110 aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
111 mSpeculativeLoadQueue.AppendElement()->
112 InitImage(*url,
113 crossOrigin ? *crossOrigin : NullString());
114 }
115 } else if (nsHtml5Atoms::script == aName) {
116 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
117 NS_ASSERTION(treeOp, "Tree op allocation failed.");
118 treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, content, tokenizer->getLineNumber());
120 nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC);
121 if (url) {
122 nsString* charset = aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
123 nsString* type = aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
124 nsString* crossOrigin =
125 aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
126 mSpeculativeLoadQueue.AppendElement()->
127 InitScript(*url,
128 (charset) ? *charset : EmptyString(),
129 (type) ? *type : EmptyString(),
130 (crossOrigin) ? *crossOrigin : NullString(),
131 mode == NS_HTML5TREE_BUILDER_IN_HEAD);
132 mCurrentHtmlScriptIsAsyncOrDefer =
133 aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC) ||
134 aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER);
135 }
136 } else if (nsHtml5Atoms::link == aName) {
137 nsString* rel = aAttributes->getValue(nsHtml5AttributeName::ATTR_REL);
138 // Not splitting on space here is bogus but the old parser didn't even
139 // do a case-insensitive check.
140 if (rel && rel->LowerCaseEqualsASCII("stylesheet")) {
141 nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
142 if (url) {
143 nsString* charset = aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
144 nsString* crossOrigin =
145 aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
146 mSpeculativeLoadQueue.AppendElement()->
147 InitStyle(*url,
148 (charset) ? *charset : EmptyString(),
149 (crossOrigin) ? *crossOrigin : NullString());
150 }
151 }
152 } else if (nsHtml5Atoms::video == aName) {
153 nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_POSTER);
154 if (url) {
155 mSpeculativeLoadQueue.AppendElement()->InitImage(*url, NullString());
156 }
157 } else if (nsHtml5Atoms::style == aName) {
158 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
159 NS_ASSERTION(treeOp, "Tree op allocation failed.");
160 treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
161 } else if (nsHtml5Atoms::html == aName) {
162 nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST);
163 if (url) {
164 mSpeculativeLoadQueue.AppendElement()->InitManifest(*url);
165 } else {
166 mSpeculativeLoadQueue.AppendElement()->InitManifest(EmptyString());
167 }
168 } else if (nsHtml5Atoms::base == aName) {
169 nsString* url =
170 aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
171 if (url) {
172 mSpeculativeLoadQueue.AppendElement()->InitBase(*url);
173 }
174 }
175 break;
176 case kNameSpaceID_SVG:
177 if (nsHtml5Atoms::image == aName) {
178 nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
179 if (url) {
180 mSpeculativeLoadQueue.AppendElement()->InitImage(*url, NullString());
181 }
182 } else if (nsHtml5Atoms::script == aName) {
183 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
184 NS_ASSERTION(treeOp, "Tree op allocation failed.");
185 treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, content, tokenizer->getLineNumber());
187 nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
188 if (url) {
189 nsString* type = aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
190 nsString* crossOrigin =
191 aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
192 mSpeculativeLoadQueue.AppendElement()->
193 InitScript(*url,
194 EmptyString(),
195 (type) ? *type : EmptyString(),
196 (crossOrigin) ? *crossOrigin : NullString(),
197 mode == NS_HTML5TREE_BUILDER_IN_HEAD);
198 }
199 } else if (nsHtml5Atoms::style == aName) {
200 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
201 NS_ASSERTION(treeOp, "Tree op allocation failed.");
202 treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
204 nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
205 if (url) {
206 nsString* crossOrigin =
207 aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
208 mSpeculativeLoadQueue.AppendElement()->
209 InitStyle(*url, EmptyString(),
210 (crossOrigin) ? *crossOrigin : NullString());
211 }
212 }
213 break;
214 }
215 } else if (aNamespace != kNameSpaceID_MathML) {
216 // No speculative loader--just line numbers and defer/async check
217 if (nsHtml5Atoms::style == aName) {
218 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
219 NS_ASSERTION(treeOp, "Tree op allocation failed.");
220 treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
221 } else if (nsHtml5Atoms::script == aName) {
222 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
223 NS_ASSERTION(treeOp, "Tree op allocation failed.");
224 treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, content, tokenizer->getLineNumber());
225 if (aNamespace == kNameSpaceID_XHTML) {
226 mCurrentHtmlScriptIsAsyncOrDefer =
227 aAttributes->contains(nsHtml5AttributeName::ATTR_SRC) &&
228 (aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC) ||
229 aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER));
230 }
231 } else if (aNamespace == kNameSpaceID_XHTML && nsHtml5Atoms::html == aName) {
232 nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST);
233 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
234 NS_ASSERTION(treeOp, "Tree op allocation failed.");
235 if (url) {
236 treeOp->Init(eTreeOpProcessOfflineManifest, *url);
237 } else {
238 treeOp->Init(eTreeOpProcessOfflineManifest, EmptyString());
239 }
240 }
241 }
243 // End wall of code for speculative loading
245 return content;
246 }
248 nsIContentHandle*
249 nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName, nsHtml5HtmlAttributes* aAttributes, nsIContentHandle* aFormElement)
250 {
251 nsIContentHandle* content = createElement(aNamespace, aName, aAttributes);
252 if (aFormElement) {
253 if (mBuilder) {
254 nsHtml5TreeOperation::SetFormElement(static_cast<nsIContent*>(content),
255 static_cast<nsIContent*>(aFormElement));
256 } else {
257 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
258 NS_ASSERTION(treeOp, "Tree op allocation failed.");
259 treeOp->Init(eTreeOpSetFormElement, content, aFormElement);
260 }
261 }
262 return content;
263 }
265 nsIContentHandle*
266 nsHtml5TreeBuilder::createHtmlElementSetAsRoot(nsHtml5HtmlAttributes* aAttributes)
267 {
268 nsIContentHandle* content = createElement(kNameSpaceID_XHTML, nsHtml5Atoms::html, aAttributes);
269 if (mBuilder) {
270 nsresult rv = nsHtml5TreeOperation::AppendToDocument(static_cast<nsIContent*>(content),
271 mBuilder);
272 if (NS_FAILED(rv)) {
273 MarkAsBrokenAndRequestSuspension(rv);
274 }
275 } else {
276 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
277 NS_ASSERTION(treeOp, "Tree op allocation failed.");
278 treeOp->Init(eTreeOpAppendToDocument, content);
279 }
280 return content;
281 }
283 void
284 nsHtml5TreeBuilder::detachFromParent(nsIContentHandle* aElement)
285 {
286 NS_PRECONDITION(aElement, "Null element");
288 if (mBuilder) {
289 nsHtml5TreeOperation::Detach(static_cast<nsIContent*>(aElement),
290 mBuilder);
291 return;
292 }
294 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
295 NS_ASSERTION(treeOp, "Tree op allocation failed.");
296 treeOp->Init(eTreeOpDetach, aElement);
297 }
299 void
300 nsHtml5TreeBuilder::appendElement(nsIContentHandle* aChild, nsIContentHandle* aParent)
301 {
302 NS_PRECONDITION(aChild, "Null child");
303 NS_PRECONDITION(aParent, "Null parent");
304 if (deepTreeSurrogateParent) {
305 return;
306 }
308 if (mBuilder) {
309 nsresult rv = nsHtml5TreeOperation::Append(static_cast<nsIContent*>(aChild),
310 static_cast<nsIContent*>(aParent),
311 mBuilder);
312 if (NS_FAILED(rv)) {
313 MarkAsBrokenAndRequestSuspension(rv);
314 }
315 return;
316 }
318 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
319 NS_ASSERTION(treeOp, "Tree op allocation failed.");
320 treeOp->Init(eTreeOpAppend, aChild, aParent);
321 }
323 void
324 nsHtml5TreeBuilder::appendChildrenToNewParent(nsIContentHandle* aOldParent, nsIContentHandle* aNewParent)
325 {
326 NS_PRECONDITION(aOldParent, "Null old parent");
327 NS_PRECONDITION(aNewParent, "Null new parent");
329 if (mBuilder) {
330 nsresult rv = nsHtml5TreeOperation::AppendChildrenToNewParent(
331 static_cast<nsIContent*>(aOldParent),
332 static_cast<nsIContent*>(aNewParent),
333 mBuilder);
334 if (NS_FAILED(rv)) {
335 MarkAsBrokenAndRequestSuspension(rv);
336 }
337 return;
338 }
340 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
341 NS_ASSERTION(treeOp, "Tree op allocation failed.");
342 treeOp->Init(eTreeOpAppendChildrenToNewParent, aOldParent, aNewParent);
343 }
345 void
346 nsHtml5TreeBuilder::insertFosterParentedCharacters(char16_t* aBuffer, int32_t aStart, int32_t aLength, nsIContentHandle* aTable, nsIContentHandle* aStackParent)
347 {
348 NS_PRECONDITION(aBuffer, "Null buffer");
349 NS_PRECONDITION(aTable, "Null table");
350 NS_PRECONDITION(aStackParent, "Null stack parent");
351 MOZ_ASSERT(!aStart, "aStart must always be zero.");
353 if (mBuilder) {
354 nsresult rv = nsHtml5TreeOperation::FosterParentText(
355 static_cast<nsIContent*>(aStackParent),
356 aBuffer, // XXX aStart always ignored???
357 aLength,
358 static_cast<nsIContent*>(aTable),
359 mBuilder);
360 if (NS_FAILED(rv)) {
361 MarkAsBrokenAndRequestSuspension(rv);
362 }
363 return;
364 }
366 char16_t* bufferCopy = new char16_t[aLength];
367 memcpy(bufferCopy, aBuffer, aLength * sizeof(char16_t));
369 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
370 NS_ASSERTION(treeOp, "Tree op allocation failed.");
371 treeOp->Init(eTreeOpFosterParentText, bufferCopy, aLength, aStackParent, aTable);
372 }
374 void
375 nsHtml5TreeBuilder::insertFosterParentedChild(nsIContentHandle* aChild, nsIContentHandle* aTable, nsIContentHandle* aStackParent)
376 {
377 NS_PRECONDITION(aChild, "Null child");
378 NS_PRECONDITION(aTable, "Null table");
379 NS_PRECONDITION(aStackParent, "Null stack parent");
381 if (mBuilder) {
382 nsresult rv = nsHtml5TreeOperation::FosterParent(
383 static_cast<nsIContent*>(aChild),
384 static_cast<nsIContent*>(aStackParent),
385 static_cast<nsIContent*>(aTable),
386 mBuilder);
387 if (NS_FAILED(rv)) {
388 MarkAsBrokenAndRequestSuspension(rv);
389 }
390 return;
391 }
393 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
394 NS_ASSERTION(treeOp, "Tree op allocation failed.");
395 treeOp->Init(eTreeOpFosterParent, aChild, aStackParent, aTable);
396 }
398 void
399 nsHtml5TreeBuilder::appendCharacters(nsIContentHandle* aParent, char16_t* aBuffer, int32_t aStart, int32_t aLength)
400 {
401 NS_PRECONDITION(aBuffer, "Null buffer");
402 NS_PRECONDITION(aParent, "Null parent");
403 MOZ_ASSERT(!aStart, "aStart must always be zero.");
405 if (mBuilder) {
406 nsresult rv = nsHtml5TreeOperation::AppendText(
407 aBuffer, // XXX aStart always ignored???
408 aLength,
409 static_cast<nsIContent*>(deepTreeSurrogateParent ?
410 deepTreeSurrogateParent : aParent),
411 mBuilder);
412 if (NS_FAILED(rv)) {
413 MarkAsBrokenAndRequestSuspension(rv);
414 }
415 return;
416 }
418 char16_t* bufferCopy = new char16_t[aLength];
419 memcpy(bufferCopy, aBuffer, aLength * sizeof(char16_t));
421 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
422 NS_ASSERTION(treeOp, "Tree op allocation failed.");
423 treeOp->Init(eTreeOpAppendText, bufferCopy, aLength,
424 deepTreeSurrogateParent ? deepTreeSurrogateParent : aParent);
425 }
427 void
428 nsHtml5TreeBuilder::appendIsindexPrompt(nsIContentHandle* aParent)
429 {
430 NS_PRECONDITION(aParent, "Null parent");
432 if (mBuilder) {
433 nsresult rv = nsHtml5TreeOperation::AppendIsindexPrompt(
434 static_cast<nsIContent*>(aParent),
435 mBuilder);
436 if (NS_FAILED(rv)) {
437 MarkAsBrokenAndRequestSuspension(rv);
438 }
439 return;
440 }
442 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
443 NS_ASSERTION(treeOp, "Tree op allocation failed.");
444 treeOp->Init(eTreeOpAppendIsindexPrompt, aParent);
445 }
447 void
448 nsHtml5TreeBuilder::appendComment(nsIContentHandle* aParent, char16_t* aBuffer, int32_t aStart, int32_t aLength)
449 {
450 NS_PRECONDITION(aBuffer, "Null buffer");
451 NS_PRECONDITION(aParent, "Null parent");
452 MOZ_ASSERT(!aStart, "aStart must always be zero.");
454 if (deepTreeSurrogateParent) {
455 return;
456 }
458 if (mBuilder) {
459 nsresult rv = nsHtml5TreeOperation::AppendComment(
460 static_cast<nsIContent*>(aParent),
461 aBuffer, // XXX aStart always ignored???
462 aLength,
463 mBuilder);
464 if (NS_FAILED(rv)) {
465 MarkAsBrokenAndRequestSuspension(rv);
466 }
467 return;
468 }
470 char16_t* bufferCopy = new char16_t[aLength];
471 memcpy(bufferCopy, aBuffer, aLength * sizeof(char16_t));
473 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
474 NS_ASSERTION(treeOp, "Tree op allocation failed.");
475 treeOp->Init(eTreeOpAppendComment, bufferCopy, aLength, aParent);
476 }
478 void
479 nsHtml5TreeBuilder::appendCommentToDocument(char16_t* aBuffer, int32_t aStart, int32_t aLength)
480 {
481 NS_PRECONDITION(aBuffer, "Null buffer");
482 MOZ_ASSERT(!aStart, "aStart must always be zero.");
484 if (mBuilder) {
485 nsresult rv = nsHtml5TreeOperation::AppendCommentToDocument(
486 aBuffer, // XXX aStart always ignored???
487 aLength,
488 mBuilder);
489 if (NS_FAILED(rv)) {
490 MarkAsBrokenAndRequestSuspension(rv);
491 }
492 return;
493 }
495 char16_t* bufferCopy = new char16_t[aLength];
496 memcpy(bufferCopy, aBuffer, aLength * sizeof(char16_t));
498 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
499 NS_ASSERTION(treeOp, "Tree op allocation failed.");
500 treeOp->Init(eTreeOpAppendCommentToDocument, bufferCopy, aLength);
501 }
503 void
504 nsHtml5TreeBuilder::addAttributesToElement(nsIContentHandle* aElement, nsHtml5HtmlAttributes* aAttributes)
505 {
506 NS_PRECONDITION(aElement, "Null element");
507 NS_PRECONDITION(aAttributes, "Null attributes");
509 if (aAttributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
510 return;
511 }
513 if (mBuilder) {
514 MOZ_ASSERT(aAttributes == tokenizer->GetAttributes(),
515 "Using attribute other than the tokenizer's to add to body or html.");
516 nsresult rv = nsHtml5TreeOperation::AddAttributes(
517 static_cast<nsIContent*>(aElement),
518 aAttributes,
519 mBuilder);
520 if (NS_FAILED(rv)) {
521 MarkAsBrokenAndRequestSuspension(rv);
522 }
523 return;
524 }
526 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
527 NS_ASSERTION(treeOp, "Tree op allocation failed.");
528 treeOp->Init(aElement, aAttributes);
529 }
531 void
532 nsHtml5TreeBuilder::markMalformedIfScript(nsIContentHandle* aElement)
533 {
534 NS_PRECONDITION(aElement, "Null element");
536 if (mBuilder) {
537 nsHtml5TreeOperation::MarkMalformedIfScript(
538 static_cast<nsIContent*>(aElement));
539 return;
540 }
542 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
543 NS_ASSERTION(treeOp, "Tree op allocation failed.");
544 treeOp->Init(eTreeOpMarkMalformedIfScript, aElement);
545 }
547 void
548 nsHtml5TreeBuilder::start(bool fragment)
549 {
550 mCurrentHtmlScriptIsAsyncOrDefer = false;
551 deepTreeSurrogateParent = nullptr;
552 #ifdef DEBUG
553 mActive = true;
554 #endif
555 }
557 void
558 nsHtml5TreeBuilder::end()
559 {
560 mOpQueue.Clear();
561 #ifdef DEBUG
562 mActive = false;
563 #endif
564 }
566 void
567 nsHtml5TreeBuilder::appendDoctypeToDocument(nsIAtom* aName, nsString* aPublicId, nsString* aSystemId)
568 {
569 NS_PRECONDITION(aName, "Null name");
571 if (mBuilder) {
572 nsCOMPtr<nsIAtom> name = nsHtml5TreeOperation::Reget(aName);
573 nsresult rv =
574 nsHtml5TreeOperation::AppendDoctypeToDocument(name,
575 *aPublicId,
576 *aSystemId,
577 mBuilder);
578 if (NS_FAILED(rv)) {
579 MarkAsBrokenAndRequestSuspension(rv);
580 }
581 return;
582 }
584 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
585 NS_ASSERTION(treeOp, "Tree op allocation failed.");
586 treeOp->Init(aName, *aPublicId, *aSystemId);
587 // nsXMLContentSink can flush here, but what's the point?
588 // It can also interrupt here, but we can't.
589 }
591 void
592 nsHtml5TreeBuilder::elementPushed(int32_t aNamespace, nsIAtom* aName, nsIContentHandle* aElement)
593 {
594 NS_ASSERTION(aNamespace == kNameSpaceID_XHTML || aNamespace == kNameSpaceID_SVG || aNamespace == kNameSpaceID_MathML, "Element isn't HTML, SVG or MathML!");
595 NS_ASSERTION(aName, "Element doesn't have local name!");
596 NS_ASSERTION(aElement, "No element!");
597 /*
598 * The frame constructor uses recursive algorithms, so it can't deal with
599 * arbitrarily deep trees. This is especially a problem on Windows where
600 * the permitted depth of the runtime stack is rather small.
601 *
602 * The following is a protection against author incompetence--not against
603 * malice. There are other ways to make the DOM deep anyway.
604 *
605 * The basic idea is that when the tree builder stack gets too deep,
606 * append operations no longer append to the node that the HTML parsing
607 * algorithm says they should but instead text nodes are append to the last
608 * element that was seen before a magic tree builder stack threshold was
609 * reached and element and comment nodes aren't appended to the DOM at all.
610 *
611 * However, for security reasons, non-child descendant text nodes inside an
612 * SVG script or style element should not become children. Also, non-cell
613 * table elements shouldn't be used as surrogate parents for user experience
614 * reasons.
615 */
616 if (!deepTreeSurrogateParent && currentPtr >= MAX_REFLOW_DEPTH &&
617 !(aName == nsHtml5Atoms::script ||
618 aName == nsHtml5Atoms::table ||
619 aName == nsHtml5Atoms::thead ||
620 aName == nsHtml5Atoms::tfoot ||
621 aName == nsHtml5Atoms::tbody ||
622 aName == nsHtml5Atoms::tr ||
623 aName == nsHtml5Atoms::colgroup ||
624 aName == nsHtml5Atoms::style)) {
625 deepTreeSurrogateParent = aElement;
626 }
627 if (aNamespace != kNameSpaceID_XHTML) {
628 return;
629 }
630 if (aName == nsHtml5Atoms::body || aName == nsHtml5Atoms::frameset) {
631 if (mBuilder) {
632 // InnerHTML and DOMParser shouldn't start layout anyway
633 return;
634 }
635 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
636 NS_ASSERTION(treeOp, "Tree op allocation failed.");
637 treeOp->Init(eTreeOpStartLayout);
638 return;
639 }
640 if (aName == nsHtml5Atoms::input ||
641 aName == nsHtml5Atoms::button) {
642 if (!formPointer) {
643 // If form inputs don't belong to a form, their state preservation
644 // won't work right without an append notification flush at this
645 // point. See bug 497861.
646 if (mBuilder) {
647 mBuilder->FlushPendingAppendNotifications();
648 } else {
649 mOpQueue.AppendElement()->Init(eTreeOpFlushPendingAppendNotifications);
650 }
651 }
652 if (mBuilder) {
653 nsHtml5TreeOperation::DoneCreatingElement(static_cast<nsIContent*>(aElement));
654 } else {
655 mOpQueue.AppendElement()->Init(eTreeOpDoneCreatingElement, aElement);
656 }
657 return;
658 }
659 if (aName == nsHtml5Atoms::audio ||
660 aName == nsHtml5Atoms::video ||
661 aName == nsHtml5Atoms::menuitem) {
662 if (mBuilder) {
663 nsHtml5TreeOperation::DoneCreatingElement(static_cast<nsIContent*>(aElement));
664 } else {
665 mOpQueue.AppendElement()->Init(eTreeOpDoneCreatingElement, aElement);
666 }
667 return;
668 }
669 }
671 void
672 nsHtml5TreeBuilder::elementPopped(int32_t aNamespace, nsIAtom* aName, nsIContentHandle* aElement)
673 {
674 NS_ASSERTION(aNamespace == kNameSpaceID_XHTML || aNamespace == kNameSpaceID_SVG || aNamespace == kNameSpaceID_MathML, "Element isn't HTML, SVG or MathML!");
675 NS_ASSERTION(aName, "Element doesn't have local name!");
676 NS_ASSERTION(aElement, "No element!");
677 if (deepTreeSurrogateParent && currentPtr <= MAX_REFLOW_DEPTH) {
678 deepTreeSurrogateParent = nullptr;
679 }
680 if (aNamespace == kNameSpaceID_MathML) {
681 return;
682 }
683 // we now have only SVG and HTML
684 if (aName == nsHtml5Atoms::script) {
685 if (mPreventScriptExecution) {
686 if (mBuilder) {
687 nsHtml5TreeOperation::PreventScriptExecution(static_cast<nsIContent*>(aElement));
688 return;
689 }
690 mOpQueue.AppendElement()->Init(eTreeOpPreventScriptExecution, aElement);
691 return;
692 }
693 if (mBuilder) {
694 return;
695 }
696 if (mCurrentHtmlScriptIsAsyncOrDefer) {
697 NS_ASSERTION(aNamespace == kNameSpaceID_XHTML,
698 "Only HTML scripts may be async/defer.");
699 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
700 NS_ASSERTION(treeOp, "Tree op allocation failed.");
701 treeOp->Init(eTreeOpRunScriptAsyncDefer, aElement);
702 mCurrentHtmlScriptIsAsyncOrDefer = false;
703 return;
704 }
705 requestSuspension();
706 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
707 NS_ASSERTION(treeOp, "Tree op allocation failed.");
708 treeOp->InitScript(aElement);
709 return;
710 }
711 if (aName == nsHtml5Atoms::title) {
712 if (mBuilder) {
713 nsHtml5TreeOperation::DoneAddingChildren(static_cast<nsIContent*>(aElement), mBuilder);
714 return;
715 }
716 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
717 NS_ASSERTION(treeOp, "Tree op allocation failed.");
718 treeOp->Init(eTreeOpDoneAddingChildren, aElement);
719 return;
720 }
721 if (aName == nsHtml5Atoms::style || (aNamespace == kNameSpaceID_XHTML && aName == nsHtml5Atoms::link)) {
722 if (mBuilder) {
723 MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(),
724 "Scripts must be blocked.");
725 mBuilder->FlushPendingAppendNotifications();
726 mBuilder->UpdateStyleSheet(static_cast<nsIContent*>(aElement));
727 return;
728 }
729 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
730 NS_ASSERTION(treeOp, "Tree op allocation failed.");
731 treeOp->Init(eTreeOpUpdateStyleSheet, aElement);
732 return;
733 }
734 if (aNamespace == kNameSpaceID_SVG) {
735 if (aName == nsHtml5Atoms::svg) {
736 if (mBuilder) {
737 nsHtml5TreeOperation::SvgLoad(static_cast<nsIContent*>(aElement));
738 return;
739 }
740 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
741 NS_ASSERTION(treeOp, "Tree op allocation failed.");
742 treeOp->Init(eTreeOpSvgLoad, aElement);
743 }
744 return;
745 }
746 // we now have only HTML
747 // Some HTML nodes need DoneAddingChildren() called to initialize
748 // properly (e.g. form state restoration).
749 // XXX expose ElementName group here and do switch
750 if (aName == nsHtml5Atoms::object ||
751 aName == nsHtml5Atoms::applet) {
752 if (mBuilder) {
753 nsHtml5TreeOperation::DoneAddingChildren(static_cast<nsIContent*>(aElement), mBuilder);
754 return;
755 }
756 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
757 NS_ASSERTION(treeOp, "Tree op allocation failed.");
758 treeOp->Init(eTreeOpDoneAddingChildren, aElement);
759 return;
760 }
761 if (aName == nsHtml5Atoms::select ||
762 aName == nsHtml5Atoms::textarea) {
763 if (!formPointer) {
764 // If form inputs don't belong to a form, their state preservation
765 // won't work right without an append notification flush at this
766 // point. See bug 497861 and bug 539895.
767 if (mBuilder) {
768 mBuilder->FlushPendingAppendNotifications();
769 } else {
770 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
771 NS_ASSERTION(treeOp, "Tree op allocation failed.");
772 treeOp->Init(eTreeOpFlushPendingAppendNotifications);
773 }
774 }
775 if (mBuilder) {
776 nsHtml5TreeOperation::DoneAddingChildren(static_cast<nsIContent*>(aElement), mBuilder);
777 return;
778 }
779 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
780 NS_ASSERTION(treeOp, "Tree op allocation failed.");
781 treeOp->Init(eTreeOpDoneAddingChildren, aElement);
782 return;
783 }
784 if (aName == nsHtml5Atoms::meta && !fragment && !mBuilder) {
785 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
786 NS_ASSERTION(treeOp, "Tree op allocation failed.");
787 treeOp->Init(eTreeOpProcessMeta, aElement);
788 return;
789 }
790 return;
791 }
793 void
794 nsHtml5TreeBuilder::accumulateCharacters(const char16_t* aBuf, int32_t aStart, int32_t aLength)
795 {
796 int32_t newFillLen = charBufferLen + aLength;
797 if (newFillLen > charBuffer.length) {
798 int32_t newAllocLength = newFillLen + (newFillLen >> 1);
799 jArray<char16_t,int32_t> newBuf = jArray<char16_t,int32_t>::newJArray(newAllocLength);
800 memcpy(newBuf, charBuffer, sizeof(char16_t) * charBufferLen);
801 charBuffer = newBuf;
802 }
803 memcpy(charBuffer + charBufferLen, aBuf + aStart, sizeof(char16_t) * aLength);
804 charBufferLen = newFillLen;
805 }
807 nsIContentHandle*
808 nsHtml5TreeBuilder::AllocateContentHandle()
809 {
810 if (MOZ_UNLIKELY(mBuilder)) {
811 MOZ_ASSUME_UNREACHABLE("Must never allocate a handle with builder.");
812 return nullptr;
813 }
814 if (mHandlesUsed == NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH) {
815 mOldHandles.AppendElement(mHandles.forget());
816 mHandles = new nsIContent*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH];
817 mHandlesUsed = 0;
818 }
819 #ifdef DEBUG
820 mHandles[mHandlesUsed] = (nsIContent*)0xC0DEDBAD;
821 #endif
822 return &mHandles[mHandlesUsed++];
823 }
825 bool
826 nsHtml5TreeBuilder::HasScript()
827 {
828 uint32_t len = mOpQueue.Length();
829 if (!len) {
830 return false;
831 }
832 return mOpQueue.ElementAt(len - 1).IsRunScript();
833 }
835 bool
836 nsHtml5TreeBuilder::Flush(bool aDiscretionary)
837 {
838 if (MOZ_UNLIKELY(mBuilder)) {
839 MOZ_ASSUME_UNREACHABLE("Must never flush with builder.");
840 return false;
841 }
842 if (!aDiscretionary ||
843 !(charBufferLen &&
844 currentPtr >= 0 &&
845 stack[currentPtr]->isFosterParenting())) {
846 // Don't flush text on discretionary flushes if the current element on
847 // the stack is a foster-parenting element and there's pending text,
848 // because flushing in that case would make the tree shape dependent on
849 // where the flush points fall.
850 flushCharacters();
851 }
852 FlushLoads();
853 if (mOpSink) {
854 bool hasOps = !mOpQueue.IsEmpty();
855 if (hasOps) {
856 mOpSink->MoveOpsFrom(mOpQueue);
857 }
858 return hasOps;
859 }
860 // no op sink: throw away ops
861 mOpQueue.Clear();
862 return false;
863 }
865 void
866 nsHtml5TreeBuilder::FlushLoads()
867 {
868 if (MOZ_UNLIKELY(mBuilder)) {
869 MOZ_ASSUME_UNREACHABLE("Must never flush loads with builder.");
870 return;
871 }
872 if (!mSpeculativeLoadQueue.IsEmpty()) {
873 mSpeculativeLoadStage->MoveSpeculativeLoadsFrom(mSpeculativeLoadQueue);
874 }
875 }
877 void
878 nsHtml5TreeBuilder::SetDocumentCharset(nsACString& aCharset,
879 int32_t aCharsetSource)
880 {
881 if (mBuilder) {
882 mBuilder->SetDocumentCharsetAndSource(aCharset, aCharsetSource);
883 } else if (mSpeculativeLoadStage) {
884 mSpeculativeLoadQueue.AppendElement()->InitSetDocumentCharset(
885 aCharset, aCharsetSource);
886 } else {
887 mOpQueue.AppendElement()->Init(
888 eTreeOpSetDocumentCharset, aCharset, aCharsetSource);
889 }
890 }
892 void
893 nsHtml5TreeBuilder::StreamEnded()
894 {
895 MOZ_ASSERT(!mBuilder, "Must not call StreamEnded with builder.");
896 MOZ_ASSERT(!fragment, "Must not parse fragments off the main thread.");
897 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
898 NS_ASSERTION(treeOp, "Tree op allocation failed.");
899 treeOp->Init(eTreeOpStreamEnded);
900 }
902 void
903 nsHtml5TreeBuilder::NeedsCharsetSwitchTo(const nsACString& aCharset,
904 int32_t aCharsetSource,
905 int32_t aLineNumber)
906 {
907 if (MOZ_UNLIKELY(mBuilder)) {
908 MOZ_ASSUME_UNREACHABLE("Must never switch charset with builder.");
909 return;
910 }
911 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
912 NS_ASSERTION(treeOp, "Tree op allocation failed.");
913 treeOp->Init(eTreeOpNeedsCharsetSwitchTo,
914 aCharset,
915 aCharsetSource,
916 aLineNumber);
917 }
919 void
920 nsHtml5TreeBuilder::MaybeComplainAboutCharset(const char* aMsgId,
921 bool aError,
922 int32_t aLineNumber)
923 {
924 if (MOZ_UNLIKELY(mBuilder)) {
925 MOZ_ASSUME_UNREACHABLE("Must never complain about charset with builder.");
926 return;
927 }
928 mOpQueue.AppendElement()->Init(aMsgId, aError, aLineNumber);
929 }
931 void
932 nsHtml5TreeBuilder::AddSnapshotToScript(nsAHtml5TreeBuilderState* aSnapshot, int32_t aLine)
933 {
934 if (MOZ_UNLIKELY(mBuilder)) {
935 MOZ_ASSUME_UNREACHABLE("Must never use snapshots with builder.");
936 return;
937 }
938 NS_PRECONDITION(HasScript(), "No script to add a snapshot to!");
939 NS_PRECONDITION(aSnapshot, "Got null snapshot.");
940 mOpQueue.ElementAt(mOpQueue.Length() - 1).SetSnapshot(aSnapshot, aLine);
941 }
943 void
944 nsHtml5TreeBuilder::DropHandles()
945 {
946 MOZ_ASSERT(!mBuilder, "Must not drop handles with builder.");
947 mOldHandles.Clear();
948 mHandlesUsed = 0;
949 }
951 void
952 nsHtml5TreeBuilder::MarkAsBroken(nsresult aRv)
953 {
954 if (MOZ_UNLIKELY(mBuilder)) {
955 MOZ_ASSUME_UNREACHABLE("Must not call this with builder.");
956 return;
957 }
958 mOpQueue.Clear(); // Previous ops don't matter anymore
959 mOpQueue.AppendElement()->Init(aRv);
960 }
962 void
963 nsHtml5TreeBuilder::StartPlainTextViewSource(const nsAutoString& aTitle)
964 {
965 MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
966 startTag(nsHtml5ElementName::ELT_TITLE,
967 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES,
968 false);
970 // XUL will add the "Source of: " prefix.
971 uint32_t length = aTitle.Length();
972 if (length > INT32_MAX) {
973 length = INT32_MAX;
974 }
975 characters(aTitle.get(), 0, (int32_t)length);
976 endTag(nsHtml5ElementName::ELT_TITLE);
978 startTag(nsHtml5ElementName::ELT_LINK,
979 nsHtml5ViewSourceUtils::NewLinkAttributes(),
980 false);
982 startTag(nsHtml5ElementName::ELT_BODY,
983 nsHtml5ViewSourceUtils::NewBodyAttributes(),
984 false);
986 StartPlainTextBody();
987 }
989 void
990 nsHtml5TreeBuilder::StartPlainText()
991 {
992 MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
993 startTag(nsHtml5ElementName::ELT_LINK,
994 nsHtml5PlainTextUtils::NewLinkAttributes(),
995 false);
997 StartPlainTextBody();
998 }
1000 void
1001 nsHtml5TreeBuilder::StartPlainTextBody()
1002 {
1003 MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
1004 startTag(nsHtml5ElementName::ELT_PRE,
1005 nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES,
1006 false);
1007 needToDropLF = false;
1008 }
1010 // DocumentModeHandler
1011 void
1012 nsHtml5TreeBuilder::documentMode(nsHtml5DocumentMode m)
1013 {
1014 if (mBuilder) {
1015 mBuilder->SetDocumentMode(m);
1016 return;
1017 }
1018 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
1019 NS_ASSERTION(treeOp, "Tree op allocation failed.");
1020 treeOp->Init(m);
1021 }
1023 nsIContentHandle*
1024 nsHtml5TreeBuilder::getDocumentFragmentForTemplate(nsIContentHandle* aTemplate)
1025 {
1026 if (mBuilder) {
1027 return nsHtml5TreeOperation::GetDocumentFragmentForTemplate(static_cast<nsIContent*>(aTemplate));
1028 }
1029 nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
1030 NS_ASSERTION(treeOp, "Tree op allocation failed.");
1031 nsIContentHandle* fragHandle = AllocateContentHandle();
1032 treeOp->Init(eTreeOpGetDocumentFragmentForTemplate, aTemplate, fragHandle);
1033 return fragHandle;
1034 }
1036 nsIContentHandle*
1037 nsHtml5TreeBuilder::getFormPointerForContext(nsIContentHandle* aContext)
1038 {
1039 MOZ_ASSERT(mBuilder, "Must have builder.");
1040 if (!aContext) {
1041 return nullptr;
1042 }
1044 MOZ_ASSERT(NS_IsMainThread());
1046 // aContext must always be an element that already exists
1047 // in the document.
1048 nsIContent* contextNode = static_cast<nsIContent*>(aContext);
1049 nsIContent* currentAncestor = contextNode;
1051 // We traverse the ancestors of the context node to find the nearest
1052 // form pointer. This traversal is why aContext must not be an emtpy handle.
1053 nsIContent* nearestForm = nullptr;
1054 while (currentAncestor) {
1055 if (currentAncestor->IsHTML(nsGkAtoms::form)) {
1056 nearestForm = currentAncestor;
1057 break;
1058 }
1059 currentAncestor = currentAncestor->GetParent();
1060 }
1062 if (!nearestForm) {
1063 return nullptr;
1064 }
1066 return nearestForm;
1067 }
1069 // Error reporting
1071 void
1072 nsHtml5TreeBuilder::EnableViewSource(nsHtml5Highlighter* aHighlighter)
1073 {
1074 MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
1075 mViewSource = aHighlighter;
1076 }
1078 void
1079 nsHtml5TreeBuilder::errStrayStartTag(nsIAtom* aName)
1080 {
1081 if (MOZ_UNLIKELY(mViewSource)) {
1082 mViewSource->AddErrorToCurrentRun("errStrayStartTag2", aName);
1083 }
1084 }
1086 void
1087 nsHtml5TreeBuilder::errStrayEndTag(nsIAtom* aName)
1088 {
1089 if (MOZ_UNLIKELY(mViewSource)) {
1090 mViewSource->AddErrorToCurrentRun("errStrayEndTag", aName);
1091 }
1092 }
1094 void
1095 nsHtml5TreeBuilder::errUnclosedElements(int32_t aIndex, nsIAtom* aName)
1096 {
1097 if (MOZ_UNLIKELY(mViewSource)) {
1098 mViewSource->AddErrorToCurrentRun("errUnclosedElements", aName);
1099 }
1100 }
1102 void
1103 nsHtml5TreeBuilder::errUnclosedElementsImplied(int32_t aIndex, nsIAtom* aName)
1104 {
1105 if (MOZ_UNLIKELY(mViewSource)) {
1106 mViewSource->AddErrorToCurrentRun("errUnclosedElementsImplied",
1107 aName);
1108 }
1109 }
1111 void
1112 nsHtml5TreeBuilder::errUnclosedElementsCell(int32_t aIndex)
1113 {
1114 if (MOZ_UNLIKELY(mViewSource)) {
1115 mViewSource->AddErrorToCurrentRun("errUnclosedElementsCell");
1116 }
1117 }
1119 void
1120 nsHtml5TreeBuilder::errStrayDoctype()
1121 {
1122 if (MOZ_UNLIKELY(mViewSource)) {
1123 mViewSource->AddErrorToCurrentRun("errStrayDoctype");
1124 }
1125 }
1127 void
1128 nsHtml5TreeBuilder::errAlmostStandardsDoctype()
1129 {
1130 if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) {
1131 mViewSource->AddErrorToCurrentRun("errAlmostStandardsDoctype");
1132 }
1133 }
1135 void
1136 nsHtml5TreeBuilder::errQuirkyDoctype()
1137 {
1138 if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) {
1139 mViewSource->AddErrorToCurrentRun("errQuirkyDoctype");
1140 }
1141 }
1143 void
1144 nsHtml5TreeBuilder::errNonSpaceInTrailer()
1145 {
1146 if (MOZ_UNLIKELY(mViewSource)) {
1147 mViewSource->AddErrorToCurrentRun("errNonSpaceInTrailer");
1148 }
1149 }
1151 void
1152 nsHtml5TreeBuilder::errNonSpaceAfterFrameset()
1153 {
1154 if (MOZ_UNLIKELY(mViewSource)) {
1155 mViewSource->AddErrorToCurrentRun("errNonSpaceAfterFrameset");
1156 }
1157 }
1159 void
1160 nsHtml5TreeBuilder::errNonSpaceInFrameset()
1161 {
1162 if (MOZ_UNLIKELY(mViewSource)) {
1163 mViewSource->AddErrorToCurrentRun("errNonSpaceInFrameset");
1164 }
1165 }
1167 void
1168 nsHtml5TreeBuilder::errNonSpaceAfterBody()
1169 {
1170 if (MOZ_UNLIKELY(mViewSource)) {
1171 mViewSource->AddErrorToCurrentRun("errNonSpaceAfterBody");
1172 }
1173 }
1175 void
1176 nsHtml5TreeBuilder::errNonSpaceInColgroupInFragment()
1177 {
1178 if (MOZ_UNLIKELY(mViewSource)) {
1179 mViewSource->AddErrorToCurrentRun("errNonSpaceInColgroupInFragment");
1180 }
1181 }
1183 void
1184 nsHtml5TreeBuilder::errNonSpaceInNoscriptInHead()
1185 {
1186 if (MOZ_UNLIKELY(mViewSource)) {
1187 mViewSource->AddErrorToCurrentRun("errNonSpaceInNoscriptInHead");
1188 }
1189 }
1191 void
1192 nsHtml5TreeBuilder::errFooBetweenHeadAndBody(nsIAtom* aName)
1193 {
1194 if (MOZ_UNLIKELY(mViewSource)) {
1195 mViewSource->AddErrorToCurrentRun("errFooBetweenHeadAndBody", aName);
1196 }
1197 }
1199 void
1200 nsHtml5TreeBuilder::errStartTagWithoutDoctype()
1201 {
1202 if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) {
1203 mViewSource->AddErrorToCurrentRun("errStartTagWithoutDoctype");
1204 }
1205 }
1207 void
1208 nsHtml5TreeBuilder::errNoSelectInTableScope()
1209 {
1210 if (MOZ_UNLIKELY(mViewSource)) {
1211 mViewSource->AddErrorToCurrentRun("errNoSelectInTableScope");
1212 }
1213 }
1215 void
1216 nsHtml5TreeBuilder::errStartSelectWhereEndSelectExpected()
1217 {
1218 if (MOZ_UNLIKELY(mViewSource)) {
1219 mViewSource->AddErrorToCurrentRun(
1220 "errStartSelectWhereEndSelectExpected");
1221 }
1222 }
1224 void
1225 nsHtml5TreeBuilder::errStartTagWithSelectOpen(nsIAtom* aName)
1226 {
1227 if (MOZ_UNLIKELY(mViewSource)) {
1228 mViewSource->AddErrorToCurrentRun("errStartTagWithSelectOpen", aName);
1229 }
1230 }
1232 void
1233 nsHtml5TreeBuilder::errBadStartTagInHead(nsIAtom* aName)
1234 {
1235 if (MOZ_UNLIKELY(mViewSource)) {
1236 mViewSource->AddErrorToCurrentRun("errBadStartTagInHead2", aName);
1237 }
1238 }
1240 void
1241 nsHtml5TreeBuilder::errImage()
1242 {
1243 if (MOZ_UNLIKELY(mViewSource)) {
1244 mViewSource->AddErrorToCurrentRun("errImage");
1245 }
1246 }
1248 void
1249 nsHtml5TreeBuilder::errIsindex()
1250 {
1251 if (MOZ_UNLIKELY(mViewSource)) {
1252 mViewSource->AddErrorToCurrentRun("errIsindex");
1253 }
1254 }
1256 void
1257 nsHtml5TreeBuilder::errFooSeenWhenFooOpen(nsIAtom* aName)
1258 {
1259 if (MOZ_UNLIKELY(mViewSource)) {
1260 mViewSource->AddErrorToCurrentRun("errFooSeenWhenFooOpen", aName);
1261 }
1262 }
1264 void
1265 nsHtml5TreeBuilder::errHeadingWhenHeadingOpen()
1266 {
1267 if (MOZ_UNLIKELY(mViewSource)) {
1268 mViewSource->AddErrorToCurrentRun("errHeadingWhenHeadingOpen");
1269 }
1270 }
1272 void
1273 nsHtml5TreeBuilder::errFramesetStart()
1274 {
1275 if (MOZ_UNLIKELY(mViewSource)) {
1276 mViewSource->AddErrorToCurrentRun("errFramesetStart");
1277 }
1278 }
1280 void
1281 nsHtml5TreeBuilder::errNoCellToClose()
1282 {
1283 if (MOZ_UNLIKELY(mViewSource)) {
1284 mViewSource->AddErrorToCurrentRun("errNoCellToClose");
1285 }
1286 }
1288 void
1289 nsHtml5TreeBuilder::errStartTagInTable(nsIAtom* aName)
1290 {
1291 if (MOZ_UNLIKELY(mViewSource)) {
1292 mViewSource->AddErrorToCurrentRun("errStartTagInTable", aName);
1293 }
1294 }
1296 void
1297 nsHtml5TreeBuilder::errFormWhenFormOpen()
1298 {
1299 if (MOZ_UNLIKELY(mViewSource)) {
1300 mViewSource->AddErrorToCurrentRun("errFormWhenFormOpen");
1301 }
1302 }
1304 void
1305 nsHtml5TreeBuilder::errTableSeenWhileTableOpen()
1306 {
1307 if (MOZ_UNLIKELY(mViewSource)) {
1308 mViewSource->AddErrorToCurrentRun("errTableSeenWhileTableOpen");
1309 }
1310 }
1312 void
1313 nsHtml5TreeBuilder::errStartTagInTableBody(nsIAtom* aName)
1314 {
1315 if (MOZ_UNLIKELY(mViewSource)) {
1316 mViewSource->AddErrorToCurrentRun("errStartTagInTableBody", aName);
1317 }
1318 }
1320 void
1321 nsHtml5TreeBuilder::errEndTagSeenWithoutDoctype()
1322 {
1323 if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) {
1324 mViewSource->AddErrorToCurrentRun("errEndTagSeenWithoutDoctype");
1325 }
1326 }
1328 void
1329 nsHtml5TreeBuilder::errEndTagAfterBody()
1330 {
1331 if (MOZ_UNLIKELY(mViewSource)) {
1332 mViewSource->AddErrorToCurrentRun("errEndTagAfterBody");
1333 }
1334 }
1336 void
1337 nsHtml5TreeBuilder::errEndTagSeenWithSelectOpen(nsIAtom* aName)
1338 {
1339 if (MOZ_UNLIKELY(mViewSource)) {
1340 mViewSource->AddErrorToCurrentRun("errEndTagSeenWithSelectOpen",
1341 aName);
1342 }
1343 }
1345 void
1346 nsHtml5TreeBuilder::errGarbageInColgroup()
1347 {
1348 if (MOZ_UNLIKELY(mViewSource)) {
1349 mViewSource->AddErrorToCurrentRun("errGarbageInColgroup");
1350 }
1351 }
1353 void
1354 nsHtml5TreeBuilder::errEndTagBr()
1355 {
1356 if (MOZ_UNLIKELY(mViewSource)) {
1357 mViewSource->AddErrorToCurrentRun("errEndTagBr");
1358 }
1359 }
1361 void
1362 nsHtml5TreeBuilder::errNoElementToCloseButEndTagSeen(nsIAtom* aName)
1363 {
1364 if (MOZ_UNLIKELY(mViewSource)) {
1365 mViewSource->AddErrorToCurrentRun(
1366 "errNoElementToCloseButEndTagSeen", aName);
1367 }
1368 }
1370 void
1371 nsHtml5TreeBuilder::errHtmlStartTagInForeignContext(nsIAtom* aName)
1372 {
1373 if (MOZ_UNLIKELY(mViewSource)) {
1374 mViewSource->AddErrorToCurrentRun("errHtmlStartTagInForeignContext",
1375 aName);
1376 }
1377 }
1379 void
1380 nsHtml5TreeBuilder::errTableClosedWhileCaptionOpen()
1381 {
1382 if (MOZ_UNLIKELY(mViewSource)) {
1383 mViewSource->AddErrorToCurrentRun("errTableClosedWhileCaptionOpen");
1384 }
1385 }
1387 void
1388 nsHtml5TreeBuilder::errNoTableRowToClose()
1389 {
1390 if (MOZ_UNLIKELY(mViewSource)) {
1391 mViewSource->AddErrorToCurrentRun("errNoTableRowToClose");
1392 }
1393 }
1395 void
1396 nsHtml5TreeBuilder::errNonSpaceInTable()
1397 {
1398 if (MOZ_UNLIKELY(mViewSource)) {
1399 mViewSource->AddErrorToCurrentRun("errNonSpaceInTable");
1400 }
1401 }
1403 void
1404 nsHtml5TreeBuilder::errUnclosedChildrenInRuby()
1405 {
1406 if (MOZ_UNLIKELY(mViewSource)) {
1407 mViewSource->AddErrorToCurrentRun("errUnclosedChildrenInRuby");
1408 }
1409 }
1411 void
1412 nsHtml5TreeBuilder::errStartTagSeenWithoutRuby(nsIAtom* aName)
1413 {
1414 if (MOZ_UNLIKELY(mViewSource)) {
1415 mViewSource->AddErrorToCurrentRun("errStartTagSeenWithoutRuby",
1416 aName);
1417 }
1418 }
1420 void
1421 nsHtml5TreeBuilder::errSelfClosing()
1422 {
1423 if (MOZ_UNLIKELY(mViewSource)) {
1424 mViewSource->AddErrorToCurrentSlash("errSelfClosing");
1425 }
1426 }
1428 void
1429 nsHtml5TreeBuilder::errNoCheckUnclosedElementsOnStack()
1430 {
1431 if (MOZ_UNLIKELY(mViewSource)) {
1432 mViewSource->AddErrorToCurrentRun(
1433 "errNoCheckUnclosedElementsOnStack");
1434 }
1435 }
1437 void
1438 nsHtml5TreeBuilder::errEndTagDidNotMatchCurrentOpenElement(nsIAtom* aName,
1439 nsIAtom* aOther)
1440 {
1441 if (MOZ_UNLIKELY(mViewSource)) {
1442 mViewSource->AddErrorToCurrentRun(
1443 "errEndTagDidNotMatchCurrentOpenElement", aName, aOther);
1444 }
1445 }
1447 void
1448 nsHtml5TreeBuilder::errEndTagViolatesNestingRules(nsIAtom* aName)
1449 {
1450 if (MOZ_UNLIKELY(mViewSource)) {
1451 mViewSource->AddErrorToCurrentRun("errEndTagViolatesNestingRules", aName);
1452 }
1453 }
1455 void
1456 nsHtml5TreeBuilder::errEndWithUnclosedElements(nsIAtom* aName)
1457 {
1458 if (MOZ_UNLIKELY(mViewSource)) {
1459 mViewSource->AddErrorToCurrentRun("errEndWithUnclosedElements", aName);
1460 }
1461 }