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