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