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