294559d4440ddcd9e1f47936ab84a285b56b3f88
[WebKit-https.git] / Source / WebCore / html / parser / HTMLTreeBuilder.cpp
1 /*
2  * Copyright (C) 2010 Google, Inc. All Rights Reserved.
3  * Copyright (C) 2011, 2015 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GOOGLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "HTMLTreeBuilder.h"
29
30 #include "DocumentFragment.h"
31 #include "HTMLDocument.h"
32 #include "HTMLDocumentParser.h"
33 #include "HTMLFormControlElement.h"
34 #include "HTMLFormElement.h"
35 #include "HTMLOptGroupElement.h"
36 #include "HTMLParserIdioms.h"
37 #include "LocalizedStrings.h"
38 #include "NotImplemented.h"
39 #include "XLinkNames.h"
40 #include "XMLNSNames.h"
41 #include "XMLNames.h"
42 #include <wtf/NeverDestroyed.h>
43 #include <wtf/unicode/CharacterNames.h>
44
45 #if ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(IOS)
46 #include "TelephoneNumberDetector.h"
47 #endif
48
49 namespace WebCore {
50
51 using namespace HTMLNames;
52
53 namespace {
54
55 inline bool isHTMLSpaceOrReplacementCharacter(UChar character)
56 {
57     return isHTMLSpace(character) || character == replacementCharacter;
58 }
59
60 }
61
62 static inline TextPosition uninitializedPositionValue1()
63 {
64     return TextPosition(OrdinalNumber::fromOneBasedInt(-1), OrdinalNumber::first());
65 }
66
67 static inline bool isAllWhitespace(const String& string)
68 {
69     return string.isAllSpecialCharacters<isHTMLSpace>();
70 }
71
72 static inline bool isAllWhitespaceOrReplacementCharacters(const String& string)
73 {
74     return string.isAllSpecialCharacters<isHTMLSpaceOrReplacementCharacter>();
75 }
76
77 static bool isNumberedHeaderTag(const AtomicString& tagName)
78 {
79     return tagName == h1Tag
80         || tagName == h2Tag
81         || tagName == h3Tag
82         || tagName == h4Tag
83         || tagName == h5Tag
84         || tagName == h6Tag;
85 }
86
87 static bool isCaptionColOrColgroupTag(const AtomicString& tagName)
88 {
89     return tagName == captionTag || tagName == colTag || tagName == colgroupTag;
90 }
91
92 static bool isTableCellContextTag(const AtomicString& tagName)
93 {
94     return tagName == thTag || tagName == tdTag;
95 }
96
97 static bool isTableBodyContextTag(const AtomicString& tagName)
98 {
99     return tagName == tbodyTag || tagName == tfootTag || tagName == theadTag;
100 }
101
102 static bool isNonAnchorNonNobrFormattingTag(const AtomicString& tagName)
103 {
104     return tagName == bTag
105         || tagName == bigTag
106         || tagName == codeTag
107         || tagName == emTag
108         || tagName == fontTag
109         || tagName == iTag
110         || tagName == sTag
111         || tagName == smallTag
112         || tagName == strikeTag
113         || tagName == strongTag
114         || tagName == ttTag
115         || tagName == uTag;
116 }
117
118 static bool isNonAnchorFormattingTag(const AtomicString& tagName)
119 {
120     return tagName == nobrTag || isNonAnchorNonNobrFormattingTag(tagName);
121 }
122
123 // https://html.spec.whatwg.org/multipage/syntax.html#formatting
124 static bool isFormattingTag(const AtomicString& tagName)
125 {
126     return tagName == aTag || isNonAnchorFormattingTag(tagName);
127 }
128
129 class HTMLTreeBuilder::ExternalCharacterTokenBuffer {
130 public:
131     explicit ExternalCharacterTokenBuffer(AtomicHTMLToken& token)
132         : m_text(token.characters(), token.charactersLength())
133         , m_isAll8BitData(token.charactersIsAll8BitData())
134     {
135         ASSERT(!isEmpty());
136     }
137
138     explicit ExternalCharacterTokenBuffer(const String& string)
139         : m_text(string)
140         , m_isAll8BitData(m_text.is8Bit())
141     {
142         ASSERT(!isEmpty());
143     }
144
145     ~ExternalCharacterTokenBuffer()
146     {
147         ASSERT(isEmpty());
148     }
149
150     bool isEmpty() const { return m_text.isEmpty(); }
151
152     bool isAll8BitData() const { return m_isAll8BitData; }
153
154     void skipAtMostOneLeadingNewline()
155     {
156         ASSERT(!isEmpty());
157         if (m_text[0] == '\n')
158             m_text = m_text.substring(1);
159     }
160
161     void skipLeadingWhitespace()
162     {
163         skipLeading<isHTMLSpace>();
164     }
165
166     String takeLeadingWhitespace()
167     {
168         return takeLeading<isHTMLSpace>();
169     }
170
171     void skipLeadingNonWhitespace()
172     {
173         skipLeading<isNotHTMLSpace>();
174     }
175
176     String takeRemaining()
177     {
178         String result = makeString(m_text);
179         m_text = StringView();
180         return result;
181     }
182
183     void giveRemainingTo(StringBuilder& recipient)
184     {
185         recipient.append(m_text);
186         m_text = StringView();
187     }
188
189     String takeRemainingWhitespace()
190     {
191         ASSERT(!isEmpty());
192         Vector<LChar, 8> whitespace;
193         do {
194             UChar character = m_text[0];
195             if (isHTMLSpace(character))
196                 whitespace.append(character);
197             m_text = m_text.substring(1);
198         } while (!m_text.isEmpty());
199
200         // Returning the null string when there aren't any whitespace
201         // characters is slightly cleaner semantically because we don't want
202         // to insert a text node (as opposed to inserting an empty text node).
203         if (whitespace.isEmpty())
204             return String();
205
206         return String::adopt(whitespace);
207     }
208
209 private:
210     template<bool characterPredicate(UChar)> void skipLeading()
211     {
212         ASSERT(!isEmpty());
213         while (characterPredicate(m_text[0])) {
214             m_text = m_text.substring(1);
215             if (m_text.isEmpty())
216                 return;
217         }
218     }
219
220     template<bool characterPredicate(UChar)> String takeLeading()
221     {
222         ASSERT(!isEmpty());
223         StringView start = m_text;
224         skipLeading<characterPredicate>();
225         if (start.length() == m_text.length())
226             return String();
227         return makeString(start.substring(0, start.length() - m_text.length()));
228     }
229
230     String makeString(StringView stringView) const
231     {
232         if (stringView.is8Bit() || !isAll8BitData())
233             return stringView.toString();
234         return String::make8BitFrom16BitSource(stringView.characters16(), stringView.length());
235     }
236
237     StringView m_text;
238     bool m_isAll8BitData;
239 };
240
241 inline bool HTMLTreeBuilder::isParsingTemplateContents() const
242 {
243 #if ENABLE(TEMPLATE_ELEMENT)
244     return m_tree.openElements().hasTemplateInHTMLScope();
245 #else
246     return false;
247 #endif
248 }
249
250 inline bool HTMLTreeBuilder::isParsingFragmentOrTemplateContents() const
251 {
252     return isParsingFragment() || isParsingTemplateContents();
253 }
254
255 HTMLTreeBuilder::HTMLTreeBuilder(HTMLDocumentParser& parser, HTMLDocument& document, ParserContentPolicy parserContentPolicy, const HTMLParserOptions& options)
256     : m_parser(parser)
257     , m_options(options)
258     , m_tree(document, parserContentPolicy, options.maximumDOMTreeDepth)
259     , m_scriptToProcessStartPosition(uninitializedPositionValue1())
260 {
261 #if !ASSERT_DISABLED
262     m_destructionProhibited = false;
263 #endif
264 }
265
266 HTMLTreeBuilder::HTMLTreeBuilder(HTMLDocumentParser& parser, DocumentFragment& fragment, Element& contextElement, ParserContentPolicy parserContentPolicy, const HTMLParserOptions& options)
267     : m_parser(parser)
268     , m_options(options)
269     , m_fragmentContext(fragment, contextElement)
270     , m_tree(fragment, parserContentPolicy, options.maximumDOMTreeDepth)
271     , m_scriptToProcessStartPosition(uninitializedPositionValue1())
272 {
273     ASSERT(isMainThread());
274
275     // https://html.spec.whatwg.org/multipage/syntax.html#parsing-html-fragments
276     // For efficiency, we skip step 5 ("Let root be a new html element with no attributes") and instead use the DocumentFragment as a root node.
277     m_tree.openElements().pushRootNode(HTMLStackItem::create(fragment));
278
279 #if ENABLE(TEMPLATE_ELEMENT)
280     if (contextElement.hasTagName(templateTag))
281         m_templateInsertionModes.append(InsertionMode::TemplateContents);
282 #endif
283
284     resetInsertionModeAppropriately();
285
286     m_tree.setForm(is<HTMLFormElement>(contextElement) ? &downcast<HTMLFormElement>(contextElement) : HTMLFormElement::findClosestFormAncestor(contextElement));
287
288 #if !ASSERT_DISABLED
289     m_destructionProhibited = false;
290 #endif
291 }
292
293 HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext()
294 {
295 }
296
297 HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext(DocumentFragment& fragment, Element& contextElement)
298     : m_fragment(&fragment)
299 {
300     ASSERT(!fragment.hasChildNodes());
301     m_contextElementStackItem = HTMLStackItem::create(contextElement);
302 }
303
304 inline Element& HTMLTreeBuilder::FragmentParsingContext::contextElement() const
305 {
306     return contextElementStackItem().element();
307 }
308
309 inline HTMLStackItem& HTMLTreeBuilder::FragmentParsingContext::contextElementStackItem() const
310 {
311     ASSERT(m_fragment);
312     return *m_contextElementStackItem;
313 }
314
315 RefPtr<Element> HTMLTreeBuilder::takeScriptToProcess(TextPosition& scriptStartPosition)
316 {
317     ASSERT(!m_destroyed);
318
319     if (!m_scriptToProcess)
320         return nullptr;
321
322     // Unpause ourselves, callers may pause us again when processing the script.
323     // The HTML5 spec is written as though scripts are executed inside the tree builder.
324     // We pause the parser to exit the tree builder, and then resume before running scripts.
325     scriptStartPosition = m_scriptToProcessStartPosition;
326     m_scriptToProcessStartPosition = uninitializedPositionValue1();
327     return WTF::move(m_scriptToProcess);
328 }
329
330 void HTMLTreeBuilder::constructTree(AtomicHTMLToken& token)
331 {
332 #if !ASSERT_DISABLED
333     ASSERT(!m_destroyed);
334     ASSERT(!m_destructionProhibited);
335     m_destructionProhibited = true;
336 #endif
337
338     if (shouldProcessTokenInForeignContent(token))
339         processTokenInForeignContent(token);
340     else
341         processToken(token);
342
343     bool inForeignContent = !m_tree.isEmpty()
344         && !isInHTMLNamespace(adjustedCurrentStackItem())
345         && !HTMLElementStack::isHTMLIntegrationPoint(m_tree.currentStackItem())
346         && !HTMLElementStack::isMathMLTextIntegrationPoint(m_tree.currentStackItem());
347
348     m_parser.tokenizer().setForceNullCharacterReplacement(m_insertionMode == InsertionMode::Text || inForeignContent);
349     m_parser.tokenizer().setShouldAllowCDATA(inForeignContent);
350
351 #if !ASSERT_DISABLED
352     m_destructionProhibited = false;
353 #endif
354
355     m_tree.executeQueuedTasks();
356     // The tree builder might have been destroyed as an indirect result of executing the queued tasks.
357 }
358
359 void HTMLTreeBuilder::processToken(AtomicHTMLToken& token)
360 {
361     switch (token.type()) {
362     case HTMLToken::Uninitialized:
363         ASSERT_NOT_REACHED();
364         break;
365     case HTMLToken::DOCTYPE:
366         m_shouldSkipLeadingNewline = false;
367         processDoctypeToken(token);
368         break;
369     case HTMLToken::StartTag:
370         m_shouldSkipLeadingNewline = false;
371         processStartTag(token);
372         break;
373     case HTMLToken::EndTag:
374         m_shouldSkipLeadingNewline = false;
375         processEndTag(token);
376         break;
377     case HTMLToken::Comment:
378         m_shouldSkipLeadingNewline = false;
379         processComment(token);
380         return;
381     case HTMLToken::Character:
382         processCharacter(token);
383         break;
384     case HTMLToken::EndOfFile:
385         m_shouldSkipLeadingNewline = false;
386         processEndOfFile(token);
387         break;
388     }
389 }
390
391 void HTMLTreeBuilder::processDoctypeToken(AtomicHTMLToken& token)
392 {
393     ASSERT(token.type() == HTMLToken::DOCTYPE);
394     if (m_insertionMode == InsertionMode::Initial) {
395         m_tree.insertDoctype(&token);
396         m_insertionMode = InsertionMode::BeforeHTML;
397         return;
398     }
399     if (m_insertionMode == InsertionMode::InTableText) {
400         defaultForInTableText();
401         processDoctypeToken(token);
402         return;
403     }
404     parseError(token);
405 }
406
407 void HTMLTreeBuilder::processFakeStartTag(const QualifiedName& tagName, Vector<Attribute>&& attributes)
408 {
409     // FIXME: We'll need a fancier conversion than just "localName" for SVG/MathML tags.
410     AtomicHTMLToken fakeToken(HTMLToken::StartTag, tagName.localName(), WTF::move(attributes));
411     processStartTag(fakeToken);
412 }
413
414 void HTMLTreeBuilder::processFakeEndTag(const AtomicString& tagName)
415 {
416     AtomicHTMLToken fakeToken(HTMLToken::EndTag, tagName);
417     processEndTag(fakeToken);
418 }
419
420 void HTMLTreeBuilder::processFakeEndTag(const QualifiedName& tagName)
421 {
422     // FIXME: We'll need a fancier conversion than just "localName" for SVG/MathML tags.
423     processFakeEndTag(tagName.localName());
424 }
425
426 void HTMLTreeBuilder::processFakeCharacters(const String& characters)
427 {
428     ASSERT(!characters.isEmpty());
429     ExternalCharacterTokenBuffer buffer(characters);
430     processCharacterBuffer(buffer);
431 }
432
433 void HTMLTreeBuilder::processFakePEndTagIfPInButtonScope()
434 {
435     if (!m_tree.openElements().inButtonScope(pTag.localName()))
436         return;
437     AtomicHTMLToken endP(HTMLToken::EndTag, pTag.localName());
438     processEndTag(endP);
439 }
440
441 Vector<Attribute> HTMLTreeBuilder::attributesForIsindexInput(AtomicHTMLToken& token)
442 {
443     Vector<Attribute> attributes = token.attributes();
444     attributes.removeAllMatching([] (const Attribute& attribute) {
445         const QualifiedName& name = attribute.name();
446         return name.matches(nameAttr) || name.matches(actionAttr) || name.matches(promptAttr);
447     });
448
449     attributes.append(Attribute(nameAttr, isindexTag.localName()));
450     return attributes;
451 }
452
453 void HTMLTreeBuilder::processIsindexStartTagForInBody(AtomicHTMLToken& token)
454 {
455     ASSERT(token.type() == HTMLToken::StartTag);
456     ASSERT(token.name() == isindexTag);
457     parseError(token);
458     if (m_tree.form() && !isParsingTemplateContents())
459         return;
460     notImplemented(); // Acknowledge self-closing flag
461     processFakeStartTag(formTag);
462     if (Attribute* actionAttribute = findAttribute(token.attributes(), actionAttr))
463         m_tree.form()->setAttribute(actionAttr, actionAttribute->value());
464     processFakeStartTag(hrTag);
465     processFakeStartTag(labelTag);
466     if (Attribute* promptAttribute = findAttribute(token.attributes(), promptAttr))
467         processFakeCharacters(promptAttribute->value());
468     else
469         processFakeCharacters(searchableIndexIntroduction());
470     processFakeStartTag(inputTag, attributesForIsindexInput(token));
471     notImplemented(); // This second set of characters may be needed by non-english locales.
472     processFakeEndTag(labelTag);
473     processFakeStartTag(hrTag);
474     processFakeEndTag(formTag);
475 }
476
477 namespace {
478
479 bool isLi(const HTMLStackItem& item)
480 {
481     return item.hasTagName(liTag);
482 }
483
484 bool isDdOrDt(const HTMLStackItem& item)
485 {
486     return item.hasTagName(ddTag) || item.hasTagName(dtTag);
487 }
488
489 }
490
491 template <bool shouldClose(const HTMLStackItem&)> void HTMLTreeBuilder::processCloseWhenNestedTag(AtomicHTMLToken& token)
492 {
493     m_framesetOk = false;
494     for (auto* nodeRecord = &m_tree.openElements().topRecord(); ; nodeRecord = nodeRecord->next()) {
495         HTMLStackItem& item = nodeRecord->stackItem();
496         if (shouldClose(item)) {
497             ASSERT(item.isElement());
498             processFakeEndTag(item.localName());
499             break;
500         }
501         if (isSpecialNode(item) && !item.hasTagName(addressTag) && !item.hasTagName(divTag) && !item.hasTagName(pTag))
502             break;
503     }
504     processFakePEndTagIfPInButtonScope();
505     m_tree.insertHTMLElement(&token);
506 }
507
508 template <typename TableQualifiedName> static HashMap<AtomicString, QualifiedName> createCaseMap(const TableQualifiedName* const names[], unsigned length)
509 {
510     HashMap<AtomicString, QualifiedName> map;
511     for (unsigned i = 0; i < length; ++i) {
512         const QualifiedName& name = *names[i];
513         const AtomicString& localName = name.localName();
514         AtomicString loweredLocalName = localName.lower();
515         if (loweredLocalName != localName)
516             map.add(loweredLocalName, name);
517     }
518     return map;
519 }
520
521 static void adjustSVGTagNameCase(AtomicHTMLToken& token)
522 {
523     static NeverDestroyed<HashMap<AtomicString, QualifiedName>> map = createCaseMap(SVGNames::getSVGTags(), SVGNames::SVGTagsCount);
524     const QualifiedName& casedName = map.get().get(token.name());
525     if (casedName.localName().isNull())
526         return;
527     token.setName(casedName.localName());
528 }
529
530 static inline void adjustAttributes(HashMap<AtomicString, QualifiedName>& map, AtomicHTMLToken& token)
531 {
532     for (auto& attribute : token.attributes()) {
533         const QualifiedName& casedName = map.get(attribute.localName());
534         if (!casedName.localName().isNull())
535             attribute.parserSetName(casedName);
536     }
537 }
538
539 template<const QualifiedName* const* attributesTable(), unsigned attributesTableLength> static void adjustAttributes(AtomicHTMLToken& token)
540 {
541     static NeverDestroyed<HashMap<AtomicString, QualifiedName>> map = createCaseMap(attributesTable(), attributesTableLength);
542     adjustAttributes(map, token);
543 }
544
545 static inline void adjustSVGAttributes(AtomicHTMLToken& token)
546 {
547     adjustAttributes<SVGNames::getSVGAttrs, SVGNames::SVGAttrsCount>(token);
548 }
549
550 static inline void adjustMathMLAttributes(AtomicHTMLToken& token)
551 {
552     adjustAttributes<MathMLNames::getMathMLAttrs, MathMLNames::MathMLAttrsCount>(token);
553 }
554
555 static void addNamesWithPrefix(HashMap<AtomicString, QualifiedName>& map, const AtomicString& prefix, const QualifiedName* const names[], unsigned length)
556 {
557     for (unsigned i = 0; i < length; ++i) {
558         const QualifiedName& name = *names[i];
559         const AtomicString& localName = name.localName();
560         map.add(prefix + ':' + localName, QualifiedName(prefix, localName, name.namespaceURI()));
561     }
562 }
563
564 static HashMap<AtomicString, QualifiedName> createForeignAttributesMap()
565 {
566     HashMap<AtomicString, QualifiedName> map;
567
568     addNamesWithPrefix(map, xlinkAtom, XLinkNames::getXLinkAttrs(), XLinkNames::XLinkAttrsCount);
569     addNamesWithPrefix(map, xmlAtom, XMLNames::getXMLAttrs(), XMLNames::XMLAttrsCount);
570
571     map.add(WTF::xmlnsAtom, XMLNSNames::xmlnsAttr);
572     map.add("xmlns:xlink", QualifiedName(xmlnsAtom, xlinkAtom, XMLNSNames::xmlnsNamespaceURI));
573
574     return map;
575 }
576
577 static void adjustForeignAttributes(AtomicHTMLToken& token)
578 {
579     static NeverDestroyed<HashMap<AtomicString, QualifiedName>> map = createForeignAttributesMap();
580     adjustAttributes(map, token);
581 }
582
583 void HTMLTreeBuilder::processStartTagForInBody(AtomicHTMLToken& token)
584 {
585     ASSERT(token.type() == HTMLToken::StartTag);
586     if (token.name() == htmlTag) {
587         processHtmlStartTagForInBody(token);
588         return;
589     }
590     if (token.name() == baseTag
591         || token.name() == basefontTag
592         || token.name() == bgsoundTag
593         || token.name() == commandTag
594         || token.name() == linkTag
595         || token.name() == metaTag
596         || token.name() == noframesTag
597         || token.name() == scriptTag
598         || token.name() == styleTag
599         || token.name() == titleTag) {
600         bool didProcess = processStartTagForInHead(token);
601         ASSERT_UNUSED(didProcess, didProcess);
602         return;
603     }
604     if (token.name() == bodyTag) {
605         parseError(token);
606         bool fragmentOrTemplateCase = !m_tree.openElements().secondElementIsHTMLBodyElement() || m_tree.openElements().hasOnlyOneElement();
607 #if ENABLE(TEMPLATE_ELEMENT)
608         fragmentOrTemplateCase = fragmentOrTemplateCase || m_tree.openElements().hasTemplateInHTMLScope();
609 #endif
610         if (fragmentOrTemplateCase) {
611             ASSERT(isParsingFragmentOrTemplateContents());
612             return;
613         }
614         m_framesetOk = false;
615         m_tree.insertHTMLBodyStartTagInBody(&token);
616         return;
617     }
618     if (token.name() == framesetTag) {
619         parseError(token);
620         if (!m_tree.openElements().secondElementIsHTMLBodyElement() || m_tree.openElements().hasOnlyOneElement()) {
621             ASSERT(isParsingFragmentOrTemplateContents());
622             return;
623         }
624         if (!m_framesetOk)
625             return;
626         m_tree.openElements().bodyElement().remove(ASSERT_NO_EXCEPTION);
627         m_tree.openElements().popUntil(&m_tree.openElements().bodyElement());
628         m_tree.openElements().popHTMLBodyElement();
629         ASSERT(&m_tree.openElements().top() == &m_tree.openElements().htmlElement());
630         m_tree.insertHTMLElement(&token);
631         m_insertionMode = InsertionMode::InFrameset;
632         return;
633     }
634     if (token.name() == addressTag
635         || token.name() == articleTag
636         || token.name() == asideTag
637         || token.name() == blockquoteTag
638         || token.name() == centerTag
639         || token.name() == detailsTag
640         || token.name() == dirTag
641         || token.name() == divTag
642         || token.name() == dlTag
643         || token.name() == fieldsetTag
644         || token.name() == figcaptionTag
645         || token.name() == figureTag
646         || token.name() == footerTag
647         || token.name() == headerTag
648         || token.name() == hgroupTag
649         || token.name() == mainTag
650         || token.name() == menuTag
651         || token.name() == navTag
652         || token.name() == olTag
653         || token.name() == pTag
654         || token.name() == sectionTag
655         || token.name() == summaryTag
656         || token.name() == ulTag) {
657         processFakePEndTagIfPInButtonScope();
658         m_tree.insertHTMLElement(&token);
659         return;
660     }
661     if (isNumberedHeaderTag(token.name())) {
662         processFakePEndTagIfPInButtonScope();
663         if (isNumberedHeaderElement(m_tree.currentStackItem())) {
664             parseError(token);
665             m_tree.openElements().pop();
666         }
667         m_tree.insertHTMLElement(&token);
668         return;
669     }
670     if (token.name() == preTag || token.name() == listingTag) {
671         processFakePEndTagIfPInButtonScope();
672         m_tree.insertHTMLElement(&token);
673         m_shouldSkipLeadingNewline = true;
674         m_framesetOk = false;
675         return;
676     }
677     if (token.name() == formTag) {
678         if (m_tree.form() && !isParsingTemplateContents()) {
679             parseError(token);
680             return;
681         }
682         processFakePEndTagIfPInButtonScope();
683         m_tree.insertHTMLFormElement(&token);
684         return;
685     }
686     if (token.name() == liTag) {
687         processCloseWhenNestedTag<isLi>(token);
688         return;
689     }
690     if (token.name() == ddTag || token.name() == dtTag) {
691         processCloseWhenNestedTag<isDdOrDt>(token);
692         return;
693     }
694     if (token.name() == plaintextTag) {
695         processFakePEndTagIfPInButtonScope();
696         m_tree.insertHTMLElement(&token);
697         m_parser.tokenizer().setPLAINTEXTState();
698         return;
699     }
700     if (token.name() == buttonTag) {
701         if (m_tree.openElements().inScope(buttonTag)) {
702             parseError(token);
703             processFakeEndTag(buttonTag);
704             processStartTag(token); // FIXME: Could we just fall through here?
705             return;
706         }
707         m_tree.reconstructTheActiveFormattingElements();
708         m_tree.insertHTMLElement(&token);
709         m_framesetOk = false;
710         return;
711     }
712     if (token.name() == aTag) {
713         Element* activeATag = m_tree.activeFormattingElements().closestElementInScopeWithName(aTag.localName());
714         if (activeATag) {
715             parseError(token);
716             processFakeEndTag(aTag);
717             m_tree.activeFormattingElements().remove(activeATag);
718             if (m_tree.openElements().contains(activeATag))
719                 m_tree.openElements().remove(activeATag);
720         }
721         m_tree.reconstructTheActiveFormattingElements();
722         m_tree.insertFormattingElement(&token);
723         return;
724     }
725     if (isNonAnchorNonNobrFormattingTag(token.name())) {
726         m_tree.reconstructTheActiveFormattingElements();
727         m_tree.insertFormattingElement(&token);
728         return;
729     }
730     if (token.name() == nobrTag) {
731         m_tree.reconstructTheActiveFormattingElements();
732         if (m_tree.openElements().inScope(nobrTag)) {
733             parseError(token);
734             processFakeEndTag(nobrTag);
735             m_tree.reconstructTheActiveFormattingElements();
736         }
737         m_tree.insertFormattingElement(&token);
738         return;
739     }
740     if (token.name() == appletTag || token.name() == embedTag || token.name() == objectTag) {
741         if (!pluginContentIsAllowed(m_tree.parserContentPolicy()))
742             return;
743     }
744     if (token.name() == appletTag || token.name() == marqueeTag || token.name() == objectTag) {
745         m_tree.reconstructTheActiveFormattingElements();
746         m_tree.insertHTMLElement(&token);
747         m_tree.activeFormattingElements().appendMarker();
748         m_framesetOk = false;
749         return;
750     }
751     if (token.name() == tableTag) {
752         if (!m_tree.inQuirksMode() && m_tree.openElements().inButtonScope(pTag))
753             processFakeEndTag(pTag);
754         m_tree.insertHTMLElement(&token);
755         m_framesetOk = false;
756         m_insertionMode = InsertionMode::InTable;
757         return;
758     }
759     if (token.name() == imageTag) {
760         parseError(token);
761         // Apparently we're not supposed to ask.
762         token.setName(imgTag.localName());
763         // Note the fall through to the imgTag handling below!
764     }
765     if (token.name() == areaTag
766         || token.name() == brTag
767         || token.name() == embedTag
768         || token.name() == imgTag
769         || token.name() == keygenTag
770         || token.name() == wbrTag) {
771         m_tree.reconstructTheActiveFormattingElements();
772         m_tree.insertSelfClosingHTMLElement(&token);
773         m_framesetOk = false;
774         return;
775     }
776     if (token.name() == inputTag) {
777         m_tree.reconstructTheActiveFormattingElements();
778         m_tree.insertSelfClosingHTMLElement(&token);
779         Attribute* typeAttribute = findAttribute(token.attributes(), typeAttr);
780         if (!typeAttribute || !equalIgnoringCase(typeAttribute->value(), "hidden"))
781             m_framesetOk = false;
782         return;
783     }
784     if (token.name() == paramTag || token.name() == sourceTag || token.name() == trackTag) {
785         m_tree.insertSelfClosingHTMLElement(&token);
786         return;
787     }
788     if (token.name() == hrTag) {
789         processFakePEndTagIfPInButtonScope();
790         m_tree.insertSelfClosingHTMLElement(&token);
791         m_framesetOk = false;
792         return;
793     }
794     if (token.name() == isindexTag) {
795         processIsindexStartTagForInBody(token);
796         return;
797     }
798     if (token.name() == textareaTag) {
799         m_tree.insertHTMLElement(&token);
800         m_shouldSkipLeadingNewline = true;
801         m_parser.tokenizer().setRCDATAState();
802         m_originalInsertionMode = m_insertionMode;
803         m_framesetOk = false;
804         m_insertionMode = InsertionMode::Text;
805         return;
806     }
807     if (token.name() == xmpTag) {
808         processFakePEndTagIfPInButtonScope();
809         m_tree.reconstructTheActiveFormattingElements();
810         m_framesetOk = false;
811         processGenericRawTextStartTag(token);
812         return;
813     }
814     if (token.name() == iframeTag) {
815         m_framesetOk = false;
816         processGenericRawTextStartTag(token);
817         return;
818     }
819     if (token.name() == noembedTag && m_options.pluginsEnabled) {
820         processGenericRawTextStartTag(token);
821         return;
822     }
823     if (token.name() == noscriptTag && m_options.scriptEnabled) {
824         processGenericRawTextStartTag(token);
825         return;
826     }
827     if (token.name() == selectTag) {
828         m_tree.reconstructTheActiveFormattingElements();
829         m_tree.insertHTMLElement(&token);
830         m_framesetOk = false;
831         if (m_insertionMode == InsertionMode::InTable
832             || m_insertionMode == InsertionMode::InCaption
833             || m_insertionMode == InsertionMode::InColumnGroup
834             || m_insertionMode == InsertionMode::InTableBody
835             || m_insertionMode == InsertionMode::InRow
836             || m_insertionMode == InsertionMode::InCell)
837             m_insertionMode = InsertionMode::InSelectInTable;
838         else
839             m_insertionMode = InsertionMode::InSelect;
840         return;
841     }
842     if (token.name() == optgroupTag || token.name() == optionTag) {
843         if (is<HTMLOptionElement>(m_tree.currentStackItem().node())) {
844             AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName());
845             processEndTag(endOption);
846         }
847         m_tree.reconstructTheActiveFormattingElements();
848         m_tree.insertHTMLElement(&token);
849         return;
850     }
851     if (token.name() == rbTag || token.name() == rtcTag) {
852         if (m_tree.openElements().inScope(rubyTag.localName())) {
853             m_tree.generateImpliedEndTags();
854             if (!m_tree.currentStackItem().hasTagName(rubyTag))
855                 parseError(token);
856         }
857         m_tree.insertHTMLElement(&token);
858         return;
859     }
860     if (token.name() == rtTag || token.name() == rpTag) {
861         if (m_tree.openElements().inScope(rubyTag.localName())) {
862             m_tree.generateImpliedEndTagsWithExclusion(rtcTag.localName());
863             if (!m_tree.currentStackItem().hasTagName(rubyTag) && !m_tree.currentStackItem().hasTagName(rtcTag))
864                 parseError(token);
865         }
866         m_tree.insertHTMLElement(&token);
867         return;
868     }
869     if (token.name() == MathMLNames::mathTag.localName()) {
870         m_tree.reconstructTheActiveFormattingElements();
871         adjustMathMLAttributes(token);
872         adjustForeignAttributes(token);
873         m_tree.insertForeignElement(&token, MathMLNames::mathmlNamespaceURI);
874         return;
875     }
876     if (token.name() == SVGNames::svgTag.localName()) {
877         m_tree.reconstructTheActiveFormattingElements();
878         adjustSVGAttributes(token);
879         adjustForeignAttributes(token);
880         m_tree.insertForeignElement(&token, SVGNames::svgNamespaceURI);
881         return;
882     }
883     if (isCaptionColOrColgroupTag(token.name())
884         || token.name() == frameTag
885         || token.name() == headTag
886         || isTableBodyContextTag(token.name())
887         || isTableCellContextTag(token.name())
888         || token.name() == trTag) {
889         parseError(token);
890         return;
891     }
892 #if ENABLE(TEMPLATE_ELEMENT)
893     if (token.name() == templateTag) {
894         processTemplateStartTag(token);
895         return;
896     }
897 #endif
898     m_tree.reconstructTheActiveFormattingElements();
899     m_tree.insertHTMLElement(&token);
900 }
901
902 #if ENABLE(TEMPLATE_ELEMENT)
903
904 void HTMLTreeBuilder::processTemplateStartTag(AtomicHTMLToken& token)
905 {
906     m_tree.activeFormattingElements().appendMarker();
907     m_tree.insertHTMLElement(&token);
908     m_templateInsertionModes.append(InsertionMode::TemplateContents);
909     m_insertionMode = InsertionMode::TemplateContents;
910 }
911
912 bool HTMLTreeBuilder::processTemplateEndTag(AtomicHTMLToken& token)
913 {
914     ASSERT(token.name() == templateTag.localName());
915     if (!m_tree.openElements().hasTemplateInHTMLScope()) {
916         ASSERT(m_templateInsertionModes.isEmpty() || (m_templateInsertionModes.size() == 1 && m_fragmentContext.contextElement().hasTagName(templateTag)));
917         parseError(token);
918         return false;
919     }
920     m_tree.generateImpliedEndTags();
921     if (!m_tree.currentStackItem().hasTagName(templateTag))
922         parseError(token);
923     m_tree.openElements().popUntilPopped(templateTag);
924     m_tree.activeFormattingElements().clearToLastMarker();
925     m_templateInsertionModes.removeLast();
926     resetInsertionModeAppropriately();
927     return true;
928 }
929
930 bool HTMLTreeBuilder::processEndOfFileForInTemplateContents(AtomicHTMLToken& token)
931 {
932     AtomicHTMLToken endTemplate(HTMLToken::EndTag, templateTag.localName());
933     if (!processTemplateEndTag(endTemplate))
934         return false;
935
936     processEndOfFile(token);
937     return true;
938 }
939
940 #endif
941
942 bool HTMLTreeBuilder::processColgroupEndTagForInColumnGroup()
943 {
944     bool ignoreFakeEndTag = m_tree.currentIsRootNode();
945 #if ENABLE(TEMPLATE_ELEMENT)
946     ignoreFakeEndTag = ignoreFakeEndTag || m_tree.currentNode().hasTagName(templateTag);
947 #endif
948
949     if (ignoreFakeEndTag) {
950         ASSERT(isParsingFragmentOrTemplateContents());
951         // FIXME: parse error
952         return false;
953     }
954     m_tree.openElements().pop();
955     m_insertionMode = InsertionMode::InTable;
956     return true;
957 }
958
959 // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#close-the-cell
960 void HTMLTreeBuilder::closeTheCell()
961 {
962     ASSERT(m_insertionMode == InsertionMode::InCell);
963     if (m_tree.openElements().inTableScope(tdTag)) {
964         ASSERT(!m_tree.openElements().inTableScope(thTag));
965         processFakeEndTag(tdTag);
966         return;
967     }
968     ASSERT(m_tree.openElements().inTableScope(thTag));
969     processFakeEndTag(thTag);
970     ASSERT(m_insertionMode == InsertionMode::InRow);
971 }
972
973 void HTMLTreeBuilder::processStartTagForInTable(AtomicHTMLToken& token)
974 {
975     ASSERT(token.type() == HTMLToken::StartTag);
976     if (token.name() == captionTag) {
977         m_tree.openElements().popUntilTableScopeMarker();
978         m_tree.activeFormattingElements().appendMarker();
979         m_tree.insertHTMLElement(&token);
980         m_insertionMode = InsertionMode::InCaption;
981         return;
982     }
983     if (token.name() == colgroupTag) {
984         m_tree.openElements().popUntilTableScopeMarker();
985         m_tree.insertHTMLElement(&token);
986         m_insertionMode = InsertionMode::InColumnGroup;
987         return;
988     }
989     if (token.name() == colTag) {
990         processFakeStartTag(colgroupTag);
991         ASSERT(m_insertionMode == InsertionMode::InColumnGroup);
992         processStartTag(token);
993         return;
994     }
995     if (isTableBodyContextTag(token.name())) {
996         m_tree.openElements().popUntilTableScopeMarker();
997         m_tree.insertHTMLElement(&token);
998         m_insertionMode = InsertionMode::InTableBody;
999         return;
1000     }
1001     if (isTableCellContextTag(token.name()) || token.name() == trTag) {
1002         processFakeStartTag(tbodyTag);
1003         ASSERT(m_insertionMode == InsertionMode::InTableBody);
1004         processStartTag(token);
1005         return;
1006     }
1007     if (token.name() == tableTag) {
1008         parseError(token);
1009         if (!processTableEndTagForInTable()) {
1010             ASSERT(isParsingFragmentOrTemplateContents());
1011             return;
1012         }
1013         processStartTag(token);
1014         return;
1015     }
1016     if (token.name() == styleTag || token.name() == scriptTag) {
1017         processStartTagForInHead(token);
1018         return;
1019     }
1020     if (token.name() == inputTag) {
1021         Attribute* typeAttribute = findAttribute(token.attributes(), typeAttr);
1022         if (typeAttribute && equalIgnoringCase(typeAttribute->value(), "hidden")) {
1023             parseError(token);
1024             m_tree.insertSelfClosingHTMLElement(&token);
1025             return;
1026         }
1027         // Fall through to "anything else" case.
1028     }
1029     if (token.name() == formTag) {
1030         parseError(token);
1031         if (m_tree.form() && !isParsingTemplateContents())
1032             return;
1033         m_tree.insertHTMLFormElement(&token, true);
1034         m_tree.openElements().pop();
1035         return;
1036     }
1037 #if ENABLE(TEMPLATE_ELEMENT)
1038     if (token.name() == templateTag) {
1039         processTemplateStartTag(token);
1040         return;
1041     }
1042 #endif
1043     parseError(token);
1044     HTMLConstructionSite::RedirectToFosterParentGuard redirecter(m_tree);
1045     processStartTagForInBody(token);
1046 }
1047
1048 void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token)
1049 {
1050     ASSERT(token.type() == HTMLToken::StartTag);
1051     switch (m_insertionMode) {
1052     case InsertionMode::Initial:
1053         defaultForInitial();
1054         ASSERT(m_insertionMode == InsertionMode::BeforeHTML);
1055         FALLTHROUGH;
1056     case InsertionMode::BeforeHTML:
1057         if (token.name() == htmlTag) {
1058             m_tree.insertHTMLHtmlStartTagBeforeHTML(&token);
1059             m_insertionMode = InsertionMode::BeforeHead;
1060             return;
1061         }
1062         defaultForBeforeHTML();
1063         ASSERT(m_insertionMode == InsertionMode::BeforeHead);
1064         FALLTHROUGH;
1065     case InsertionMode::BeforeHead:
1066         if (token.name() == htmlTag) {
1067             processHtmlStartTagForInBody(token);
1068             return;
1069         }
1070         if (token.name() == headTag) {
1071             m_tree.insertHTMLHeadElement(&token);
1072             m_insertionMode = InsertionMode::InHead;
1073             return;
1074         }
1075         defaultForBeforeHead();
1076         ASSERT(m_insertionMode == InsertionMode::InHead);
1077         FALLTHROUGH;
1078     case InsertionMode::InHead:
1079         if (processStartTagForInHead(token))
1080             return;
1081         defaultForInHead();
1082         ASSERT(m_insertionMode == InsertionMode::AfterHead);
1083         FALLTHROUGH;
1084     case InsertionMode::AfterHead:
1085         if (token.name() == htmlTag) {
1086             processHtmlStartTagForInBody(token);
1087             return;
1088         }
1089         if (token.name() == bodyTag) {
1090             m_framesetOk = false;
1091             m_tree.insertHTMLBodyElement(&token);
1092             m_insertionMode = InsertionMode::InBody;
1093             return;
1094         }
1095         if (token.name() == framesetTag) {
1096             m_tree.insertHTMLElement(&token);
1097             m_insertionMode = InsertionMode::InFrameset;
1098             return;
1099         }
1100         if (token.name() == baseTag
1101             || token.name() == basefontTag
1102             || token.name() == bgsoundTag
1103             || token.name() == linkTag
1104             || token.name() == metaTag
1105             || token.name() == noframesTag
1106             || token.name() == scriptTag
1107             || token.name() == styleTag
1108 #if ENABLE(TEMPLATE_ELEMENT)
1109             || token.name() == templateTag
1110 #endif
1111             || token.name() == titleTag) {
1112             parseError(token);
1113             m_tree.openElements().pushHTMLHeadElement(m_tree.headStackItem());
1114             processStartTagForInHead(token);
1115             m_tree.openElements().removeHTMLHeadElement(&m_tree.head());
1116             return;
1117         }
1118         if (token.name() == headTag) {
1119             parseError(token);
1120             return;
1121         }
1122         defaultForAfterHead();
1123         ASSERT(m_insertionMode == InsertionMode::InBody);
1124         FALLTHROUGH;
1125     case InsertionMode::InBody:
1126         processStartTagForInBody(token);
1127         break;
1128     case InsertionMode::InTable:
1129         processStartTagForInTable(token);
1130         break;
1131     case InsertionMode::InCaption:
1132         if (isCaptionColOrColgroupTag(token.name())
1133             || isTableBodyContextTag(token.name())
1134             || isTableCellContextTag(token.name())
1135             || token.name() == trTag) {
1136             parseError(token);
1137             if (!processCaptionEndTagForInCaption()) {
1138                 ASSERT(isParsingFragment());
1139                 return;
1140             }
1141             processStartTag(token);
1142             return;
1143         }
1144         processStartTagForInBody(token);
1145         break;
1146     case InsertionMode::InColumnGroup:
1147         if (token.name() == htmlTag) {
1148             processHtmlStartTagForInBody(token);
1149             return;
1150         }
1151         if (token.name() == colTag) {
1152             m_tree.insertSelfClosingHTMLElement(&token);
1153             return;
1154         }
1155 #if ENABLE(TEMPLATE_ELEMENT)
1156         if (token.name() == templateTag) {
1157             processTemplateStartTag(token);
1158             return;
1159         }
1160 #endif
1161         if (!processColgroupEndTagForInColumnGroup()) {
1162             ASSERT(isParsingFragmentOrTemplateContents());
1163             return;
1164         }
1165         processStartTag(token);
1166         break;
1167     case InsertionMode::InTableBody:
1168         if (token.name() == trTag) {
1169             m_tree.openElements().popUntilTableBodyScopeMarker(); // How is there ever anything to pop?
1170             m_tree.insertHTMLElement(&token);
1171             m_insertionMode = InsertionMode::InRow;
1172             return;
1173         }
1174         if (isTableCellContextTag(token.name())) {
1175             parseError(token);
1176             processFakeStartTag(trTag);
1177             ASSERT(m_insertionMode == InsertionMode::InRow);
1178             processStartTag(token);
1179             return;
1180         }
1181         if (isCaptionColOrColgroupTag(token.name()) || isTableBodyContextTag(token.name())) {
1182             // FIXME: This is slow.
1183             if (!m_tree.openElements().inTableScope(tbodyTag) && !m_tree.openElements().inTableScope(theadTag) && !m_tree.openElements().inTableScope(tfootTag)) {
1184                 ASSERT(isParsingFragmentOrTemplateContents());
1185                 parseError(token);
1186                 return;
1187             }
1188             m_tree.openElements().popUntilTableBodyScopeMarker();
1189             ASSERT(isTableBodyContextTag(m_tree.currentStackItem().localName()));
1190             processFakeEndTag(m_tree.currentStackItem().localName());
1191             processStartTag(token);
1192             return;
1193         }
1194         processStartTagForInTable(token);
1195         break;
1196     case InsertionMode::InRow:
1197         if (isTableCellContextTag(token.name())) {
1198             m_tree.openElements().popUntilTableRowScopeMarker();
1199             m_tree.insertHTMLElement(&token);
1200             m_insertionMode = InsertionMode::InCell;
1201             m_tree.activeFormattingElements().appendMarker();
1202             return;
1203         }
1204         if (token.name() == trTag
1205             || isCaptionColOrColgroupTag(token.name())
1206             || isTableBodyContextTag(token.name())) {
1207             if (!processTrEndTagForInRow()) {
1208                 ASSERT(isParsingFragmentOrTemplateContents());
1209                 return;
1210             }
1211             ASSERT(m_insertionMode == InsertionMode::InTableBody);
1212             processStartTag(token);
1213             return;
1214         }
1215         processStartTagForInTable(token);
1216         break;
1217     case InsertionMode::InCell:
1218         if (isCaptionColOrColgroupTag(token.name())
1219             || isTableCellContextTag(token.name())
1220             || token.name() == trTag
1221             || isTableBodyContextTag(token.name())) {
1222             // FIXME: This could be more efficient.
1223             if (!m_tree.openElements().inTableScope(tdTag) && !m_tree.openElements().inTableScope(thTag)) {
1224                 ASSERT(isParsingFragment());
1225                 parseError(token);
1226                 return;
1227             }
1228             closeTheCell();
1229             processStartTag(token);
1230             return;
1231         }
1232         processStartTagForInBody(token);
1233         break;
1234     case InsertionMode::AfterBody:
1235     case InsertionMode::AfterAfterBody:
1236         if (token.name() == htmlTag) {
1237             processHtmlStartTagForInBody(token);
1238             return;
1239         }
1240         m_insertionMode = InsertionMode::InBody;
1241         processStartTag(token);
1242         break;
1243     case InsertionMode::InHeadNoscript:
1244         if (token.name() == htmlTag) {
1245             processHtmlStartTagForInBody(token);
1246             return;
1247         }
1248         if (token.name() == basefontTag
1249             || token.name() == bgsoundTag
1250             || token.name() == linkTag
1251             || token.name() == metaTag
1252             || token.name() == noframesTag
1253             || token.name() == styleTag) {
1254             bool didProcess = processStartTagForInHead(token);
1255             ASSERT_UNUSED(didProcess, didProcess);
1256             return;
1257         }
1258         if (token.name() == htmlTag || token.name() == noscriptTag) {
1259             parseError(token);
1260             return;
1261         }
1262         defaultForInHeadNoscript();
1263         processToken(token);
1264         break;
1265     case InsertionMode::InFrameset:
1266         if (token.name() == htmlTag) {
1267             processHtmlStartTagForInBody(token);
1268             return;
1269         }
1270         if (token.name() == framesetTag) {
1271             m_tree.insertHTMLElement(&token);
1272             return;
1273         }
1274         if (token.name() == frameTag) {
1275             m_tree.insertSelfClosingHTMLElement(&token);
1276             return;
1277         }
1278         if (token.name() == noframesTag) {
1279             processStartTagForInHead(token);
1280             return;
1281         }
1282 #if ENABLE(TEMPLATE_ELEMENT)
1283         if (token.name() == templateTag) {
1284             processTemplateStartTag(token);
1285             return;
1286         }
1287 #endif
1288         parseError(token);
1289         break;
1290     case InsertionMode::AfterFrameset:
1291     case InsertionMode::AfterAfterFrameset:
1292         if (token.name() == htmlTag) {
1293             processHtmlStartTagForInBody(token);
1294             return;
1295         }
1296         if (token.name() == noframesTag) {
1297             processStartTagForInHead(token);
1298             return;
1299         }
1300         parseError(token);
1301         break;
1302     case InsertionMode::InSelectInTable:
1303         if (token.name() == captionTag
1304             || token.name() == tableTag
1305             || isTableBodyContextTag(token.name())
1306             || token.name() == trTag
1307             || isTableCellContextTag(token.name())) {
1308             parseError(token);
1309             AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName());
1310             processEndTag(endSelect);
1311             processStartTag(token);
1312             return;
1313         }
1314         FALLTHROUGH;
1315     case InsertionMode::InSelect:
1316         if (token.name() == htmlTag) {
1317             processHtmlStartTagForInBody(token);
1318             return;
1319         }
1320         if (token.name() == optionTag) {
1321             if (is<HTMLOptionElement>(m_tree.currentStackItem().node())) {
1322                 AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName());
1323                 processEndTag(endOption);
1324             }
1325             m_tree.insertHTMLElement(&token);
1326             return;
1327         }
1328         if (token.name() == optgroupTag) {
1329             if (is<HTMLOptionElement>(m_tree.currentStackItem().node())) {
1330                 AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName());
1331                 processEndTag(endOption);
1332             }
1333             if (is<HTMLOptGroupElement>(m_tree.currentStackItem().node())) {
1334                 AtomicHTMLToken endOptgroup(HTMLToken::EndTag, optgroupTag.localName());
1335                 processEndTag(endOptgroup);
1336             }
1337             m_tree.insertHTMLElement(&token);
1338             return;
1339         }
1340         if (token.name() == selectTag) {
1341             parseError(token);
1342             AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName());
1343             processEndTag(endSelect);
1344             return;
1345         }
1346         if (token.name() == inputTag || token.name() == keygenTag || token.name() == textareaTag) {
1347             parseError(token);
1348             if (!m_tree.openElements().inSelectScope(selectTag)) {
1349                 ASSERT(isParsingFragment());
1350                 return;
1351             }
1352             AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName());
1353             processEndTag(endSelect);
1354             processStartTag(token);
1355             return;
1356         }
1357         if (token.name() == scriptTag) {
1358             bool didProcess = processStartTagForInHead(token);
1359             ASSERT_UNUSED(didProcess, didProcess);
1360             return;
1361         }
1362 #if ENABLE(TEMPLATE_ELEMENT)
1363         if (token.name() == templateTag) {
1364             processTemplateStartTag(token);
1365             return;
1366         }
1367 #endif
1368         break;
1369     case InsertionMode::InTableText:
1370         defaultForInTableText();
1371         processStartTag(token);
1372         break;
1373     case InsertionMode::Text:
1374         ASSERT_NOT_REACHED();
1375         break;
1376 #if ENABLE(TEMPLATE_ELEMENT)
1377     case InsertionMode::TemplateContents:
1378         if (token.name() == templateTag) {
1379             processTemplateStartTag(token);
1380             return;
1381         }
1382
1383         if (token.name() == linkTag
1384             || token.name() == scriptTag
1385             || token.name() == styleTag
1386             || token.name() == metaTag) {
1387             processStartTagForInHead(token);
1388             return;
1389         }
1390
1391         InsertionMode insertionMode = InsertionMode::TemplateContents;
1392         if (token.name() == frameTag)
1393             insertionMode = InsertionMode::InFrameset;
1394         else if (token.name() == colTag)
1395             insertionMode = InsertionMode::InColumnGroup;
1396         else if (isCaptionColOrColgroupTag(token.name()) || isTableBodyContextTag(token.name()))
1397             insertionMode = InsertionMode::InTable;
1398         else if (token.name() == trTag)
1399             insertionMode = InsertionMode::InTableBody;
1400         else if (isTableCellContextTag(token.name()))
1401             insertionMode = InsertionMode::InRow;
1402         else
1403             insertionMode = InsertionMode::InBody;
1404
1405         ASSERT(insertionMode != InsertionMode::TemplateContents);
1406         ASSERT(m_templateInsertionModes.last() == InsertionMode::TemplateContents);
1407         m_templateInsertionModes.last() = insertionMode;
1408         m_insertionMode = insertionMode;
1409
1410         processStartTag(token);
1411         break;
1412 #endif
1413     }
1414 }
1415
1416 void HTMLTreeBuilder::processHtmlStartTagForInBody(AtomicHTMLToken& token)
1417 {
1418     parseError(token);
1419 #if ENABLE(TEMPLATE_ELEMENT)
1420     if (m_tree.openElements().hasTemplateInHTMLScope()) {
1421         ASSERT(isParsingTemplateContents());
1422         return;
1423     }
1424 #endif
1425     m_tree.insertHTMLHtmlStartTagInBody(&token);
1426 }
1427
1428 bool HTMLTreeBuilder::processBodyEndTagForInBody(AtomicHTMLToken& token)
1429 {
1430     ASSERT(token.type() == HTMLToken::EndTag);
1431     ASSERT(token.name() == bodyTag);
1432     if (!m_tree.openElements().inScope(bodyTag.localName())) {
1433         parseError(token);
1434         return false;
1435     }
1436     notImplemented(); // Emit a more specific parse error based on stack contents.
1437     m_insertionMode = InsertionMode::AfterBody;
1438     return true;
1439 }
1440
1441 void HTMLTreeBuilder::processAnyOtherEndTagForInBody(AtomicHTMLToken& token)
1442 {
1443     ASSERT(token.type() == HTMLToken::EndTag);
1444     for (auto* record = &m_tree.openElements().topRecord(); ; record = record->next()) {
1445         HTMLStackItem& item = record->stackItem();
1446         if (item.matchesHTMLTag(token.name())) {
1447             m_tree.generateImpliedEndTagsWithExclusion(token.name());
1448             if (!m_tree.currentStackItem().matchesHTMLTag(token.name()))
1449                 parseError(token);
1450             m_tree.openElements().popUntilPopped(&item.element());
1451             return;
1452         }
1453         if (isSpecialNode(item)) {
1454             parseError(token);
1455             return;
1456         }
1457     }
1458 }
1459
1460 // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-inbody
1461 void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken& token)
1462 {
1463     // The adoption agency algorithm is N^2. We limit the number of iterations
1464     // to stop from hanging the whole browser. This limit is specified in the
1465     // adoption agency algorithm: 
1466     // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#parsing-main-inbody
1467     static const int outerIterationLimit = 8;
1468     static const int innerIterationLimit = 3;
1469
1470     // 1, 2, 3 and 16 are covered by the for() loop.
1471     for (int i = 0; i < outerIterationLimit; ++i) {
1472         // 4.
1473         Element* formattingElement = m_tree.activeFormattingElements().closestElementInScopeWithName(token.name());
1474         // 4.a
1475         if (!formattingElement)
1476             return processAnyOtherEndTagForInBody(token);
1477         // 4.c
1478         if ((m_tree.openElements().contains(formattingElement)) && !m_tree.openElements().inScope(formattingElement)) {
1479             parseError(token);
1480             notImplemented(); // Check the stack of open elements for a more specific parse error.
1481             return;
1482         }
1483         // 4.b
1484         auto* formattingElementRecord = m_tree.openElements().find(formattingElement);
1485         if (!formattingElementRecord) {
1486             parseError(token);
1487             m_tree.activeFormattingElements().remove(formattingElement);
1488             return;
1489         }
1490         // 4.d
1491         if (formattingElement != &m_tree.currentElement())
1492             parseError(token);
1493         // 5.
1494         auto* furthestBlock = m_tree.openElements().furthestBlockForFormattingElement(formattingElement);
1495         // 6.
1496         if (!furthestBlock) {
1497             m_tree.openElements().popUntilPopped(formattingElement);
1498             m_tree.activeFormattingElements().remove(formattingElement);
1499             return;
1500         }
1501         // 7.
1502         ASSERT(furthestBlock->isAbove(formattingElementRecord));
1503         Ref<HTMLStackItem> commonAncestor = formattingElementRecord->next()->stackItem();
1504         // 8.
1505         HTMLFormattingElementList::Bookmark bookmark = m_tree.activeFormattingElements().bookmarkFor(formattingElement);
1506         // 9.
1507         auto* node = furthestBlock;
1508         auto* nextNode = node->next();
1509         auto* lastNode = furthestBlock;
1510         // 9.1, 9.2, 9.3 and 9.11 are covered by the for() loop.
1511         for (int i = 0; i < innerIterationLimit; ++i) {
1512             // 9.4
1513             node = nextNode;
1514             ASSERT(node);
1515             nextNode = node->next(); // Save node->next() for the next iteration in case node is deleted in 9.5.
1516             // 9.5
1517             if (!m_tree.activeFormattingElements().contains(&node->element())) {
1518                 m_tree.openElements().remove(&node->element());
1519                 node = 0;
1520                 continue;
1521             }
1522             // 9.6
1523             if (node == formattingElementRecord)
1524                 break;
1525             // 9.7
1526             RefPtr<HTMLStackItem> newItem = m_tree.createElementFromSavedToken(&node->stackItem());
1527
1528             HTMLFormattingElementList::Entry* nodeEntry = m_tree.activeFormattingElements().find(&node->element());
1529             nodeEntry->replaceElement(newItem.copyRef());
1530             node->replaceElement(newItem.release());
1531
1532             // 9.8
1533             if (lastNode == furthestBlock)
1534                 bookmark.moveToAfter(nodeEntry);
1535             // 9.9
1536             m_tree.reparent(*node, *lastNode);
1537             // 9.10
1538             lastNode = node;
1539         }
1540         // 10.
1541         m_tree.insertAlreadyParsedChild(commonAncestor.get(), *lastNode);
1542         // 11.
1543         RefPtr<HTMLStackItem> newItem = m_tree.createElementFromSavedToken(&formattingElementRecord->stackItem());
1544         // 12.
1545         m_tree.takeAllChildren(*newItem, *furthestBlock);
1546         // 13.
1547         m_tree.reparent(*furthestBlock, *newItem);
1548         // 14.
1549         m_tree.activeFormattingElements().swapTo(formattingElement, newItem, bookmark);
1550         // 15.
1551         m_tree.openElements().remove(formattingElement);
1552         m_tree.openElements().insertAbove(newItem, furthestBlock);
1553     }
1554 }
1555
1556 void HTMLTreeBuilder::resetInsertionModeAppropriately()
1557 {
1558     // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#reset-the-insertion-mode-appropriately
1559     bool last = false;
1560     for (auto* record = &m_tree.openElements().topRecord(); ; record = record->next()) {
1561         HTMLStackItem* item = &record->stackItem();
1562         if (&item->node() == &m_tree.openElements().rootNode()) {
1563             last = true;
1564 #if ENABLE(TEMPLATE_ELEMENT)
1565             bool shouldCreateItem = isParsingFragment();
1566 #else
1567             ASSERT(isParsingFragment());
1568             bool shouldCreateItem = true;
1569 #endif
1570             if (shouldCreateItem)
1571                 item = &m_fragmentContext.contextElementStackItem();
1572         }
1573
1574 #if ENABLE(TEMPLATE_ELEMENT)
1575         if (item->hasTagName(templateTag)) {
1576             m_insertionMode = m_templateInsertionModes.last();
1577             return;
1578         }
1579 #endif
1580         if (item->hasTagName(selectTag)) {
1581 #if ENABLE(TEMPLATE_ELEMENT)
1582             if (!last) {
1583                 while (&item->node() != &m_tree.openElements().rootNode() && !item->hasTagName(templateTag)) {
1584                     record = record->next();
1585                     item = &record->stackItem();
1586                     if (is<HTMLTableElement>(item->node())) {
1587                         m_insertionMode = InsertionMode::InSelectInTable;
1588                         return;
1589                     }
1590                 }
1591             }
1592 #endif
1593             m_insertionMode = InsertionMode::InSelect;
1594             return;
1595         }
1596         if (item->hasTagName(tdTag) || item->hasTagName(thTag)) {
1597             m_insertionMode = InsertionMode::InCell;
1598             return;
1599         }
1600         if (item->hasTagName(trTag)) {
1601             m_insertionMode = InsertionMode::InRow;
1602             return;
1603         }
1604         if (item->hasTagName(tbodyTag) || item->hasTagName(theadTag) || item->hasTagName(tfootTag)) {
1605             m_insertionMode = InsertionMode::InTableBody;
1606             return;
1607         }
1608         if (item->hasTagName(captionTag)) {
1609             m_insertionMode = InsertionMode::InCaption;
1610             return;
1611         }
1612         if (item->hasTagName(colgroupTag)) {
1613             m_insertionMode = InsertionMode::InColumnGroup;
1614             return;
1615         }
1616         if (is<HTMLTableElement>(item->node())) {
1617             m_insertionMode = InsertionMode::InTable;
1618             return;
1619         }
1620         if (item->hasTagName(headTag)) {
1621 #if ENABLE(TEMPLATE_ELEMENT)
1622             if (!m_fragmentContext.fragment() || &m_fragmentContext.contextElement() != &item->node()) {
1623                 m_insertionMode = InsertionMode::InHead;
1624                 return;
1625             }
1626 #endif
1627             m_insertionMode = InsertionMode::InBody;
1628             return;
1629         }
1630         if (item->hasTagName(bodyTag)) {
1631             m_insertionMode = InsertionMode::InBody;
1632             return;
1633         }
1634         if (item->hasTagName(framesetTag)) {
1635             m_insertionMode = InsertionMode::InFrameset;
1636             return;
1637         }
1638         if (item->hasTagName(htmlTag)) {
1639             if (m_tree.headStackItem()) {
1640                 m_insertionMode = InsertionMode::AfterHead;
1641                 return;
1642             }
1643             ASSERT(isParsingFragment());
1644             m_insertionMode = InsertionMode::BeforeHead;
1645             return;
1646         }
1647         if (last) {
1648             ASSERT(isParsingFragment());
1649             m_insertionMode = InsertionMode::InBody;
1650             return;
1651         }
1652     }
1653 }
1654
1655 void HTMLTreeBuilder::processEndTagForInTableBody(AtomicHTMLToken& token)
1656 {
1657     ASSERT(token.type() == HTMLToken::EndTag);
1658     if (isTableBodyContextTag(token.name())) {
1659         if (!m_tree.openElements().inTableScope(token.name())) {
1660             parseError(token);
1661             return;
1662         }
1663         m_tree.openElements().popUntilTableBodyScopeMarker();
1664         m_tree.openElements().pop();
1665         m_insertionMode = InsertionMode::InTable;
1666         return;
1667     }
1668     if (token.name() == tableTag) {
1669         // FIXME: This is slow.
1670         if (!m_tree.openElements().inTableScope(tbodyTag) && !m_tree.openElements().inTableScope(theadTag) && !m_tree.openElements().inTableScope(tfootTag)) {
1671             ASSERT(isParsingFragmentOrTemplateContents());
1672             parseError(token);
1673             return;
1674         }
1675         m_tree.openElements().popUntilTableBodyScopeMarker();
1676         ASSERT(isTableBodyContextTag(m_tree.currentStackItem().localName()));
1677         processFakeEndTag(m_tree.currentStackItem().localName());
1678         processEndTag(token);
1679         return;
1680     }
1681     if (token.name() == bodyTag
1682         || isCaptionColOrColgroupTag(token.name())
1683         || token.name() == htmlTag
1684         || isTableCellContextTag(token.name())
1685         || token.name() == trTag) {
1686         parseError(token);
1687         return;
1688     }
1689     processEndTagForInTable(token);
1690 }
1691
1692 void HTMLTreeBuilder::processEndTagForInRow(AtomicHTMLToken& token)
1693 {
1694     ASSERT(token.type() == HTMLToken::EndTag);
1695     if (token.name() == trTag) {
1696         processTrEndTagForInRow();
1697         return;
1698     }
1699     if (token.name() == tableTag) {
1700         if (!processTrEndTagForInRow()) {
1701             ASSERT(isParsingFragmentOrTemplateContents());
1702             return;
1703         }
1704         ASSERT(m_insertionMode == InsertionMode::InTableBody);
1705         processEndTag(token);
1706         return;
1707     }
1708     if (isTableBodyContextTag(token.name())) {
1709         if (!m_tree.openElements().inTableScope(token.name())) {
1710             parseError(token);
1711             return;
1712         }
1713         processFakeEndTag(trTag);
1714         ASSERT(m_insertionMode == InsertionMode::InTableBody);
1715         processEndTag(token);
1716         return;
1717     }
1718     if (token.name() == bodyTag
1719         || isCaptionColOrColgroupTag(token.name())
1720         || token.name() == htmlTag
1721         || isTableCellContextTag(token.name())) {
1722         parseError(token);
1723         return;
1724     }
1725     processEndTagForInTable(token);
1726 }
1727
1728 void HTMLTreeBuilder::processEndTagForInCell(AtomicHTMLToken& token)
1729 {
1730     ASSERT(token.type() == HTMLToken::EndTag);
1731     if (isTableCellContextTag(token.name())) {
1732         if (!m_tree.openElements().inTableScope(token.name())) {
1733             parseError(token);
1734             return;
1735         }
1736         m_tree.generateImpliedEndTags();
1737         if (!m_tree.currentStackItem().matchesHTMLTag(token.name()))
1738             parseError(token);
1739         m_tree.openElements().popUntilPopped(token.name());
1740         m_tree.activeFormattingElements().clearToLastMarker();
1741         m_insertionMode = InsertionMode::InRow;
1742         return;
1743     }
1744     if (token.name() == bodyTag
1745         || isCaptionColOrColgroupTag(token.name())
1746         || token.name() == htmlTag) {
1747         parseError(token);
1748         return;
1749     }
1750     if (token.name() == tableTag
1751         || token.name() == trTag
1752         || isTableBodyContextTag(token.name())) {
1753         if (!m_tree.openElements().inTableScope(token.name())) {
1754 #if ENABLE(TEMPLATE_ELEMENT)
1755             ASSERT(isTableBodyContextTag(token.name()) || m_tree.openElements().inTableScope(templateTag) || isParsingFragment());
1756 #else
1757             ASSERT(isTableBodyContextTag(token.name()) || isParsingFragment());
1758 #endif
1759             parseError(token);
1760             return;
1761         }
1762         closeTheCell();
1763         processEndTag(token);
1764         return;
1765     }
1766     processEndTagForInBody(token);
1767 }
1768
1769 void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken& token)
1770 {
1771     ASSERT(token.type() == HTMLToken::EndTag);
1772     if (token.name() == bodyTag) {
1773         processBodyEndTagForInBody(token);
1774         return;
1775     }
1776     if (token.name() == htmlTag) {
1777         AtomicHTMLToken endBody(HTMLToken::EndTag, bodyTag.localName());
1778         if (processBodyEndTagForInBody(endBody))
1779             processEndTag(token);
1780         return;
1781     }
1782     if (token.name() == addressTag
1783         || token.name() == articleTag
1784         || token.name() == asideTag
1785         || token.name() == blockquoteTag
1786         || token.name() == buttonTag
1787         || token.name() == centerTag
1788         || token.name() == detailsTag
1789         || token.name() == dirTag
1790         || token.name() == divTag
1791         || token.name() == dlTag
1792         || token.name() == fieldsetTag
1793         || token.name() == figcaptionTag
1794         || token.name() == figureTag
1795         || token.name() == footerTag
1796         || token.name() == headerTag
1797         || token.name() == hgroupTag
1798         || token.name() == listingTag
1799         || token.name() == mainTag
1800         || token.name() == menuTag
1801         || token.name() == navTag
1802         || token.name() == olTag
1803         || token.name() == preTag
1804         || token.name() == sectionTag
1805         || token.name() == summaryTag
1806         || token.name() == ulTag) {
1807         if (!m_tree.openElements().inScope(token.name())) {
1808             parseError(token);
1809             return;
1810         }
1811         m_tree.generateImpliedEndTags();
1812         if (!m_tree.currentStackItem().matchesHTMLTag(token.name()))
1813             parseError(token);
1814         m_tree.openElements().popUntilPopped(token.name());
1815         return;
1816     }
1817     if (token.name() == formTag) {
1818         if (!isParsingTemplateContents()) {
1819             RefPtr<Element> node = m_tree.takeForm();
1820             if (!node || !m_tree.openElements().inScope(node.get())) {
1821                 parseError(token);
1822                 return;
1823             }
1824             m_tree.generateImpliedEndTags();
1825             if (&m_tree.currentNode() != node.get())
1826                 parseError(token);
1827             m_tree.openElements().remove(node.get());
1828         } else {
1829             if (!m_tree.openElements().inScope(token.name())) {
1830                 parseError(token);
1831                 return;
1832             }
1833             m_tree.generateImpliedEndTags();
1834             if (!m_tree.currentNode().hasTagName(formTag))
1835                 parseError(token);
1836             m_tree.openElements().popUntilPopped(token.name());
1837         }
1838     }
1839     if (token.name() == pTag) {
1840         if (!m_tree.openElements().inButtonScope(token.name())) {
1841             parseError(token);
1842             processFakeStartTag(pTag);
1843             ASSERT(m_tree.openElements().inScope(token.name()));
1844             processEndTag(token);
1845             return;
1846         }
1847         m_tree.generateImpliedEndTagsWithExclusion(token.name());
1848         if (!m_tree.currentStackItem().matchesHTMLTag(token.name()))
1849             parseError(token);
1850         m_tree.openElements().popUntilPopped(token.name());
1851         return;
1852     }
1853     if (token.name() == liTag) {
1854         if (!m_tree.openElements().inListItemScope(token.name())) {
1855             parseError(token);
1856             return;
1857         }
1858         m_tree.generateImpliedEndTagsWithExclusion(token.name());
1859         if (!m_tree.currentStackItem().matchesHTMLTag(token.name()))
1860             parseError(token);
1861         m_tree.openElements().popUntilPopped(token.name());
1862         return;
1863     }
1864     if (token.name() == ddTag || token.name() == dtTag) {
1865         if (!m_tree.openElements().inScope(token.name())) {
1866             parseError(token);
1867             return;
1868         }
1869         m_tree.generateImpliedEndTagsWithExclusion(token.name());
1870         if (!m_tree.currentStackItem().matchesHTMLTag(token.name()))
1871             parseError(token);
1872         m_tree.openElements().popUntilPopped(token.name());
1873         return;
1874     }
1875     if (isNumberedHeaderTag(token.name())) {
1876         if (!m_tree.openElements().hasNumberedHeaderElementInScope()) {
1877             parseError(token);
1878             return;
1879         }
1880         m_tree.generateImpliedEndTags();
1881         if (!m_tree.currentStackItem().matchesHTMLTag(token.name()))
1882             parseError(token);
1883         m_tree.openElements().popUntilNumberedHeaderElementPopped();
1884         return;
1885     }
1886     if (isFormattingTag(token.name())) {
1887         callTheAdoptionAgency(token);
1888         return;
1889     }
1890     if (token.name() == appletTag || token.name() == marqueeTag || token.name() == objectTag) {
1891         if (!m_tree.openElements().inScope(token.name())) {
1892             parseError(token);
1893             return;
1894         }
1895         m_tree.generateImpliedEndTags();
1896         if (!m_tree.currentStackItem().matchesHTMLTag(token.name()))
1897             parseError(token);
1898         m_tree.openElements().popUntilPopped(token.name());
1899         m_tree.activeFormattingElements().clearToLastMarker();
1900         return;
1901     }
1902     if (token.name() == brTag) {
1903         parseError(token);
1904         processFakeStartTag(brTag);
1905         return;
1906     }
1907 #if ENABLE(TEMPLATE_ELEMENT)
1908     if (token.name() == templateTag) {
1909         processTemplateEndTag(token);
1910         return;
1911     }
1912 #endif
1913     processAnyOtherEndTagForInBody(token);
1914 }
1915
1916 bool HTMLTreeBuilder::processCaptionEndTagForInCaption()
1917 {
1918     if (!m_tree.openElements().inTableScope(captionTag.localName())) {
1919         ASSERT(isParsingFragment());
1920         // FIXME: parse error
1921         return false;
1922     }
1923     m_tree.generateImpliedEndTags();
1924     // FIXME: parse error if (!m_tree.currentStackItem().hasTagName(captionTag))
1925     m_tree.openElements().popUntilPopped(captionTag.localName());
1926     m_tree.activeFormattingElements().clearToLastMarker();
1927     m_insertionMode = InsertionMode::InTable;
1928     return true;
1929 }
1930
1931 bool HTMLTreeBuilder::processTrEndTagForInRow()
1932 {
1933     if (!m_tree.openElements().inTableScope(trTag)) {
1934         ASSERT(isParsingFragmentOrTemplateContents());
1935         // FIXME: parse error
1936         return false;
1937     }
1938     m_tree.openElements().popUntilTableRowScopeMarker();
1939     ASSERT(m_tree.currentStackItem().hasTagName(trTag));
1940     m_tree.openElements().pop();
1941     m_insertionMode = InsertionMode::InTableBody;
1942     return true;
1943 }
1944
1945 bool HTMLTreeBuilder::processTableEndTagForInTable()
1946 {
1947     if (!m_tree.openElements().inTableScope(tableTag)) {
1948         ASSERT(isParsingFragmentOrTemplateContents());
1949         // FIXME: parse error.
1950         return false;
1951     }
1952     m_tree.openElements().popUntilPopped(tableTag.localName());
1953     resetInsertionModeAppropriately();
1954     return true;
1955 }
1956
1957 void HTMLTreeBuilder::processEndTagForInTable(AtomicHTMLToken& token)
1958 {
1959     ASSERT(token.type() == HTMLToken::EndTag);
1960     if (token.name() == tableTag) {
1961         processTableEndTagForInTable();
1962         return;
1963     }
1964     if (token.name() == bodyTag
1965         || isCaptionColOrColgroupTag(token.name())
1966         || token.name() == htmlTag
1967         || isTableBodyContextTag(token.name())
1968         || isTableCellContextTag(token.name())
1969         || token.name() == trTag) {
1970         parseError(token);
1971         return;
1972     }
1973     parseError(token);
1974     // Is this redirection necessary here?
1975     HTMLConstructionSite::RedirectToFosterParentGuard redirecter(m_tree);
1976     processEndTagForInBody(token);
1977 }
1978
1979 void HTMLTreeBuilder::processEndTag(AtomicHTMLToken& token)
1980 {
1981     ASSERT(token.type() == HTMLToken::EndTag);
1982     switch (m_insertionMode) {
1983     case InsertionMode::Initial:
1984         defaultForInitial();
1985         ASSERT(m_insertionMode == InsertionMode::BeforeHTML);
1986         FALLTHROUGH;
1987     case InsertionMode::BeforeHTML:
1988         if (token.name() != headTag && token.name() != bodyTag && token.name() != htmlTag && token.name() != brTag) {
1989             parseError(token);
1990             return;
1991         }
1992         defaultForBeforeHTML();
1993         ASSERT(m_insertionMode == InsertionMode::BeforeHead);
1994         FALLTHROUGH;
1995     case InsertionMode::BeforeHead:
1996         if (token.name() != headTag && token.name() != bodyTag && token.name() != htmlTag && token.name() != brTag) {
1997             parseError(token);
1998             return;
1999         }
2000         defaultForBeforeHead();
2001         ASSERT(m_insertionMode == InsertionMode::InHead);
2002         FALLTHROUGH;
2003     case InsertionMode::InHead:
2004         // FIXME: This case should be broken out into processEndTagForInHead,
2005         // because other end tag cases now refer to it ("process the token for using the rules of the "in head" insertion mode").
2006         // but because the logic falls through to InsertionMode::AfterHead, that gets a little messy.
2007 #if ENABLE(TEMPLATE_ELEMENT)
2008         if (token.name() == templateTag) {
2009             processTemplateEndTag(token);
2010             return;
2011         }
2012 #endif
2013         if (token.name() == headTag) {
2014             m_tree.openElements().popHTMLHeadElement();
2015             m_insertionMode = InsertionMode::AfterHead;
2016             return;
2017         }
2018         if (token.name() != bodyTag && token.name() != htmlTag && token.name() != brTag) {
2019             parseError(token);
2020             return;
2021         }
2022         defaultForInHead();
2023         ASSERT(m_insertionMode == InsertionMode::AfterHead);
2024         FALLTHROUGH;
2025     case InsertionMode::AfterHead:
2026         if (token.name() != bodyTag && token.name() != htmlTag && token.name() != brTag) {
2027             parseError(token);
2028             return;
2029         }
2030         defaultForAfterHead();
2031         ASSERT(m_insertionMode == InsertionMode::InBody);
2032         FALLTHROUGH;
2033     case InsertionMode::InBody:
2034         processEndTagForInBody(token);
2035         break;
2036     case InsertionMode::InTable:
2037         processEndTagForInTable(token);
2038         break;
2039     case InsertionMode::InCaption:
2040         if (token.name() == captionTag) {
2041             processCaptionEndTagForInCaption();
2042             return;
2043         }
2044         if (token.name() == tableTag) {
2045             parseError(token);
2046             if (!processCaptionEndTagForInCaption()) {
2047                 ASSERT(isParsingFragment());
2048                 return;
2049             }
2050             processEndTag(token);
2051             return;
2052         }
2053         if (token.name() == bodyTag
2054             || token.name() == colTag
2055             || token.name() == colgroupTag
2056             || token.name() == htmlTag
2057             || isTableBodyContextTag(token.name())
2058             || isTableCellContextTag(token.name())
2059             || token.name() == trTag) {
2060             parseError(token);
2061             return;
2062         }
2063         processEndTagForInBody(token);
2064         break;
2065     case InsertionMode::InColumnGroup:
2066         if (token.name() == colgroupTag) {
2067             processColgroupEndTagForInColumnGroup();
2068             return;
2069         }
2070         if (token.name() == colTag) {
2071             parseError(token);
2072             return;
2073         }
2074 #if ENABLE(TEMPLATE_ELEMENT)
2075         if (token.name() == templateTag) {
2076             processTemplateEndTag(token);
2077             return;
2078         }
2079 #endif
2080         if (!processColgroupEndTagForInColumnGroup()) {
2081             ASSERT(isParsingFragmentOrTemplateContents());
2082             return;
2083         }
2084         processEndTag(token);
2085         break;
2086     case InsertionMode::InRow:
2087         processEndTagForInRow(token);
2088         break;
2089     case InsertionMode::InCell:
2090         processEndTagForInCell(token);
2091         break;
2092     case InsertionMode::InTableBody:
2093         processEndTagForInTableBody(token);
2094         break;
2095     case InsertionMode::AfterBody:
2096         if (token.name() == htmlTag) {
2097             if (isParsingFragment()) {
2098                 parseError(token);
2099                 return;
2100             }
2101             m_insertionMode = InsertionMode::AfterAfterBody;
2102             return;
2103         }
2104         FALLTHROUGH;
2105     case InsertionMode::AfterAfterBody:
2106         ASSERT(m_insertionMode == InsertionMode::AfterBody || m_insertionMode == InsertionMode::AfterAfterBody);
2107         parseError(token);
2108         m_insertionMode = InsertionMode::InBody;
2109         processEndTag(token);
2110         break;
2111     case InsertionMode::InHeadNoscript:
2112         if (token.name() == noscriptTag) {
2113             ASSERT(m_tree.currentStackItem().hasTagName(noscriptTag));
2114             m_tree.openElements().pop();
2115             ASSERT(m_tree.currentStackItem().hasTagName(headTag));
2116             m_insertionMode = InsertionMode::InHead;
2117             return;
2118         }
2119         if (token.name() != brTag) {
2120             parseError(token);
2121             return;
2122         }
2123         defaultForInHeadNoscript();
2124         processToken(token);
2125         break;
2126     case InsertionMode::Text:
2127         if (token.name() == scriptTag) {
2128             // Pause ourselves so that parsing stops until the script can be processed by the caller.
2129             ASSERT(m_tree.currentStackItem().hasTagName(scriptTag));
2130             if (scriptingContentIsAllowed(m_tree.parserContentPolicy()))
2131                 m_scriptToProcess = &m_tree.currentElement();
2132             m_tree.openElements().pop();
2133             m_insertionMode = m_originalInsertionMode;
2134
2135             // This token will not have been created by the tokenizer if a
2136             // self-closing script tag was encountered and pre-HTML5 parser
2137             // quirks are enabled. We must set the tokenizer's state to
2138             // DataState explicitly if the tokenizer didn't have a chance to.
2139             ASSERT(m_parser.tokenizer().isInDataState() || m_options.usePreHTML5ParserQuirks);
2140             m_parser.tokenizer().setDataState();
2141             return;
2142         }
2143         m_tree.openElements().pop();
2144         m_insertionMode = m_originalInsertionMode;
2145         break;
2146     case InsertionMode::InFrameset:
2147         if (token.name() == framesetTag) {
2148             bool ignoreFramesetForFragmentParsing  = m_tree.currentIsRootNode();
2149 #if ENABLE(TEMPLATE_ELEMENT)
2150             ignoreFramesetForFragmentParsing = ignoreFramesetForFragmentParsing || m_tree.openElements().hasTemplateInHTMLScope();
2151 #endif
2152             if (ignoreFramesetForFragmentParsing) {
2153                 ASSERT(isParsingFragmentOrTemplateContents());
2154                 parseError(token);
2155                 return;
2156             }
2157             m_tree.openElements().pop();
2158             if (!isParsingFragment() && !m_tree.currentStackItem().hasTagName(framesetTag))
2159                 m_insertionMode = InsertionMode::AfterFrameset;
2160             return;
2161         }
2162 #if ENABLE(TEMPLATE_ELEMENT)
2163         if (token.name() == templateTag) {
2164             processTemplateEndTag(token);
2165             return;
2166         }
2167 #endif
2168         break;
2169     case InsertionMode::AfterFrameset:
2170         if (token.name() == htmlTag) {
2171             m_insertionMode = InsertionMode::AfterAfterFrameset;
2172             return;
2173         }
2174         FALLTHROUGH;
2175     case InsertionMode::AfterAfterFrameset:
2176         ASSERT(m_insertionMode == InsertionMode::AfterFrameset || m_insertionMode == InsertionMode::AfterAfterFrameset);
2177         parseError(token);
2178         break;
2179     case InsertionMode::InSelectInTable:
2180         if (token.name() == captionTag
2181             || token.name() == tableTag
2182             || isTableBodyContextTag(token.name())
2183             || token.name() == trTag
2184             || isTableCellContextTag(token.name())) {
2185             parseError(token);
2186             if (m_tree.openElements().inTableScope(token.name())) {
2187                 AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName());
2188                 processEndTag(endSelect);
2189                 processEndTag(token);
2190             }
2191             return;
2192         }
2193         FALLTHROUGH;
2194     case InsertionMode::InSelect:
2195         ASSERT(m_insertionMode == InsertionMode::InSelect || m_insertionMode == InsertionMode::InSelectInTable);
2196         if (token.name() == optgroupTag) {
2197             if (is<HTMLOptionElement>(m_tree.currentStackItem().node()) && m_tree.oneBelowTop() && is<HTMLOptGroupElement>(m_tree.oneBelowTop()->node()))
2198                 processFakeEndTag(optionTag);
2199             if (is<HTMLOptGroupElement>(m_tree.currentStackItem().node())) {
2200                 m_tree.openElements().pop();
2201                 return;
2202             }
2203             parseError(token);
2204             return;
2205         }
2206         if (token.name() == optionTag) {
2207             if (is<HTMLOptionElement>(m_tree.currentStackItem().node())) {
2208                 m_tree.openElements().pop();
2209                 return;
2210             }
2211             parseError(token);
2212             return;
2213         }
2214         if (token.name() == selectTag) {
2215             if (!m_tree.openElements().inSelectScope(token.name())) {
2216                 ASSERT(isParsingFragment());
2217                 parseError(token);
2218                 return;
2219             }
2220             m_tree.openElements().popUntilPopped(selectTag.localName());
2221             resetInsertionModeAppropriately();
2222             return;
2223         }
2224 #if ENABLE(TEMPLATE_ELEMENT)
2225         if (token.name() == templateTag) {
2226             processTemplateEndTag(token);
2227             return;
2228         }
2229 #endif
2230         break;
2231     case InsertionMode::InTableText:
2232         defaultForInTableText();
2233         processEndTag(token);
2234         break;
2235 #if ENABLE(TEMPLATE_ELEMENT)
2236     case InsertionMode::TemplateContents:
2237         if (token.name() == templateTag) {
2238             processTemplateEndTag(token);
2239             return;
2240         }
2241         break;
2242 #endif
2243     }
2244 }
2245
2246 void HTMLTreeBuilder::processComment(AtomicHTMLToken& token)
2247 {
2248     ASSERT(token.type() == HTMLToken::Comment);
2249     if (m_insertionMode == InsertionMode::Initial
2250         || m_insertionMode == InsertionMode::BeforeHTML
2251         || m_insertionMode == InsertionMode::AfterAfterBody
2252         || m_insertionMode == InsertionMode::AfterAfterFrameset) {
2253         m_tree.insertCommentOnDocument(&token);
2254         return;
2255     }
2256     if (m_insertionMode == InsertionMode::AfterBody) {
2257         m_tree.insertCommentOnHTMLHtmlElement(&token);
2258         return;
2259     }
2260     if (m_insertionMode == InsertionMode::InTableText) {
2261         defaultForInTableText();
2262         processComment(token);
2263         return;
2264     }
2265     m_tree.insertComment(&token);
2266 }
2267
2268 void HTMLTreeBuilder::processCharacter(AtomicHTMLToken& token)
2269 {
2270     ASSERT(token.type() == HTMLToken::Character);
2271     ExternalCharacterTokenBuffer buffer(token);
2272     processCharacterBuffer(buffer);
2273 }
2274
2275 #if ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(IOS)
2276
2277 // FIXME: Extract the following iOS-specific code into a separate file.
2278 // From the string 4089961010, creates a link of the form <a href="tel:4089961010">4089961010</a> and inserts it.
2279 void HTMLTreeBuilder::insertPhoneNumberLink(const String& string)
2280 {
2281     Vector<Attribute> attributes;
2282     attributes.append(Attribute(HTMLNames::hrefAttr, ASCIILiteral("tel:") + string));
2283
2284     const AtomicString& aTagLocalName = aTag.localName();
2285     AtomicHTMLToken aStartToken(HTMLToken::StartTag, aTagLocalName, WTF::move(attributes));
2286     AtomicHTMLToken aEndToken(HTMLToken::EndTag, aTagLocalName);
2287
2288     processStartTag(aStartToken);
2289     m_tree.executeQueuedTasks();
2290     m_tree.insertTextNode(string);
2291     processEndTag(aEndToken);
2292 }
2293
2294 // Locates the phone numbers in the string and deals with it
2295 // 1. Appends the text before the phone number as a text node.
2296 // 2. Wraps the phone number in a tel: link.
2297 // 3. Goes back to step 1 if a phone number is found in the rest of the string.
2298 // 4. Appends the rest of the string as a text node.
2299 void HTMLTreeBuilder::linkifyPhoneNumbers(const String& string)
2300 {
2301     ASSERT(TelephoneNumberDetector::isSupported());
2302
2303     // relativeStartPosition and relativeEndPosition are the endpoints of the phone number range,
2304     // relative to the scannerPosition
2305     unsigned length = string.length();
2306     unsigned scannerPosition = 0;
2307     int relativeStartPosition = 0;
2308     int relativeEndPosition = 0;
2309
2310     auto characters = StringView(string).upconvertedCharacters();
2311
2312     // While there's a phone number in the rest of the string...
2313     while (scannerPosition < length && TelephoneNumberDetector::find(&characters[scannerPosition], length - scannerPosition, &relativeStartPosition, &relativeEndPosition)) {
2314         // The convention in the Data Detectors framework is that the end position is the first character NOT in the phone number
2315         // (that is, the length of the range is relativeEndPosition - relativeStartPosition). So substract 1 to get the same
2316         // convention as the old WebCore phone number parser (so that the rest of the code is still valid if we want to go back
2317         // to the old parser).
2318         --relativeEndPosition;
2319
2320         ASSERT(scannerPosition + relativeEndPosition < length);
2321
2322         m_tree.insertTextNode(string.substring(scannerPosition, relativeStartPosition));
2323         insertPhoneNumberLink(string.substring(scannerPosition + relativeStartPosition, relativeEndPosition - relativeStartPosition + 1));
2324
2325         scannerPosition += relativeEndPosition + 1;
2326     }
2327
2328     // Append the rest as a text node.
2329     if (scannerPosition > 0) {
2330         if (scannerPosition < length) {
2331             String after = string.substring(scannerPosition, length - scannerPosition);
2332             m_tree.insertTextNode(after);
2333         }
2334     } else
2335         m_tree.insertTextNode(string);
2336 }
2337
2338 // Looks at the ancestors of the element to determine whether we're inside an element which disallows parsing phone numbers.
2339 static inline bool disallowTelephoneNumberParsing(const ContainerNode& node)
2340 {
2341     return node.isLink()
2342         || node.hasTagName(scriptTag)
2343         || is<HTMLFormControlElement>(node)
2344         || node.hasTagName(styleTag)
2345         || node.hasTagName(ttTag)
2346         || node.hasTagName(preTag)
2347         || node.hasTagName(codeTag);
2348 }
2349
2350 static inline bool shouldParseTelephoneNumbersInNode(const ContainerNode& node)
2351 {
2352     for (const ContainerNode* ancestor = &node; ancestor; ancestor = ancestor->parentNode()) {
2353         if (disallowTelephoneNumberParsing(*ancestor))
2354             return false;
2355     }
2356     return true;
2357 }
2358
2359 #endif // ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(IOS)
2360
2361 void HTMLTreeBuilder::processCharacterBuffer(ExternalCharacterTokenBuffer& buffer)
2362 {
2363 ReprocessBuffer:
2364     // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-inbody
2365     // Note that this logic is different than the generic \r\n collapsing
2366     // handled in the input stream preprocessor. This logic is here as an
2367     // "authoring convenience" so folks can write:
2368     //
2369     // <pre>
2370     // lorem ipsum
2371     // lorem ipsum
2372     // </pre>
2373     //
2374     // without getting an extra newline at the start of their <pre> element.
2375     if (m_shouldSkipLeadingNewline) {
2376         m_shouldSkipLeadingNewline = false;
2377         buffer.skipAtMostOneLeadingNewline();
2378         if (buffer.isEmpty())
2379             return;
2380     }
2381
2382     switch (m_insertionMode) {
2383     case InsertionMode::Initial:
2384         buffer.skipLeadingWhitespace();
2385         if (buffer.isEmpty())
2386             return;
2387         defaultForInitial();
2388         ASSERT(m_insertionMode == InsertionMode::BeforeHTML);
2389         FALLTHROUGH;
2390     case InsertionMode::BeforeHTML:
2391         buffer.skipLeadingWhitespace();
2392         if (buffer.isEmpty())
2393             return;
2394         defaultForBeforeHTML();
2395         ASSERT(m_insertionMode == InsertionMode::BeforeHead);
2396         FALLTHROUGH;
2397     case InsertionMode::BeforeHead:
2398         buffer.skipLeadingWhitespace();
2399         if (buffer.isEmpty())
2400             return;
2401         defaultForBeforeHead();
2402         ASSERT(m_insertionMode == InsertionMode::InHead);
2403         FALLTHROUGH;
2404     case InsertionMode::InHead: {
2405         String leadingWhitespace = buffer.takeLeadingWhitespace();
2406         if (!leadingWhitespace.isEmpty())
2407             m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
2408         if (buffer.isEmpty())
2409             return;
2410         defaultForInHead();
2411         ASSERT(m_insertionMode == InsertionMode::AfterHead);
2412         FALLTHROUGH;
2413     }
2414     case InsertionMode::AfterHead: {
2415         String leadingWhitespace = buffer.takeLeadingWhitespace();
2416         if (!leadingWhitespace.isEmpty())
2417             m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
2418         if (buffer.isEmpty())
2419             return;
2420         defaultForAfterHead();
2421         ASSERT(m_insertionMode == InsertionMode::InBody);
2422         FALLTHROUGH;
2423     }
2424     case InsertionMode::InBody:
2425     case InsertionMode::InCaption:
2426     case InsertionMode::InCell:
2427 #if ENABLE(TEMPLATE_ELEMENT)
2428     case InsertionMode::TemplateContents:
2429 #endif
2430         processCharacterBufferForInBody(buffer);
2431         break;
2432     case InsertionMode::InTable:
2433     case InsertionMode::InTableBody:
2434     case InsertionMode::InRow:
2435         ASSERT(m_pendingTableCharacters.isEmpty());
2436         if (is<HTMLTableElement>(m_tree.currentStackItem().node())
2437             || m_tree.currentStackItem().hasTagName(HTMLNames::tbodyTag)
2438             || m_tree.currentStackItem().hasTagName(HTMLNames::tfootTag)
2439             || m_tree.currentStackItem().hasTagName(HTMLNames::theadTag)
2440             || m_tree.currentStackItem().hasTagName(HTMLNames::trTag)) {
2441
2442             m_originalInsertionMode = m_insertionMode;
2443             m_insertionMode = InsertionMode::InTableText;
2444             // Note that we fall through to the InsertionMode::InTableText case below.
2445         } else {
2446             HTMLConstructionSite::RedirectToFosterParentGuard redirecter(m_tree);
2447             processCharacterBufferForInBody(buffer);
2448             break;
2449         }
2450         FALLTHROUGH;
2451     case InsertionMode::InTableText:
2452         buffer.giveRemainingTo(m_pendingTableCharacters);
2453         break;
2454     case InsertionMode::InColumnGroup: {
2455         String leadingWhitespace = buffer.takeLeadingWhitespace();
2456         if (!leadingWhitespace.isEmpty())
2457             m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
2458         if (buffer.isEmpty())
2459             return;
2460         if (!processColgroupEndTagForInColumnGroup()) {
2461             ASSERT(isParsingFragmentOrTemplateContents());
2462             // The spec tells us to drop these characters on the floor.
2463             buffer.skipLeadingNonWhitespace();
2464             if (buffer.isEmpty())
2465                 return;
2466         }
2467         goto ReprocessBuffer;
2468     }
2469     case InsertionMode::AfterBody:
2470     case InsertionMode::AfterAfterBody:
2471         // FIXME: parse error
2472         m_insertionMode = InsertionMode::InBody;
2473         goto ReprocessBuffer;
2474     case InsertionMode::Text:
2475         m_tree.insertTextNode(buffer.takeRemaining());
2476         break;
2477     case InsertionMode::InHeadNoscript: {
2478         String leadingWhitespace = buffer.takeLeadingWhitespace();
2479         if (!leadingWhitespace.isEmpty())
2480             m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
2481         if (buffer.isEmpty())
2482             return;
2483         defaultForInHeadNoscript();
2484         goto ReprocessBuffer;
2485     }
2486     case InsertionMode::InFrameset:
2487     case InsertionMode::AfterFrameset: {
2488         String leadingWhitespace = buffer.takeRemainingWhitespace();
2489         if (!leadingWhitespace.isEmpty())
2490             m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
2491         // FIXME: We should generate a parse error if we skipped over any
2492         // non-whitespace characters.
2493         break;
2494     }
2495     case InsertionMode::InSelectInTable:
2496     case InsertionMode::InSelect:
2497         m_tree.insertTextNode(buffer.takeRemaining());
2498         break;
2499     case InsertionMode::AfterAfterFrameset: {
2500         String leadingWhitespace = buffer.takeRemainingWhitespace();
2501         if (!leadingWhitespace.isEmpty()) {
2502             m_tree.reconstructTheActiveFormattingElements();
2503             m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
2504         }
2505         // FIXME: We should generate a parse error if we skipped over any
2506         // non-whitespace characters.
2507         break;
2508     }
2509     }
2510 }
2511
2512 void HTMLTreeBuilder::processCharacterBufferForInBody(ExternalCharacterTokenBuffer& buffer)
2513 {
2514     m_tree.reconstructTheActiveFormattingElements();
2515     String characters = buffer.takeRemaining();
2516 #if ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(IOS)
2517     if (!isParsingFragment() && m_tree.isTelephoneNumberParsingEnabled() && shouldParseTelephoneNumbersInNode(m_tree.currentNode()) && TelephoneNumberDetector::isSupported())
2518         linkifyPhoneNumbers(characters);
2519     else
2520         m_tree.insertTextNode(characters);
2521 #else
2522     m_tree.insertTextNode(characters);
2523 #endif
2524     if (m_framesetOk && !isAllWhitespaceOrReplacementCharacters(characters))
2525         m_framesetOk = false;
2526 }
2527
2528 void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken& token)
2529 {
2530     ASSERT(token.type() == HTMLToken::EndOfFile);
2531     switch (m_insertionMode) {
2532     case InsertionMode::Initial:
2533         defaultForInitial();
2534         ASSERT(m_insertionMode == InsertionMode::BeforeHTML);
2535         FALLTHROUGH;
2536     case InsertionMode::BeforeHTML:
2537         defaultForBeforeHTML();
2538         ASSERT(m_insertionMode == InsertionMode::BeforeHead);
2539         FALLTHROUGH;
2540     case InsertionMode::BeforeHead:
2541         defaultForBeforeHead();
2542         ASSERT(m_insertionMode == InsertionMode::InHead);
2543         FALLTHROUGH;
2544     case InsertionMode::InHead:
2545         defaultForInHead();
2546         ASSERT(m_insertionMode == InsertionMode::AfterHead);
2547         FALLTHROUGH;
2548     case InsertionMode::AfterHead:
2549         defaultForAfterHead();
2550         ASSERT(m_insertionMode == InsertionMode::InBody);
2551         FALLTHROUGH;
2552     case InsertionMode::InBody:
2553     case InsertionMode::InCell:
2554     case InsertionMode::InCaption:
2555     case InsertionMode::InRow:
2556         notImplemented(); // Emit parse error based on what elements are still open.
2557 #if ENABLE(TEMPLATE_ELEMENT)
2558         if (!m_templateInsertionModes.isEmpty()) {
2559             if (processEndOfFileForInTemplateContents(token))
2560                 return;
2561         }
2562 #endif
2563         break;
2564     case InsertionMode::AfterBody:
2565     case InsertionMode::AfterAfterBody:
2566         break;
2567     case InsertionMode::InHeadNoscript:
2568         defaultForInHeadNoscript();
2569         processEndOfFile(token);
2570         return;
2571     case InsertionMode::AfterFrameset:
2572     case InsertionMode::AfterAfterFrameset:
2573         break;
2574     case InsertionMode::InColumnGroup:
2575         if (m_tree.currentIsRootNode()) {
2576             ASSERT(isParsingFragment());
2577             return; // FIXME: Should we break here instead of returning?
2578         }
2579 #if ENABLE(TEMPLATE_ELEMENT)
2580         ASSERT(m_tree.currentNode().hasTagName(colgroupTag) || m_tree.currentNode().hasTagName(templateTag));
2581 #else
2582         ASSERT(m_tree.currentNode().hasTagName(colgroupTag));
2583 #endif
2584         processColgroupEndTagForInColumnGroup();
2585         FALLTHROUGH;
2586     case InsertionMode::InFrameset:
2587     case InsertionMode::InTable:
2588     case InsertionMode::InTableBody:
2589     case InsertionMode::InSelectInTable:
2590     case InsertionMode::InSelect:
2591         ASSERT(m_insertionMode == InsertionMode::InSelect || m_insertionMode == InsertionMode::InSelectInTable || m_insertionMode == InsertionMode::InTable || m_insertionMode == InsertionMode::InFrameset || m_insertionMode == InsertionMode::InTableBody || m_insertionMode == InsertionMode::InColumnGroup);
2592         if (&m_tree.currentNode() != &m_tree.openElements().rootNode())
2593             parseError(token);
2594 #if ENABLE(TEMPLATE_ELEMENT)
2595         if (!m_templateInsertionModes.isEmpty()) {
2596             if (processEndOfFileForInTemplateContents(token))
2597                 return;
2598         }
2599 #endif
2600         break;
2601     case InsertionMode::InTableText:
2602         defaultForInTableText();
2603         processEndOfFile(token);
2604         return;
2605     case InsertionMode::Text:
2606         parseError(token);
2607         if (m_tree.currentStackItem().hasTagName(scriptTag))
2608             notImplemented(); // mark the script element as "already started".
2609         m_tree.openElements().pop();
2610         ASSERT(m_originalInsertionMode != InsertionMode::Text);
2611         m_insertionMode = m_originalInsertionMode;
2612         processEndOfFile(token);
2613         return;
2614 #if ENABLE(TEMPLATE_ELEMENT)
2615     case InsertionMode::TemplateContents:
2616         if (processEndOfFileForInTemplateContents(token))
2617             return;
2618         break;
2619 #endif
2620     }
2621     m_tree.openElements().popAll();
2622 }
2623
2624 void HTMLTreeBuilder::defaultForInitial()
2625 {
2626     notImplemented();
2627     m_tree.setDefaultCompatibilityMode();
2628     // FIXME: parse error
2629     m_insertionMode = InsertionMode::BeforeHTML;
2630 }
2631
2632 void HTMLTreeBuilder::defaultForBeforeHTML()
2633 {
2634     AtomicHTMLToken startHTML(HTMLToken::StartTag, htmlTag.localName());
2635     m_tree.insertHTMLHtmlStartTagBeforeHTML(&startHTML);
2636     m_insertionMode = InsertionMode::BeforeHead;
2637 }
2638
2639 void HTMLTreeBuilder::defaultForBeforeHead()
2640 {
2641     AtomicHTMLToken startHead(HTMLToken::StartTag, headTag.localName());
2642     processStartTag(startHead);
2643 }
2644
2645 void HTMLTreeBuilder::defaultForInHead()
2646 {
2647     AtomicHTMLToken endHead(HTMLToken::EndTag, headTag.localName());
2648     processEndTag(endHead);
2649 }
2650
2651 void HTMLTreeBuilder::defaultForInHeadNoscript()
2652 {
2653     AtomicHTMLToken endNoscript(HTMLToken::EndTag, noscriptTag.localName());
2654     processEndTag(endNoscript);
2655 }
2656
2657 void HTMLTreeBuilder::defaultForAfterHead()
2658 {
2659     AtomicHTMLToken startBody(HTMLToken::StartTag, bodyTag.localName());
2660     processStartTag(startBody);
2661     m_framesetOk = true;
2662 }
2663
2664 void HTMLTreeBuilder::defaultForInTableText()
2665 {
2666     String characters = m_pendingTableCharacters.toString();
2667     m_pendingTableCharacters.clear();
2668     if (!isAllWhitespace(characters)) {
2669         // FIXME: parse error
2670         HTMLConstructionSite::RedirectToFosterParentGuard redirecter(m_tree);
2671         m_tree.reconstructTheActiveFormattingElements();
2672         m_tree.insertTextNode(characters, NotAllWhitespace);
2673         m_framesetOk = false;
2674         m_insertionMode = m_originalInsertionMode;
2675         return;
2676     }
2677     m_tree.insertTextNode(characters);
2678     m_insertionMode = m_originalInsertionMode;
2679 }
2680
2681 bool HTMLTreeBuilder::processStartTagForInHead(AtomicHTMLToken& token)
2682 {
2683     ASSERT(token.type() == HTMLToken::StartTag);
2684     if (token.name() == htmlTag) {
2685         processHtmlStartTagForInBody(token);
2686         return true;
2687     }
2688     if (token.name() == baseTag
2689         || token.name() == basefontTag
2690         || token.name() == bgsoundTag
2691         || token.name() == commandTag
2692         || token.name() == linkTag
2693         || token.name() == metaTag) {
2694         m_tree.insertSelfClosingHTMLElement(&token);
2695         // Note: The custom processing for the <meta> tag is done in HTMLMetaElement::process().
2696         return true;
2697     }
2698     if (token.name() == titleTag) {
2699         processGenericRCDATAStartTag(token);
2700         return true;
2701     }
2702     if (token.name() == noscriptTag) {
2703         if (m_options.scriptEnabled) {
2704             processGenericRawTextStartTag(token);
2705             return true;
2706         }
2707         m_tree.insertHTMLElement(&token);
2708         m_insertionMode = InsertionMode::InHeadNoscript;
2709         return true;
2710     }
2711     if (token.name() == noframesTag || token.name() == styleTag) {
2712         processGenericRawTextStartTag(token);
2713         return true;
2714     }
2715     if (token.name() == scriptTag) {
2716         processScriptStartTag(token);
2717         if (m_options.usePreHTML5ParserQuirks && token.selfClosing())
2718             processFakeEndTag(scriptTag);
2719         return true;
2720     }
2721 #if ENABLE(TEMPLATE_ELEMENT)
2722     if (token.name() == templateTag) {
2723         processTemplateStartTag(token);
2724         return true;
2725     }
2726 #endif
2727     if (token.name() == headTag) {
2728         parseError(token);
2729         return true;
2730     }
2731     return false;
2732 }
2733
2734 void HTMLTreeBuilder::processGenericRCDATAStartTag(AtomicHTMLToken& token)
2735 {
2736     ASSERT(token.type() == HTMLToken::StartTag);
2737     m_tree.insertHTMLElement(&token);
2738     m_parser.tokenizer().setRCDATAState();
2739     m_originalInsertionMode = m_insertionMode;
2740     m_insertionMode = InsertionMode::Text;
2741 }
2742
2743 void HTMLTreeBuilder::processGenericRawTextStartTag(AtomicHTMLToken& token)
2744 {
2745     ASSERT(token.type() == HTMLToken::StartTag);
2746     m_tree.insertHTMLElement(&token);
2747     m_parser.tokenizer().setRAWTEXTState();
2748     m_originalInsertionMode = m_insertionMode;
2749     m_insertionMode = InsertionMode::Text;
2750 }
2751
2752 void HTMLTreeBuilder::processScriptStartTag(AtomicHTMLToken& token)
2753 {
2754     ASSERT(token.type() == HTMLToken::StartTag);
2755     m_tree.insertScriptElement(&token);
2756     m_parser.tokenizer().setScriptDataState();
2757     m_originalInsertionMode = m_insertionMode;
2758
2759     TextPosition position = m_parser.textPosition();
2760
2761     m_scriptToProcessStartPosition = position;
2762
2763     m_insertionMode = InsertionMode::Text;
2764 }
2765
2766 // http://www.whatwg.org/specs/web-apps/current-work/#adjusted-current-node
2767 HTMLStackItem& HTMLTreeBuilder::adjustedCurrentStackItem() const
2768 {
2769     ASSERT(!m_tree.isEmpty());
2770     if (isParsingFragment() && m_tree.openElements().hasOnlyOneElement())
2771         return m_fragmentContext.contextElementStackItem();
2772
2773     return m_tree.currentStackItem();
2774 }
2775
2776 // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#tree-construction
2777 bool HTMLTreeBuilder::shouldProcessTokenInForeignContent(AtomicHTMLToken& token)
2778 {
2779     if (m_tree.isEmpty())
2780         return false;
2781     HTMLStackItem& adjustedCurrentNode = adjustedCurrentStackItem();
2782     if (isInHTMLNamespace(adjustedCurrentNode))
2783         return false;
2784     if (HTMLElementStack::isMathMLTextIntegrationPoint(adjustedCurrentNode)) {
2785         if (token.type() == HTMLToken::StartTag
2786             && token.name() != MathMLNames::mglyphTag
2787             && token.name() != MathMLNames::malignmarkTag)
2788             return false;
2789         if (token.type() == HTMLToken::Character)
2790             return false;
2791     }
2792     if (adjustedCurrentNode.hasTagName(MathMLNames::annotation_xmlTag)
2793         && token.type() == HTMLToken::StartTag
2794         && token.name() == SVGNames::svgTag)
2795         return false;
2796     if (HTMLElementStack::isHTMLIntegrationPoint(adjustedCurrentNode)) {
2797         if (token.type() == HTMLToken::StartTag)
2798             return false;
2799         if (token.type() == HTMLToken::Character)
2800             return false;
2801     }
2802     if (token.type() == HTMLToken::EndOfFile)
2803         return false;
2804     return true;
2805 }
2806
2807 static bool hasAttribute(AtomicHTMLToken& token, const QualifiedName& name)
2808 {
2809     return findAttribute(token.attributes(), name);
2810 }
2811
2812 void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken& token)
2813 {
2814     HTMLStackItem& adjustedCurrentNode = adjustedCurrentStackItem();
2815     
2816     switch (token.type()) {
2817     case HTMLToken::Uninitialized:
2818         ASSERT_NOT_REACHED();
2819         break;
2820     case HTMLToken::DOCTYPE:
2821         parseError(token);
2822         break;
2823     case HTMLToken::StartTag: {
2824         if (token.name() == bTag
2825             || token.name() == bigTag
2826             || token.name() == blockquoteTag
2827             || token.name() == bodyTag
2828             || token.name() == brTag
2829             || token.name() == centerTag
2830             || token.name() == codeTag
2831             || token.name() == ddTag
2832             || token.name() == divTag
2833             || token.name() == dlTag
2834             || token.name() == dtTag
2835             || token.name() == emTag
2836             || token.name() == embedTag
2837             || isNumberedHeaderTag(token.name())
2838             || token.name() == headTag
2839             || token.name() == hrTag
2840             || token.name() == iTag
2841             || token.name() == imgTag
2842             || token.name() == liTag
2843             || token.name() == listingTag
2844             || token.name() == menuTag
2845             || token.name() == metaTag
2846             || token.name() == nobrTag
2847             || token.name() == olTag
2848             || token.name() == pTag
2849             || token.name() == preTag
2850             || token.name() == rubyTag
2851             || token.name() == sTag
2852             || token.name() == smallTag
2853             || token.name() == spanTag
2854             || token.name() == strongTag
2855             || token.name() == strikeTag
2856             || token.name() == subTag
2857             || token.name() == supTag
2858             || token.name() == tableTag
2859             || token.name() == ttTag
2860             || token.name() == uTag
2861             || token.name() == ulTag
2862             || token.name() == varTag
2863             || (token.name() == fontTag && (hasAttribute(token, colorAttr) || hasAttribute(token, faceAttr) || hasAttribute(token, sizeAttr)))) {
2864             parseError(token);
2865             m_tree.openElements().popUntilForeignContentScopeMarker();
2866             processStartTag(token);
2867             return;
2868         }
2869         const AtomicString& currentNamespace = adjustedCurrentNode.namespaceURI();
2870         if (currentNamespace == MathMLNames::mathmlNamespaceURI)
2871             adjustMathMLAttributes(token);
2872         if (currentNamespace == SVGNames::svgNamespaceURI) {
2873             adjustSVGTagNameCase(token);
2874             adjustSVGAttributes(token);
2875         }
2876         adjustForeignAttributes(token);
2877         m_tree.insertForeignElement(&token, currentNamespace);
2878         break;
2879     }
2880     case HTMLToken::EndTag: {
2881         if (adjustedCurrentNode.namespaceURI() == SVGNames::svgNamespaceURI)
2882             adjustSVGTagNameCase(token);
2883
2884         if (token.name() == SVGNames::scriptTag && m_tree.currentStackItem().hasTagName(SVGNames::scriptTag)) {
2885             if (scriptingContentIsAllowed(m_tree.parserContentPolicy()))
2886                 m_scriptToProcess = &m_tree.currentElement();
2887             m_tree.openElements().pop();
2888             return;
2889         }
2890         if (!isInHTMLNamespace(m_tree.currentStackItem())) {
2891             // FIXME: This code just wants an Element* iterator, instead of an ElementRecord*
2892             auto* nodeRecord = &m_tree.openElements().topRecord();
2893             if (nodeRecord->stackItem().localName() != token.name())
2894                 parseError(token);
2895             while (1) {
2896                 if (nodeRecord->stackItem().localName() == token.name()) {
2897                     m_tree.openElements().popUntilPopped(&nodeRecord->element());
2898                     return;
2899                 }
2900                 nodeRecord = nodeRecord->next();
2901
2902                 if (isInHTMLNamespace(nodeRecord->stackItem()))
2903                     break;
2904             }
2905         }
2906         // Otherwise, process the token according to the rules given in the section corresponding to the current insertion mode in HTML content.
2907         processEndTag(token);
2908         break;
2909     }
2910     case HTMLToken::Comment:
2911         m_tree.insertComment(&token);
2912         return;
2913     case HTMLToken::Character: {
2914         String characters = String(token.characters(), token.charactersLength());
2915         m_tree.insertTextNode(characters);
2916         if (m_framesetOk && !isAllWhitespaceOrReplacementCharacters(characters))
2917             m_framesetOk = false;
2918         break;
2919     }
2920     case HTMLToken::EndOfFile:
2921         ASSERT_NOT_REACHED();
2922         break;
2923     }
2924 }
2925
2926 void HTMLTreeBuilder::finished()
2927 {
2928     ASSERT(!m_destroyed);
2929
2930     if (isParsingFragment())
2931         return;
2932
2933 #if ENABLE(TEMPLATE_ELEMENT)
2934     ASSERT(m_templateInsertionModes.isEmpty());
2935 #endif
2936
2937     m_tree.finishedParsing();
2938     // The tree builder might have been destroyed as an indirect result of finishing the parsing.
2939 }
2940
2941 inline void HTMLTreeBuilder::parseError(AtomicHTMLToken&)
2942 {
2943 }
2944
2945 }