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