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