2010-07-06 Eric Seidel <eric@webkit.org>
[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 #if ENABLE(MATHML)
45 #include "MathMLNames.h"
46 #endif
47 #include "NotImplemented.h"
48 #if ENABLE(SVG)
49 #include "SVGNames.h"
50 #endif
51 #include "ScriptController.h"
52 #include "Settings.h"
53 #include "Text.h"
54 #include <wtf/UnusedParam.h>
55
56 namespace WebCore {
57
58 using namespace HTMLNames;
59
60 static const int uninitializedLineNumberValue = -1;
61
62 namespace {
63
64 inline bool isTreeBuilderWhiteSpace(UChar cc)
65 {
66     return cc == '\t' || cc == '\x0A' || cc == '\x0C' || cc == '\x0D' || cc == ' ';
67 }
68
69 bool shouldUseLegacyTreeBuilder(Document* document)
70 {
71     return !document->settings() || !document->settings()->html5TreeBuilderEnabled();
72 }
73
74 bool isNumberedHeaderTag(const AtomicString& tagName)
75 {
76     return tagName == h1Tag
77         || tagName == h2Tag
78         || tagName == h3Tag
79         || tagName == h4Tag
80         || tagName == h5Tag
81         || tagName == h6Tag;
82 }
83
84 bool isCaptionColOrColgroupTag(const AtomicString& tagName)
85 {
86     return tagName == captionTag
87         || tagName == colTag
88         || tagName == colgroupTag;
89 }
90
91 bool isTableCellContextTag(const AtomicString& tagName)
92 {
93     return tagName == thTag || tagName == tdTag;
94 }
95
96 bool isTableBodyContextTag(const AtomicString& tagName)
97 {
98     return tagName == tbodyTag
99         || tagName == tfootTag
100         || tagName == theadTag;
101 }
102
103 // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#special
104 bool isSpecialTag(const AtomicString& tagName)
105 {
106     return tagName == addressTag
107         || tagName == articleTag
108         || tagName == asideTag
109         || tagName == baseTag
110         || tagName == basefontTag
111         || tagName == "bgsound"
112         || tagName == blockquoteTag
113         || tagName == bodyTag
114         || tagName == brTag
115         || tagName == buttonTag
116         || tagName == centerTag
117         || tagName == colTag
118         || tagName == colgroupTag
119         || tagName == "command"
120         || tagName == ddTag
121         || tagName == "details"
122         || tagName == dirTag
123         || tagName == divTag
124         || tagName == dlTag
125         || tagName == dtTag
126         || tagName == embedTag
127         || tagName == fieldsetTag
128         || tagName == "figure"
129         || tagName == footerTag
130         || tagName == formTag
131         || tagName == frameTag
132         || tagName == framesetTag
133         || isNumberedHeaderTag(tagName)
134         || tagName == headTag
135         || tagName == headerTag
136         || tagName == hgroupTag
137         || tagName == hrTag
138         || tagName == iframeTag
139         || tagName == imgTag
140         || tagName == inputTag
141         || tagName == isindexTag
142         || tagName == liTag
143         || tagName == linkTag
144         || tagName == listingTag
145         || tagName == menuTag
146         || tagName == metaTag
147         || tagName == navTag
148         || tagName == noembedTag
149         || tagName == noframesTag
150         || tagName == noscriptTag
151         || tagName == olTag
152         || tagName == pTag
153         || tagName == paramTag
154         || tagName == plaintextTag
155         || tagName == preTag
156         || tagName == scriptTag
157         || tagName == sectionTag
158         || tagName == selectTag
159         || tagName == styleTag
160         || isTableBodyContextTag(tagName)
161         || tagName == textareaTag
162         || tagName == titleTag
163         || tagName == trTag
164         || tagName == ulTag
165         || tagName == wbrTag
166         || tagName == xmpTag;
167 }
168
169 // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#scoping
170 // Same as isScopingTag in LegacyHTMLTreeBuilder.cpp
171 // and isScopeMarker in HTMLElementStack.cpp
172 bool isScopingTag(const AtomicString& tagName)
173 {
174     return tagName == appletTag
175         || tagName == buttonTag
176         || tagName == captionTag
177 #if ENABLE(SVG_FOREIGN_OBJECT)
178         || tagName == SVGNames::foreignObjectTag
179 #endif
180         || tagName == htmlTag
181         || tagName == marqueeTag
182         || tagName == objectTag
183         || tagName == tableTag
184         || isTableCellContextTag(tagName);
185 }
186
187 bool isNonAnchorNonNobrFormattingTag(const AtomicString& tagName)
188 {
189     return tagName == bTag
190         || tagName == bigTag
191         || tagName == codeTag
192         || tagName == emTag
193         || tagName == fontTag
194         || tagName == iTag
195         || tagName == sTag
196         || tagName == smallTag
197         || tagName == strikeTag
198         || tagName == strongTag
199         || tagName == ttTag
200         || tagName == uTag;
201 }
202
203 bool isNonAnchorFormattingTag(const AtomicString& tagName)
204 {
205     return tagName == nobrTag
206         || isNonAnchorNonNobrFormattingTag(tagName);
207 }
208
209 bool requiresRedirectToFosterParent(Element* element)
210 {
211     return element->hasTagName(tableTag)
212         || isTableBodyContextTag(element->localName())
213         || element->hasTagName(trTag);
214 }
215
216 // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#formatting
217 bool isFormattingTag(const AtomicString& tagName)
218 {
219     return tagName == aTag || isNonAnchorFormattingTag(tagName);
220 }
221
222 // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#phrasing
223 bool isPhrasingTag(const AtomicString& tagName)
224 {
225     return !isSpecialTag(tagName) && !isScopingTag(tagName) && !isFormattingTag(tagName);
226 }
227
228 bool isNotFormattingAndNotPhrasing(const Element* element)
229 {
230     // The spec often says "node is not in the formatting category, and is not
231     // in the phrasing category". !phrasing && !formatting == scoping || special
232     // scoping || special is easier to compute.
233     // FIXME: localName() is wrong for non-html content.
234     const AtomicString& tagName = element->localName();
235     return isScopingTag(tagName) || isSpecialTag(tagName);
236 }
237
238 } // namespace
239
240 HTMLTreeBuilder::HTMLTreeBuilder(HTMLTokenizer* tokenizer, HTMLDocument* document, bool reportErrors)
241     : m_framesetOk(true)
242     , m_document(document)
243     , m_tree(document, FragmentScriptingAllowed)
244     , m_reportErrors(reportErrors)
245     , m_isPaused(false)
246     , m_insertionMode(InitialMode)
247     , m_originalInsertionMode(InitialMode)
248     , m_secondaryInsertionMode(InitialMode)
249     , m_tokenizer(tokenizer)
250     , m_legacyTreeBuilder(shouldUseLegacyTreeBuilder(document) ? new LegacyHTMLTreeBuilder(document, reportErrors) : 0)
251     , m_lastScriptElementStartLine(uninitializedLineNumberValue)
252     , m_scriptToProcessStartLine(uninitializedLineNumberValue)
253     , m_fragmentScriptingPermission(FragmentScriptingAllowed)
254     , m_isParsingFragment(false)
255 {
256 }
257
258 // FIXME: Member variables should be grouped into self-initializing structs to
259 // minimize code duplication between these constructors.
260 HTMLTreeBuilder::HTMLTreeBuilder(HTMLTokenizer* tokenizer, DocumentFragment* fragment, FragmentScriptingPermission scriptingPermission)
261     : m_framesetOk(true)
262     , m_document(fragment->document())
263     , m_tree(fragment->document(), scriptingPermission)
264     , m_reportErrors(false) // FIXME: Why not report errors in fragments?
265     , m_isPaused(false)
266     , m_insertionMode(InitialMode)
267     , m_originalInsertionMode(InitialMode)
268     , m_secondaryInsertionMode(InitialMode)
269     , m_tokenizer(tokenizer)
270     , m_legacyTreeBuilder(new LegacyHTMLTreeBuilder(fragment, scriptingPermission))
271     , m_lastScriptElementStartLine(uninitializedLineNumberValue)
272     , m_scriptToProcessStartLine(uninitializedLineNumberValue)
273     , m_fragmentScriptingPermission(scriptingPermission)
274     , m_isParsingFragment(true)
275 {
276 }
277
278 HTMLTreeBuilder::~HTMLTreeBuilder()
279 {
280 }
281
282 static void convertToOldStyle(AtomicHTMLToken& token, Token& oldStyleToken)
283 {
284     switch (token.type()) {
285     case HTMLToken::Uninitialized:
286     case HTMLToken::DOCTYPE:
287         ASSERT_NOT_REACHED();
288         break;
289     case HTMLToken::EndOfFile:
290         ASSERT_NOT_REACHED();
291         notImplemented();
292         break;
293     case HTMLToken::StartTag:
294     case HTMLToken::EndTag: {
295         oldStyleToken.beginTag = (token.type() == HTMLToken::StartTag);
296         oldStyleToken.selfClosingTag = token.selfClosing();
297         oldStyleToken.tagName = token.name();
298         oldStyleToken.attrs = token.takeAtributes();
299         break;
300     }
301     case HTMLToken::Comment:
302         oldStyleToken.tagName = commentAtom;
303         oldStyleToken.text = token.comment().impl();
304         break;
305     case HTMLToken::Character:
306         oldStyleToken.tagName = textAtom;
307         oldStyleToken.text = token.characters().impl();
308         break;
309     }
310 }
311
312 void HTMLTreeBuilder::handleScriptStartTag()
313 {
314     notImplemented(); // The HTML frgment case?
315     m_tokenizer->setState(HTMLTokenizer::ScriptDataState);
316     notImplemented(); // Save insertion mode.
317 }
318
319 void HTMLTreeBuilder::handleScriptEndTag(Element* scriptElement, int scriptStartLine)
320 {
321     ASSERT(!m_scriptToProcess); // Caller never called takeScriptToProcess!
322     ASSERT(m_scriptToProcessStartLine == uninitializedLineNumberValue); // Caller never called takeScriptToProcess!
323     notImplemented(); // Save insertion mode and insertion point?
324
325     // Pause ourselves so that parsing stops until the script can be processed by the caller.
326     m_isPaused = true;
327     m_scriptToProcess = scriptElement;
328     // Lexer line numbers are 0-based, ScriptSourceCode expects 1-based lines,
329     // so we convert here before passing the line number off to HTMLScriptRunner.
330     m_scriptToProcessStartLine = scriptStartLine + 1;
331 }
332
333 PassRefPtr<Element> HTMLTreeBuilder::takeScriptToProcess(int& scriptStartLine)
334 {
335     // Unpause ourselves, callers may pause us again when processing the script.
336     // The HTML5 spec is written as though scripts are executed inside the tree
337     // builder.  We pause the parser to exit the tree builder, and then resume
338     // before running scripts.
339     m_isPaused = false;
340     scriptStartLine = m_scriptToProcessStartLine;
341     m_scriptToProcessStartLine = uninitializedLineNumberValue;
342     return m_scriptToProcess.release();
343 }
344
345 HTMLTokenizer::State HTMLTreeBuilder::adjustedLexerState(HTMLTokenizer::State state, const AtomicString& tagName, Frame* frame)
346 {
347     if (tagName == textareaTag || tagName == titleTag)
348         return HTMLTokenizer::RCDATAState;
349
350     if (tagName == styleTag || tagName == iframeTag || tagName == xmpTag || tagName == noembedTag
351         || tagName == noframesTag || (tagName == noscriptTag && isScriptingFlagEnabled(frame)))
352         return HTMLTokenizer::RAWTEXTState;
353
354     if (tagName == plaintextTag)
355         return HTMLTokenizer::PLAINTEXTState;
356
357     return state;
358 }
359
360 void HTMLTreeBuilder::passTokenToLegacyParser(HTMLToken& token)
361 {
362     if (token.type() == HTMLToken::DOCTYPE) {
363         DoctypeToken doctypeToken;
364         doctypeToken.m_name.append(token.name().data(), token.name().size());
365         doctypeToken.m_publicID = token.publicIdentifier();
366         doctypeToken.m_systemID = token.systemIdentifier();
367         doctypeToken.m_forceQuirks = token.forceQuirks();
368
369         m_legacyTreeBuilder->parseDoctypeToken(&doctypeToken);
370         return;
371     }
372
373     if (token.type() == HTMLToken::EndOfFile)
374         return;
375
376     // For now, we translate into an old-style token for testing.
377     Token oldStyleToken;
378     AtomicHTMLToken atomicToken(token);
379     convertToOldStyle(atomicToken, oldStyleToken);
380
381     RefPtr<Node> result =  m_legacyTreeBuilder->parseToken(&oldStyleToken);
382     if (token.type() == HTMLToken::StartTag) {
383         // This work is supposed to be done by the parser, but
384         // when using the old parser for we have to do this manually.
385         if (oldStyleToken.tagName == scriptTag) {
386             handleScriptStartTag();
387             m_lastScriptElement = static_pointer_cast<Element>(result);
388             m_lastScriptElementStartLine = m_tokenizer->lineNumber();
389         } else if (oldStyleToken.tagName == preTag || oldStyleToken.tagName == listingTag)
390             m_tokenizer->skipLeadingNewLineForListing();
391         else
392             m_tokenizer->setState(adjustedLexerState(m_tokenizer->state(), oldStyleToken.tagName, m_document->frame()));
393     } else if (token.type() == HTMLToken::EndTag) {
394         if (oldStyleToken.tagName == scriptTag) {
395             if (m_lastScriptElement) {
396                 ASSERT(m_lastScriptElementStartLine != uninitializedLineNumberValue);
397                 if (m_fragmentScriptingPermission == FragmentScriptingNotAllowed) {
398                     // FIXME: This is a horrible hack for platform/Pasteboard.
399                     // Clear the <script> tag when using the Parser to create
400                     // a DocumentFragment for pasting so that javascript content
401                     // does not show up in pasted HTML.
402                     m_lastScriptElement->removeChildren();
403                 } else if (insertionMode() != AfterFramesetMode)
404                     handleScriptEndTag(m_lastScriptElement.get(), m_lastScriptElementStartLine);
405                 m_lastScriptElement = 0;
406                 m_lastScriptElementStartLine = uninitializedLineNumberValue;
407             }
408         } else if (oldStyleToken.tagName == framesetTag)
409             setInsertionMode(AfterFramesetMode);
410     }
411 }
412
413 void HTMLTreeBuilder::constructTreeFromToken(HTMLToken& rawToken)
414 {
415     if (m_legacyTreeBuilder) {
416         passTokenToLegacyParser(rawToken);
417         return;
418     }
419
420     AtomicHTMLToken token(rawToken);
421     processToken(token);
422 }
423
424 void HTMLTreeBuilder::processToken(AtomicHTMLToken& token)
425 {
426     switch (token.type()) {
427     case HTMLToken::Uninitialized:
428         ASSERT_NOT_REACHED();
429         break;
430     case HTMLToken::DOCTYPE:
431         processDoctypeToken(token);
432         break;
433     case HTMLToken::StartTag:
434         processStartTag(token);
435         break;
436     case HTMLToken::EndTag:
437         processEndTag(token);
438         break;
439     case HTMLToken::Comment:
440         processComment(token);
441         return;
442     case HTMLToken::Character:
443         processCharacter(token);
444         break;
445     case HTMLToken::EndOfFile:
446         processEndOfFile(token);
447         break;
448     }
449 }
450
451 void HTMLTreeBuilder::processDoctypeToken(AtomicHTMLToken& token)
452 {
453     ASSERT(token.type() == HTMLToken::DOCTYPE);
454     if (insertionMode() == InitialMode) {
455         m_tree.insertDoctype(token);
456         return;
457     }
458     parseError(token);
459 }
460
461 void HTMLTreeBuilder::processFakeStartTag(const QualifiedName& tagName, PassRefPtr<NamedNodeMap> attributes)
462 {
463     // FIXME: We'll need a fancier conversion than just "localName" for SVG/MathML tags.
464     AtomicHTMLToken fakeToken(HTMLToken::StartTag, tagName.localName(), attributes);
465     processStartTag(fakeToken);
466 }
467
468 void HTMLTreeBuilder::processFakeEndTag(const QualifiedName& tagName)
469 {
470     // FIXME: We'll need a fancier conversion than just "localName" for SVG/MathML tags.
471     AtomicHTMLToken fakeToken(HTMLToken::EndTag, tagName.localName());
472     processEndTag(fakeToken);
473 }
474
475 void HTMLTreeBuilder::processFakeCharacters(const String& characters)
476 {
477     AtomicHTMLToken fakeToken(characters);
478     processCharacter(fakeToken);
479 }
480
481 void HTMLTreeBuilder::processFakePEndTagIfPInScope()
482 {
483     if (!m_tree.openElements()->inScope(pTag.localName()))
484         return;
485     AtomicHTMLToken endP(HTMLToken::EndTag, pTag.localName());
486     processEndTag(endP);
487 }
488
489 PassRefPtr<NamedNodeMap> HTMLTreeBuilder::attributesForIsindexInput(AtomicHTMLToken& token)
490 {
491     RefPtr<NamedNodeMap> attributes = token.takeAtributes();
492     if (!attributes)
493         attributes = NamedNodeMap::create();
494     else {
495         attributes->removeAttribute(nameAttr);
496         attributes->removeAttribute(actionAttr);
497         attributes->removeAttribute(promptAttr);
498     }
499
500     RefPtr<Attribute> mappedAttribute = Attribute::createMapped(nameAttr, isindexTag.localName());
501     attributes->insertAttribute(mappedAttribute.release(), false);
502     return attributes.release();
503 }
504
505 void HTMLTreeBuilder::processIsindexStartTagForInBody(AtomicHTMLToken& token)
506 {
507     ASSERT(token.type() == HTMLToken::StartTag);
508     ASSERT(token.name() == isindexTag);
509     parseError(token);
510     if (m_tree.form())
511         return;
512     notImplemented(); // Acknowledge self-closing flag
513     processFakeStartTag(formTag);
514     Attribute* actionAttribute = token.getAttributeItem(actionAttr);
515     if (actionAttribute) {
516         ASSERT(m_tree.currentElement()->hasTagName(formTag));
517         m_tree.currentElement()->setAttribute(actionAttr, actionAttribute->value());
518     }
519     processFakeStartTag(hrTag);
520     processFakeStartTag(labelTag);
521     Attribute* promptAttribute = token.getAttributeItem(promptAttr);
522     if (promptAttribute)
523         processFakeCharacters(promptAttribute->value());
524     else
525         processFakeCharacters(searchableIndexIntroduction());
526     processFakeStartTag(inputTag, attributesForIsindexInput(token));
527     notImplemented(); // This second set of characters may be needed by non-english locales.
528     processFakeEndTag(labelTag);
529     processFakeStartTag(hrTag);
530     processFakeEndTag(formTag);
531 }
532
533 namespace {
534
535 bool isLi(const Element* element)
536 {
537     return element->hasTagName(liTag);
538 }
539
540 bool isDdOrDt(const Element* element)
541 {
542     return element->hasTagName(ddTag) || element->hasTagName(dtTag);
543 }
544
545 }
546
547 template <bool shouldClose(const Element*)>
548 void HTMLTreeBuilder::processCloseWhenNestedTag(AtomicHTMLToken& token)
549 {
550     m_framesetOk = false;
551     HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord();
552     while (1) {
553         Element* node = nodeRecord->element();
554         if (shouldClose(node)) {
555             processFakeEndTag(node->tagQName());
556             break;
557         }
558         if (isNotFormattingAndNotPhrasing(node) && !node->hasTagName(addressTag) && !node->hasTagName(divTag) && !node->hasTagName(pTag))
559             break;
560         nodeRecord = nodeRecord->next();
561     }
562     processFakePEndTagIfPInScope();
563     m_tree.insertElement(token);
564 }
565
566 void HTMLTreeBuilder::processStartTagForInBody(AtomicHTMLToken& token)
567 {
568     ASSERT(token.type() == HTMLToken::StartTag);
569     if (token.name() == htmlTag) {
570         m_tree.insertHTMLHtmlStartTagInBody(token);
571         return;
572     }
573     if (token.name() == baseTag || token.name() == "command" || token.name() == linkTag || token.name() == metaTag || token.name() == noframesTag || token.name() == scriptTag || token.name() == styleTag || token.name() == titleTag) {
574         bool didProcess = processStartTagForInHead(token);
575         ASSERT_UNUSED(didProcess, didProcess);
576         return;
577     }
578     if (token.name() == bodyTag) {
579         m_tree.insertHTMLBodyStartTagInBody(token);
580         return;
581     }
582     if (token.name() == framesetTag) {
583         parseError(token);
584         notImplemented(); // fragment case
585         if (!m_framesetOk)
586             return;
587         ExceptionCode ec = 0;
588         m_tree.openElements()->bodyElement()->remove(ec);
589         ASSERT(!ec);
590         m_tree.openElements()->popUntil(m_tree.openElements()->bodyElement());
591         m_tree.openElements()->popHTMLBodyElement();
592         ASSERT(m_tree.openElements()->top() == m_tree.openElements()->htmlElement());
593         m_tree.insertElement(token);
594         m_insertionMode = InFramesetMode;
595         return;
596     }
597     if (token.name() == addressTag || token.name() == articleTag || token.name() == asideTag || token.name() == blockquoteTag || token.name() == centerTag || token.name() == "details" || token.name() == dirTag || token.name() == divTag || token.name() == dlTag || token.name() == fieldsetTag || token.name() == "figure" || token.name() == footerTag || token.name() == headerTag || token.name() == hgroupTag || token.name() == menuTag || token.name() == navTag || token.name() == olTag || token.name() == pTag || token.name() == sectionTag || token.name() == ulTag) {
598         processFakePEndTagIfPInScope();
599         m_tree.insertElement(token);
600         return;
601     }
602     if (isNumberedHeaderTag(token.name())) {
603         processFakePEndTagIfPInScope();
604         if (isNumberedHeaderTag(m_tree.currentElement()->localName())) {
605             parseError(token);
606             m_tree.openElements()->pop();
607         }
608         m_tree.insertElement(token);
609         return;
610     }
611     if (token.name() == preTag || token.name() == listingTag) {
612         processFakePEndTagIfPInScope();
613         m_tree.insertElement(token);
614         m_tokenizer->skipLeadingNewLineForListing();
615         m_framesetOk = false;
616         return;
617     }
618     if (token.name() == formTag) {
619         notImplemented();
620         processFakePEndTagIfPInScope();
621         m_tree.insertElement(token);
622         m_tree.setForm(m_tree.currentElement());
623         return;
624     }
625     if (token.name() == liTag) {
626         processCloseWhenNestedTag<isLi>(token);
627         return;
628     }
629     if (token.name() == ddTag || token.name() == dtTag) {
630         processCloseWhenNestedTag<isDdOrDt>(token);
631         return;
632     }
633     if (token.name() == plaintextTag) {
634         processFakePEndTagIfPInScope();
635         m_tree.insertElement(token);
636         m_tokenizer->setState(HTMLTokenizer::PLAINTEXTState);
637         return;
638     }
639     if (token.name() == buttonTag) {
640         notImplemented();
641         m_tree.reconstructTheActiveFormattingElements();
642         m_tree.insertElement(token);
643         m_framesetOk = false;
644         return;
645     }
646     if (token.name() == aTag) {
647         Element* activeATag = m_tree.activeFormattingElements()->closestElementInScopeWithName(aTag.localName());
648         if (activeATag) {
649             parseError(token);
650             processFakeEndTag(aTag);
651             m_tree.activeFormattingElements()->remove(activeATag);
652             if (m_tree.openElements()->contains(activeATag))
653                 m_tree.openElements()->remove(activeATag);
654         }
655         m_tree.reconstructTheActiveFormattingElements();
656         m_tree.insertFormattingElement(token);
657         return;
658     }
659     if (isNonAnchorNonNobrFormattingTag(token.name())) {
660         m_tree.reconstructTheActiveFormattingElements();
661         m_tree.insertFormattingElement(token);
662         return;
663     }
664     if (token.name() == nobrTag) {
665         m_tree.reconstructTheActiveFormattingElements();
666         if (m_tree.openElements()->inScope(nobrTag)) {
667             parseError(token);
668             processFakeEndTag(nobrTag);
669             m_tree.reconstructTheActiveFormattingElements();
670         }
671         m_tree.insertFormattingElement(token);
672         return;
673     }
674     if (token.name() == appletTag || token.name() == marqueeTag || token.name() == objectTag) {
675         m_tree.reconstructTheActiveFormattingElements();
676         m_tree.insertElement(token);
677         m_tree.activeFormattingElements()->appendMarker();
678         m_framesetOk = false;
679         return;
680     }
681     if (token.name() == tableTag) {
682         notImplemented();
683         m_tree.insertElement(token);
684         m_framesetOk = false;
685         m_insertionMode = InTableMode;
686         return;
687     }
688     if (token.name() == imageTag) {
689         parseError(token);
690         // Apparently we're not supposed to ask.
691         token.setName(imgTag.localName());
692         // Note the fall through to the imgTag handling below!
693     }
694     if (token.name() == areaTag || token.name() == basefontTag || token.name() == "bgsound" || token.name() == brTag || token.name() == embedTag || token.name() == imgTag || token.name() == inputTag || token.name() == keygenTag || token.name() == wbrTag) {
695         m_tree.reconstructTheActiveFormattingElements();
696         m_tree.insertSelfClosingElement(token);
697         m_framesetOk = false;
698         return;
699     }
700     if (token.name() == paramTag || token.name() == sourceTag || token.name() == "track") {
701         m_tree.insertSelfClosingElement(token);
702         return;
703     }
704     if (token.name() == hrTag) {
705         processFakePEndTagIfPInScope();
706         m_tree.insertSelfClosingElement(token);
707         m_framesetOk = false;
708         return;
709     }
710     if (token.name() == isindexTag) {
711         processIsindexStartTagForInBody(token);
712         return;
713     }
714     if (token.name() == textareaTag) {
715         m_tree.insertElement(token);
716         m_tokenizer->skipLeadingNewLineForListing();
717         m_tokenizer->setState(HTMLTokenizer::RCDATAState);
718         m_originalInsertionMode = m_insertionMode;
719         m_framesetOk = false;
720         m_insertionMode = TextMode;
721         return;
722     }
723     if (token.name() == xmpTag) {
724         processFakePEndTagIfPInScope();
725         m_tree.reconstructTheActiveFormattingElements();
726         m_framesetOk = false;
727         processGenericRawTextStartTag(token);
728         return;
729     }
730     if (token.name() == iframeTag) {
731         m_framesetOk = false;
732         processGenericRawTextStartTag(token);
733         return;
734     }
735     if (token.name() == noembedTag) {
736         processGenericRawTextStartTag(token);
737         return;
738     }
739     if (token.name() == noscriptTag && isScriptingFlagEnabled(m_document->frame())) {
740         processGenericRawTextStartTag(token);
741         return;
742     }
743     if (token.name() == selectTag) {
744         m_tree.reconstructTheActiveFormattingElements();
745         m_tree.insertElement(token);
746         m_framesetOk = false;
747         if (m_insertionMode == InTableMode || m_insertionMode == InCaptionMode || m_insertionMode == InColumnGroupMode || m_insertionMode == InTableBodyMode || m_insertionMode == InRowMode || m_insertionMode == InCellMode)
748             m_insertionMode = InSelectInTableMode;
749         else
750             m_insertionMode = InSelectMode;
751         return;
752     }
753     if (token.name() == optgroupTag || token.name() == optionTag) {
754         if (m_tree.openElements()->inScope(optionTag.localName())) {
755             AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName());
756             processEndTag(endOption);
757         }
758         m_tree.reconstructTheActiveFormattingElements();
759         m_tree.insertElement(token);
760         return;
761     }
762     if (token.name() == rpTag || token.name() == rtTag) {
763         if (m_tree.openElements()->inScope(rubyTag.localName())) {
764             m_tree.generateImpliedEndTags();
765             if (!m_tree.currentElement()->hasTagName(rubyTag)) {
766                 parseError(token);
767                 m_tree.openElements()->popUntil(rubyTag.localName());
768             }
769         }
770         m_tree.insertElement(token);
771         return;
772     }
773     if (token.name() == "math") {
774         // This is the MathML foreign content branch point.
775         notImplemented();
776     }
777     if (token.name() == "svg") {
778         // This is the SVG foreign content branch point.
779         notImplemented();
780     }
781     if (isCaptionColOrColgroupTag(token.name())
782         || token.name() == frameTag
783         || token.name() == headTag
784         || isTableBodyContextTag(token.name())
785         || isTableCellContextTag(token.name())
786         || token.name() == trTag) {
787         parseError(token);
788         return;
789     }
790     m_tree.reconstructTheActiveFormattingElements();
791     m_tree.insertElement(token);
792 }
793
794 bool HTMLTreeBuilder::processColgroupEndTagForInColumnGroup()
795 {
796     if (m_tree.currentElement() == m_tree.openElements()->htmlElement()) {
797         ASSERT(m_isParsingFragment);
798         // FIXME: parse error
799         return false;
800     }
801     m_tree.openElements()->pop();
802     m_insertionMode = InTableMode;
803     return true;
804 }
805
806 // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#close-the-cell
807 void HTMLTreeBuilder::closeTheCell()
808 {
809     ASSERT(insertionMode() == InCellMode);
810     if (m_tree.openElements()->inScope(tdTag)) {
811         ASSERT(!m_tree.openElements()->inScope(thTag));
812         processFakeEndTag(tdTag);
813         return;
814     }
815     ASSERT(m_tree.openElements()->inScope(thTag));
816     processFakeEndTag(thTag);
817     ASSERT(insertionMode() == InRowMode);
818 }
819
820 void HTMLTreeBuilder::processStartTagForInTable(AtomicHTMLToken& token)
821 {
822     ASSERT(token.type() == HTMLToken::StartTag);
823     if (token.name() == captionTag) {
824         m_tree.openElements()->popUntilTableScopeMarker();
825         m_tree.activeFormattingElements()->appendMarker();
826         m_tree.insertElement(token);
827         m_insertionMode = InCaptionMode;
828         return;
829     }
830     if (token.name() == colgroupTag) {
831         m_tree.openElements()->popUntilTableScopeMarker();
832         m_tree.insertElement(token);
833         m_insertionMode = InColumnGroupMode;
834         return;
835     }
836     if (token.name() == colTag) {
837         processFakeStartTag(colgroupTag);
838         ASSERT(InColumnGroupMode);
839         processStartTag(token);
840         return;
841     }
842     if (isTableBodyContextTag(token.name())) {
843         m_tree.openElements()->popUntilTableScopeMarker();
844         m_tree.insertElement(token);
845         m_insertionMode = InTableBodyMode;
846         return;
847     }
848     if (isTableCellContextTag(token.name()) || token.name() == trTag) {
849         processFakeStartTag(tbodyTag);
850         ASSERT(insertionMode() == InTableBodyMode);
851         processStartTag(token);
852         return;
853     }
854     if (token.name() == tableTag) {
855         notImplemented();
856         return;
857     }
858     if (token.name() == styleTag || token.name() == scriptTag) {
859         processStartTagForInHead(token);
860         return;
861     }
862     if (token.name() == inputTag) {
863         notImplemented();
864         return;
865     }
866     if (token.name() == formTag) {
867         parseError(token);
868         if (m_tree.form())
869             return;
870         m_tree.insertSelfClosingElement(token);
871         return;
872     }
873     parseError(token);
874     HTMLConstructionSite::RedirectToFosterParentGuard redirecter(m_tree, requiresRedirectToFosterParent(m_tree.currentElement()));
875     processStartTagForInBody(token);
876 }
877
878 void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token)
879 {
880     ASSERT(token.type() == HTMLToken::StartTag);
881     switch (insertionMode()) {
882     case InitialMode:
883         ASSERT(insertionMode() == InitialMode);
884         processDefaultForInitialMode(token);
885         // Fall through.
886     case BeforeHTMLMode:
887         ASSERT(insertionMode() == BeforeHTMLMode);
888         if (token.name() == htmlTag) {
889             m_tree.insertHTMLHtmlStartTagBeforeHTML(token);
890             setInsertionMode(BeforeHeadMode);
891             return;
892         }
893         processDefaultForBeforeHTMLMode(token);
894         // Fall through.
895     case BeforeHeadMode:
896         ASSERT(insertionMode() == BeforeHeadMode);
897         if (token.name() == htmlTag) {
898             m_tree.insertHTMLHtmlStartTagInBody(token);
899             return;
900         }
901         if (token.name() == headTag) {
902             m_tree.insertHTMLHeadElement(token);
903             setInsertionMode(InHeadMode);
904             return;
905         }
906         processDefaultForBeforeHeadMode(token);
907         // Fall through.
908     case InHeadMode:
909         ASSERT(insertionMode() == InHeadMode);
910         if (processStartTagForInHead(token))
911             return;
912         processDefaultForInHeadMode(token);
913         // Fall through.
914     case AfterHeadMode:
915         ASSERT(insertionMode() == AfterHeadMode);
916         if (token.name() == htmlTag) {
917             m_tree.insertHTMLHtmlStartTagInBody(token);
918             return;
919         }
920         if (token.name() == bodyTag) {
921             m_framesetOk = false;
922             m_tree.insertHTMLBodyElement(token);
923             m_insertionMode = InBodyMode;
924             return;
925         }
926         if (token.name() == framesetTag) {
927             m_tree.insertElement(token);
928             setInsertionMode(InFramesetMode);
929             return;
930         }
931         if (token.name() == baseTag || token.name() == linkTag || token.name() == metaTag || token.name() == noframesTag || token.name() == scriptTag || token.name() == styleTag || token.name() == titleTag) {
932             parseError(token);
933             ASSERT(m_tree.head());
934             m_tree.openElements()->pushHTMLHeadElement(m_tree.head());
935             processStartTagForInHead(token);
936             m_tree.openElements()->removeHTMLHeadElement(m_tree.head());
937             return;
938         }
939         if (token.name() == headTag) {
940             parseError(token);
941             return;
942         }
943         processDefaultForAfterHeadMode(token);
944         // Fall through
945     case InBodyMode:
946         ASSERT(insertionMode() == InBodyMode);
947         processStartTagForInBody(token);
948         break;
949     case InTableMode:
950         ASSERT(insertionMode() == InTableMode);
951         processStartTagForInTable(token);
952         break;
953     case InCaptionMode:
954         ASSERT(insertionMode() == InCaptionMode);
955         if (isCaptionColOrColgroupTag(token.name())
956             || isTableBodyContextTag(token.name())
957             || isTableCellContextTag(token.name())
958             || token.name() == trTag) {
959             parseError(token);
960             if (!processCaptionEndTagForInCaption()) {
961                 ASSERT(m_isParsingFragment);
962                 return;
963             }
964             processStartTag(token);
965             return;
966         }
967         processStartTagForInBody(token);
968         break;
969     case InColumnGroupMode:
970         ASSERT(insertionMode() == InColumnGroupMode);
971         if (token.name() == htmlTag) {
972             m_tree.insertHTMLHtmlStartTagInBody(token);
973             return;
974         }
975         if (token.name() == colTag) {
976             m_tree.insertSelfClosingElement(token);
977             return;
978         }
979         if (!processColgroupEndTagForInColumnGroup()) {
980             ASSERT(m_isParsingFragment);
981             return;
982         }
983         processStartTag(token);
984         break;
985     case InTableBodyMode:
986         ASSERT(insertionMode() == InTableBodyMode);
987         if (token.name() == trTag) {
988             m_tree.openElements()->popUntilTableBodyScopeMarker(); // How is there ever anything to pop?
989             m_tree.insertElement(token);
990             m_insertionMode = InRowMode;
991             return;
992         }
993         if (isTableCellContextTag(token.name())) {
994             parseError(token);
995             processFakeStartTag(trTag);
996             ASSERT(insertionMode() == InRowMode);
997             processStartTag(token);
998             return;
999         }
1000         if (isCaptionColOrColgroupTag(token.name()) || isTableBodyContextTag(token.name())) {
1001             // FIXME: This is slow.
1002             if (!m_tree.openElements()->inTableScope(tbodyTag.localName()) && !m_tree.openElements()->inTableScope(theadTag.localName()) && !m_tree.openElements()->inTableScope(tfootTag.localName())) {
1003                 ASSERT(m_isParsingFragment);
1004                 parseError(token);
1005                 return;
1006             }
1007             m_tree.openElements()->popUntilTableBodyScopeMarker();
1008             ASSERT(isTableBodyContextTag(m_tree.currentElement()->localName()));
1009             processFakeEndTag(m_tree.currentElement()->tagQName());
1010             processStartTag(token);
1011             return;
1012         }
1013         processStartTagForInTable(token);
1014         break;
1015     case InRowMode:
1016         ASSERT(insertionMode() == InRowMode);
1017         if (isTableCellContextTag(token.name())) {
1018             m_tree.openElements()->popUntilTableRowScopeMarker();
1019             m_tree.insertElement(token);
1020             m_insertionMode = InCellMode;
1021             m_tree.activeFormattingElements()->appendMarker();
1022             return;
1023         }
1024         if (token.name() == trTag
1025             || isCaptionColOrColgroupTag(token.name())
1026             || isTableBodyContextTag(token.name())) {
1027             if (!processTrEndTagForInRow()) {
1028                 ASSERT(m_isParsingFragment);
1029                 return;
1030             }
1031             ASSERT(insertionMode() == InTableBodyMode);
1032             processStartTag(token);
1033             return;
1034         }
1035         processStartTagForInTable(token);
1036         break;
1037     case InCellMode:
1038         ASSERT(insertionMode() == InCellMode);
1039         if (isCaptionColOrColgroupTag(token.name())
1040             || isTableCellContextTag(token.name())
1041             || token.name() == trTag
1042             || isTableBodyContextTag(token.name())) {
1043             // FIXME: This could be more efficient.
1044             if (!m_tree.openElements()->inTableScope(tdTag) && !m_tree.openElements()->inTableScope(thTag)) {
1045                 ASSERT(m_isParsingFragment);
1046                 parseError(token);
1047                 return;
1048             }
1049             closeTheCell();
1050             processStartTag(token);
1051             return;
1052         }
1053         processStartTagForInBody(token);
1054         break;
1055     case AfterBodyMode:
1056     case AfterAfterBodyMode:
1057         ASSERT(insertionMode() == AfterBodyMode || insertionMode() == AfterAfterBodyMode);
1058         if (token.name() == htmlTag) {
1059             m_tree.insertHTMLHtmlStartTagInBody(token);
1060             return;
1061         }
1062         m_insertionMode = InBodyMode;
1063         processStartTag(token);
1064         break;
1065     case InHeadNoscriptMode:
1066         ASSERT(insertionMode() == InHeadNoscriptMode);
1067         if (token.name() == htmlTag) {
1068             m_tree.insertHTMLHtmlStartTagInBody(token);
1069             return;
1070         }
1071         if (token.name() == linkTag || token.name() == metaTag || token.name() == noframesTag || token.name() == styleTag) {
1072             bool didProcess = processStartTagForInHead(token);
1073             ASSERT_UNUSED(didProcess, didProcess);
1074             return;
1075         }
1076         if (token.name() == htmlTag || token.name() == noscriptTag) {
1077             parseError(token);
1078             return;
1079         }
1080         processDefaultForInHeadNoscriptMode(token);
1081         processToken(token);
1082         break;
1083     case InFramesetMode:
1084         ASSERT(insertionMode() == InFramesetMode);
1085         if (token.name() == htmlTag) {
1086             m_tree.insertHTMLHtmlStartTagInBody(token);
1087             return;
1088         }
1089         if (token.name() == framesetTag) {
1090             m_tree.insertElement(token);
1091             return;
1092         }
1093         if (token.name() == frameTag) {
1094             m_tree.insertSelfClosingElement(token);
1095             return;
1096         }
1097         if (token.name() == noframesTag) {
1098             processStartTagForInHead(token);
1099             return;
1100         }
1101         parseError(token);
1102         break;
1103     case AfterFramesetMode:
1104     case AfterAfterFramesetMode:
1105         ASSERT(insertionMode() == AfterFramesetMode || insertionMode() == AfterAfterFramesetMode);
1106         if (token.name() == htmlTag) {
1107             m_tree.insertHTMLHtmlStartTagInBody(token);
1108             return;
1109         }
1110         if (token.name() == noframesTag) {
1111             processStartTagForInHead(token);
1112             return;
1113         }
1114         parseError(token);
1115         break;
1116     case InSelectInTableMode:
1117         ASSERT(insertionMode() == InSelectInTableMode);
1118         if (token.name() == captionTag
1119             || token.name() == tableTag
1120             || isTableBodyContextTag(token.name())
1121             || token.name() == trTag
1122             || isTableCellContextTag(token.name())) {
1123             parseError(token);
1124             AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName());
1125             processEndTag(endSelect);
1126             processStartTag(token);
1127             return;
1128         }
1129         // Fall through
1130     case InSelectMode:
1131         ASSERT(insertionMode() == InSelectMode || insertionMode() == InSelectInTableMode);
1132         if (token.name() == htmlTag) {
1133             m_tree.insertHTMLHtmlStartTagInBody(token);
1134             return;
1135         }
1136         if (token.name() == optionTag) {
1137             if (m_tree.currentElement()->hasTagName(optionTag)) {
1138                 AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName());
1139                 processEndTag(endOption);
1140             }
1141             m_tree.insertElement(token);
1142             return;
1143         }
1144         if (token.name() == optgroupTag) {
1145             if (m_tree.currentElement()->hasTagName(optionTag)) {
1146                 AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName());
1147                 processEndTag(endOption);
1148             }
1149             if (m_tree.currentElement()->hasTagName(optgroupTag)) {
1150                 AtomicHTMLToken endOptgroup(HTMLToken::EndTag, optgroupTag.localName());
1151                 processEndTag(endOptgroup);
1152             }
1153             m_tree.insertElement(token);
1154             return;
1155         }
1156         if (token.name() == selectTag) {
1157             parseError(token);
1158             AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName());
1159             processEndTag(endSelect);
1160             return;
1161         }
1162         if (token.name() == inputTag || token.name() == keygenTag || token.name() == textareaTag) {
1163             parseError(token);
1164             notImplemented(); // fragment case
1165             AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName());
1166             processEndTag(endSelect);
1167             processStartTag(token);
1168             return;
1169         }
1170         if (token.name() == scriptTag) {
1171             bool didProcess = processStartTagForInHead(token);
1172             ASSERT_UNUSED(didProcess, didProcess);
1173             return;
1174         }
1175         break;
1176     case TextMode:
1177     case InTableTextMode:
1178     case InForeignContentMode:
1179         notImplemented();
1180         break;
1181     }
1182 }
1183
1184 bool HTMLTreeBuilder::processBodyEndTagForInBody(AtomicHTMLToken& token)
1185 {
1186     ASSERT(token.type() == HTMLToken::EndTag);
1187     ASSERT(token.name() == bodyTag);
1188     if (!m_tree.openElements()->inScope(bodyTag.localName())) {
1189         parseError(token);
1190         return false;
1191     }
1192     notImplemented();
1193     m_insertionMode = AfterBodyMode;
1194     return true;
1195 }
1196
1197 void HTMLTreeBuilder::processAnyOtherEndTagForInBody(AtomicHTMLToken& token)
1198 {
1199     ASSERT(token.type() == HTMLToken::EndTag);
1200     HTMLElementStack::ElementRecord* record = m_tree.openElements()->topRecord();
1201     while (1) {
1202         Element* node = record->element();
1203         if (node->hasLocalName(token.name())) {
1204             m_tree.generateImpliedEndTags();
1205             if (!m_tree.currentElement()->hasLocalName(token.name())) {
1206                 parseError(token);
1207                 // FIXME: This is either a bug in the spec, or a bug in our
1208                 // implementation.  Filed a bug with HTML5:
1209                 // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10080
1210                 // We might have already popped the node for the token in
1211                 // generateImpliedEndTags, just abort.
1212                 if (!m_tree.openElements()->contains(node))
1213                     return;
1214             }
1215             m_tree.openElements()->popUntil(node);
1216             m_tree.openElements()->pop();
1217             return;
1218         }
1219         if (isNotFormattingAndNotPhrasing(node)) {
1220             parseError(token);
1221             return;
1222         }
1223         record = record->next();
1224     }
1225 }
1226
1227 // FIXME: This probably belongs on HTMLElementStack.
1228 HTMLElementStack::ElementRecord* HTMLTreeBuilder::furthestBlockForFormattingElement(Element* formattingElement)
1229 {
1230     HTMLElementStack::ElementRecord* furthestBlock = 0;
1231     HTMLElementStack::ElementRecord* record = m_tree.openElements()->topRecord();
1232     for (; record; record = record->next()) {
1233         if (record->element() == formattingElement)
1234             return furthestBlock;
1235         if (isNotFormattingAndNotPhrasing(record->element()))
1236             furthestBlock = record;
1237     }
1238     ASSERT_NOT_REACHED();
1239     return 0;
1240 }
1241
1242 // FIXME: This should have a whitty name.
1243 // FIXME: This must be implemented in many other places in WebCore.
1244 void HTMLTreeBuilder::reparentChildren(Element* oldParent, Element* newParent)
1245 {
1246     Node* child = oldParent->firstChild();
1247     while (child) {
1248         Node* nextChild = child->nextSibling();
1249         ExceptionCode ec;
1250         newParent->appendChild(child, ec);
1251         ASSERT(!ec);
1252         child = nextChild;
1253     }
1254 }
1255
1256 // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-inbody
1257 void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken& token)
1258 {
1259     while (1) {
1260         // 1.
1261         Element* formattingElement = m_tree.activeFormattingElements()->closestElementInScopeWithName(token.name());
1262         if (!formattingElement || !m_tree.openElements()->inScope(formattingElement)) {
1263             parseError(token);
1264             notImplemented(); // Check the stack of open elements for a more specific parse error.
1265             return;
1266         }
1267         HTMLElementStack::ElementRecord* formattingElementRecord = m_tree.openElements()->find(formattingElement);
1268         if (!formattingElementRecord) {
1269             parseError(token);
1270             m_tree.activeFormattingElements()->remove(formattingElement);
1271             return;
1272         }
1273         if (formattingElement != m_tree.currentElement())
1274             parseError(token);
1275         // 2.
1276         HTMLElementStack::ElementRecord* furthestBlock = furthestBlockForFormattingElement(formattingElement);
1277         // 3.
1278         if (!furthestBlock) {
1279             m_tree.openElements()->popUntil(formattingElement);
1280             m_tree.openElements()->pop();
1281             m_tree.activeFormattingElements()->remove(formattingElement);
1282             return;
1283         }
1284         // 4.
1285         ASSERT(furthestBlock->isAbove(formattingElementRecord));
1286         Element* commonAncestor = formattingElementRecord->next()->element();
1287         // 5.
1288         HTMLFormattingElementList::Bookmark bookmark = m_tree.activeFormattingElements()->bookmarkFor(formattingElement);
1289         // 6.
1290         HTMLElementStack::ElementRecord* node = furthestBlock;
1291         HTMLElementStack::ElementRecord* nextNode = node->next();
1292         HTMLElementStack::ElementRecord* lastNode = furthestBlock;
1293         while (1) {
1294             // 6.1
1295             node = nextNode;
1296             ASSERT(node);
1297             nextNode = node->next(); // Save node->next() for the next iteration in case node is deleted in 6.2.
1298             // 6.2
1299             if (!m_tree.activeFormattingElements()->contains(node->element())) {
1300                 m_tree.openElements()->remove(node->element());
1301                 node = 0;
1302                 continue;
1303             }
1304             // 6.3
1305             if (node == formattingElementRecord)
1306                 break;
1307             // 6.5
1308             // FIXME: We're supposed to save the original token in the entry.
1309             AtomicHTMLToken fakeToken(HTMLToken::StartTag, node->element()->localName());
1310             // Is createElement correct? (instead of insertElement)
1311             // Does this code ever leave newElement unattached?
1312             RefPtr<Element> newElement = m_tree.createElement(fakeToken);
1313             HTMLFormattingElementList::Entry* nodeEntry = m_tree.activeFormattingElements()->find(node->element());
1314             nodeEntry->replaceElement(newElement.get());
1315             node->replaceElement(newElement.release());
1316             // 6.4 -- Intentionally out of order to handle the case where node
1317             // was replaced in 6.5.
1318             // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10096
1319             if (lastNode == furthestBlock)
1320                 bookmark.moveToAfter(node->element());
1321             // 6.6
1322             // Use appendChild instead of parserAddChild to handle possible reparenting.
1323             ExceptionCode ec;
1324             node->element()->appendChild(lastNode->element(), ec);
1325             ASSERT(!ec);
1326             // 6.7
1327             lastNode = node;
1328         }
1329         // 7
1330         const AtomicString& commonAncestorTag = commonAncestor->localName();
1331         if (commonAncestorTag == tableTag
1332             || commonAncestorTag == trTag
1333             || isTableBodyContextTag(commonAncestorTag))
1334             m_tree.fosterParent(lastNode->element());
1335         else {
1336             ExceptionCode ec;
1337             commonAncestor->appendChild(lastNode->element(), ec);
1338             ASSERT(!ec);
1339         }
1340         // 8
1341         // FIXME: We're supposed to save the original token in the entry.
1342         AtomicHTMLToken fakeToken(HTMLToken::StartTag, formattingElement->localName());
1343         RefPtr<Element> newElement = m_tree.createElement(fakeToken);
1344         // 9
1345         reparentChildren(furthestBlock->element(), newElement.get());
1346         // 10
1347         furthestBlock->element()->parserAddChild(newElement);
1348         // 11
1349         m_tree.activeFormattingElements()->remove(formattingElement);
1350         m_tree.activeFormattingElements()->insertAt(newElement.get(), bookmark);
1351         // 12
1352         m_tree.openElements()->remove(formattingElement);
1353         m_tree.openElements()->insertAbove(newElement, furthestBlock);
1354     }
1355 }
1356
1357 void HTMLTreeBuilder::setInsertionModeAndEnd(InsertionMode newInsertionMode, bool foreign)
1358 {
1359     m_insertionMode = newInsertionMode;
1360     if (foreign) {
1361         m_secondaryInsertionMode = m_insertionMode;
1362         m_insertionMode = InForeignContentMode;
1363     }
1364 }
1365
1366 void HTMLTreeBuilder::resetInsertionModeAppropriately()
1367 {
1368     // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#reset-the-insertion-mode-appropriately
1369     bool last = false;
1370     bool foreign = false;
1371     HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord();
1372     while (1) {
1373         Element* node = nodeRecord->element();
1374         if (node == m_tree.openElements()->bottom()) {
1375             ASSERT(m_isParsingFragment);
1376             last = true;
1377             notImplemented(); // node = m_contextElement;
1378         }
1379         if (node->hasTagName(selectTag)) {
1380             ASSERT(m_isParsingFragment);
1381             return setInsertionModeAndEnd(InSelectMode, foreign);
1382         }
1383         if (node->hasTagName(tdTag) || node->hasTagName(thTag))
1384             return setInsertionModeAndEnd(InCellMode, foreign);
1385         if (node->hasTagName(trTag))
1386             return setInsertionModeAndEnd(InRowMode, foreign);
1387         if (isTableBodyContextTag(node->localName()))
1388             return setInsertionModeAndEnd(InTableBodyMode, foreign);
1389         if (node->hasTagName(captionTag))
1390             return setInsertionModeAndEnd(InCaptionMode, foreign);
1391         if (node->hasTagName(colgroupTag)) {
1392             ASSERT(m_isParsingFragment);
1393             return setInsertionModeAndEnd(InColumnGroupMode, foreign);
1394         }
1395         if (node->hasTagName(tableTag))
1396             return setInsertionModeAndEnd(InTableMode, foreign);
1397         if (node->hasTagName(headTag)) {
1398             ASSERT(m_isParsingFragment);
1399             return setInsertionModeAndEnd(InBodyMode, foreign);
1400         }
1401         if (node->hasTagName(bodyTag))
1402             return setInsertionModeAndEnd(InBodyMode, foreign);
1403         if (node->hasTagName(framesetTag)) {
1404             ASSERT(m_isParsingFragment);
1405             return setInsertionModeAndEnd(InFramesetMode, foreign);
1406         }
1407         if (node->hasTagName(htmlTag)) {
1408             ASSERT(m_isParsingFragment);
1409             return setInsertionModeAndEnd(BeforeHeadMode, foreign);
1410         }
1411         if (false
1412 #if ENABLE(SVG)
1413         || node->namespaceURI() == SVGNames::svgNamespaceURI
1414 #endif
1415 #if ENABLE(MATHML)
1416         || node->namespaceURI() == MathMLNames::mathMLNamespaceURI
1417 #endif
1418             )
1419             foreign = true;
1420         if (last) {
1421             ASSERT(m_isParsingFragment);
1422             return setInsertionModeAndEnd(InBodyMode, foreign);
1423         }
1424         nodeRecord = nodeRecord->next();
1425     }
1426 }
1427
1428 void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken& token)
1429 {
1430     ASSERT(token.type() == HTMLToken::EndTag);
1431     if (token.name() == bodyTag) {
1432         processBodyEndTagForInBody(token);
1433         return;
1434     }
1435     if (token.name() == htmlTag) {
1436         AtomicHTMLToken endBody(HTMLToken::EndTag, bodyTag.localName());
1437         if (processBodyEndTagForInBody(endBody))
1438             processEndTag(token);
1439         return;
1440     }
1441     if (token.name() == addressTag || token.name() == articleTag || token.name() == asideTag || token.name() == blockquoteTag || token.name() == buttonTag || token.name() == centerTag || token.name() == "details" || token.name() == dirTag || token.name() == divTag || token.name() == dlTag || token.name() == fieldsetTag || token.name() == "figure" || token.name() == footerTag || token.name() == headerTag || token.name() == hgroupTag || token.name() == listingTag || token.name() == menuTag || token.name() == navTag || token.name() == olTag || token.name() == preTag || token.name() == sectionTag || token.name() == ulTag) {
1442         if (!m_tree.openElements()->inScope(token.name())) {
1443             parseError(token);
1444             return;
1445         }
1446         m_tree.generateImpliedEndTags();
1447         if (!m_tree.currentElement()->hasLocalName(token.name()))
1448             parseError(token);
1449         m_tree.openElements()->popUntil(token.name());
1450         m_tree.openElements()->pop();
1451     }
1452     if (token.name() == formTag) {
1453         RefPtr<Element> node = m_tree.takeForm();
1454         if (!node || !m_tree.openElements()->inScope(node.get())) {
1455             parseError(token);
1456             return;
1457         }
1458         m_tree.generateImpliedEndTags();
1459         if (m_tree.currentElement() != node.get())
1460             parseError(token);
1461         m_tree.openElements()->remove(node.get());
1462     }
1463     if (token.name() == pTag) {
1464         if (!m_tree.openElements()->inScope(token.name())) {
1465             parseError(token);
1466             processFakeStartTag(pTag);
1467             ASSERT(m_tree.openElements()->inScope(token.name()));
1468             processEndTag(token);
1469             return;
1470         }
1471         m_tree.generateImpliedEndTagsWithExclusion(token.name());
1472         if (!m_tree.currentElement()->hasLocalName(token.name()))
1473             parseError(token);
1474         m_tree.openElements()->popUntil(token.name());
1475         m_tree.openElements()->pop();
1476         return;
1477     }
1478     if (token.name() == liTag) {
1479         if (!m_tree.openElements()->inListItemScope(token.name())) {
1480             parseError(token);
1481             return;
1482         }
1483         m_tree.generateImpliedEndTagsWithExclusion(token.name());
1484         if (!m_tree.currentElement()->hasLocalName(token.name()))
1485             parseError(token);
1486         m_tree.openElements()->popUntil(token.name());
1487         m_tree.openElements()->pop();
1488         return;
1489     }
1490     if (token.name() == ddTag || token.name() == dtTag) {
1491         if (!m_tree.openElements()->inScope(token.name())) {
1492             parseError(token);
1493             return;
1494         }
1495         m_tree.generateImpliedEndTagsWithExclusion(token.name());
1496         if (!m_tree.currentElement()->hasLocalName(token.name()))
1497             parseError(token);
1498         m_tree.openElements()->popUntil(token.name());
1499         m_tree.openElements()->pop();
1500         return;
1501     }
1502     if (isNumberedHeaderTag(token.name())) {
1503         if (!m_tree.openElements()->inScope(token.name())) {
1504             parseError(token);
1505             return;
1506         }
1507         m_tree.generateImpliedEndTags();
1508         if (!m_tree.currentElement()->hasLocalName(token.name()))
1509             parseError(token);
1510         m_tree.openElements()->popUntil(token.name());
1511         m_tree.openElements()->pop();
1512         return;
1513     }
1514     if (token.name() == "sarcasm") {
1515         notImplemented(); // Take a deep breath.
1516         return;
1517     }
1518     if (isFormattingTag(token.name())) {
1519         callTheAdoptionAgency(token);
1520         return;
1521     }
1522     if (token.name() == appletTag || token.name() == marqueeTag || token.name() == objectTag) {
1523         if (!m_tree.openElements()->inScope(token.name())) {
1524             parseError(token);
1525             return;
1526         }
1527         m_tree.generateImpliedEndTags();
1528         if (!m_tree.currentElement()->hasLocalName(token.name()))
1529             parseError(token);
1530         m_tree.openElements()->popUntil(token.name());
1531         m_tree.openElements()->pop();
1532         m_tree.activeFormattingElements()->clearToLastMarker();
1533         return;
1534     }
1535     if (token.name() == brTag) {
1536         parseError(token);
1537         processFakeStartTag(brTag);
1538         return;
1539     }
1540     processAnyOtherEndTagForInBody(token);
1541 }
1542
1543 bool HTMLTreeBuilder::processCaptionEndTagForInCaption()
1544 {
1545     if (!m_tree.openElements()->inTableScope(captionTag.localName())) {
1546         ASSERT(m_isParsingFragment);
1547         // FIXME: parse error
1548         return false;
1549     }
1550     m_tree.generateImpliedEndTags();
1551     // FIXME: parse error if (!m_tree.currentElement()->hasTagName(captionTag))
1552     m_tree.openElements()->popUntil(captionTag.localName());
1553     m_tree.openElements()->pop();
1554     m_tree.activeFormattingElements()->clearToLastMarker();
1555     m_insertionMode = InTableMode;
1556     return true;
1557 }
1558
1559 bool HTMLTreeBuilder::processTrEndTagForInRow()
1560 {
1561     if (!m_tree.openElements()->inTableScope(trTag.localName())) {
1562         ASSERT(m_isParsingFragment);
1563         // FIXME: parse error
1564         return false;
1565     }
1566     m_tree.openElements()->popUntilTableRowScopeMarker();
1567     ASSERT(m_tree.currentElement()->hasTagName(trTag));
1568     m_tree.openElements()->pop();
1569     m_insertionMode = InTableBodyMode;
1570     return true;
1571 }
1572
1573 void HTMLTreeBuilder::processEndTagForInTable(AtomicHTMLToken& token)
1574 {
1575     ASSERT(token.type() == HTMLToken::EndTag);
1576     if (token.name() == tableTag) {
1577         if (!m_tree.openElements()->inTableScope(token.name())) {
1578             ASSERT(m_isParsingFragment);
1579             parseError(token);
1580             return;
1581         }
1582         m_tree.openElements()->popUntil(tableTag.localName());
1583         m_tree.openElements()->pop();
1584         resetInsertionModeAppropriately();
1585         return;
1586     }
1587     if (token.name() == bodyTag
1588         || isCaptionColOrColgroupTag(token.name())
1589         || token.name() == htmlTag
1590         || isTableBodyContextTag(token.name())
1591         || isTableCellContextTag(token.name())
1592         || token.name() == trTag) {
1593         parseError(token);
1594         return;
1595     }
1596     // Is this redirection necessary here?
1597     HTMLConstructionSite::RedirectToFosterParentGuard redirecter(m_tree, requiresRedirectToFosterParent(m_tree.currentElement()));
1598     processEndTagForInBody(token);
1599 }
1600
1601 void HTMLTreeBuilder::processEndTag(AtomicHTMLToken& token)
1602 {
1603     ASSERT(token.type() == HTMLToken::EndTag);
1604     switch (insertionMode()) {
1605     case InitialMode:
1606         ASSERT(insertionMode() == InitialMode);
1607         processDefaultForInitialMode(token);
1608         // Fall through.
1609     case BeforeHTMLMode:
1610         ASSERT(insertionMode() == BeforeHTMLMode);
1611         if (token.name() != headTag && token.name() != bodyTag && token.name() != htmlTag && token.name() != brTag) {
1612             parseError(token);
1613             return;
1614         }
1615         processDefaultForBeforeHTMLMode(token);
1616         // Fall through.
1617     case BeforeHeadMode:
1618         ASSERT(insertionMode() == BeforeHeadMode);
1619         if (token.name() != headTag && token.name() != bodyTag && token.name() != brTag) {
1620             parseError(token);
1621             return;
1622         }
1623         processDefaultForBeforeHeadMode(token);
1624         // Fall through.
1625     case InHeadMode:
1626         ASSERT(insertionMode() == InHeadMode);
1627         if (token.name() == headTag) {
1628             m_tree.openElements()->popHTMLHeadElement();
1629             setInsertionMode(AfterHeadMode);
1630             return;
1631         }
1632         if (token.name() != bodyTag && token.name() != htmlTag && token.name() != brTag) {
1633             parseError(token);
1634             return;
1635         }
1636         processDefaultForInHeadMode(token);
1637         // Fall through.
1638     case AfterHeadMode:
1639         ASSERT(insertionMode() == AfterHeadMode);
1640         if (token.name() != bodyTag && token.name() != htmlTag && token.name() != brTag) {
1641             parseError(token);
1642             return;
1643         }
1644         processDefaultForAfterHeadMode(token);
1645         // Fall through
1646     case InBodyMode:
1647         ASSERT(insertionMode() == InBodyMode);
1648         processEndTagForInBody(token);
1649         break;
1650     case InTableMode:
1651         ASSERT(insertionMode() == InTableMode);
1652         processEndTagForInTable(token);
1653         break;
1654     case InCaptionMode:
1655         ASSERT(insertionMode() == InCaptionMode);
1656         if (token.name() == captionTag) {
1657             processCaptionEndTagForInCaption();
1658             return;
1659         }
1660         if (token.name() == tableTag) {
1661             parseError(token);
1662             if (!processCaptionEndTagForInCaption()) {
1663                 ASSERT(m_isParsingFragment);
1664                 return;
1665             }
1666             processEndTag(token);
1667             return;
1668         }
1669         if (token.name() == bodyTag
1670             || token.name() == colTag
1671             || token.name() == colgroupTag
1672             || token.name() == htmlTag
1673             || isTableBodyContextTag(token.name())
1674             || isTableCellContextTag(token.name())
1675             || token.name() == trTag) {
1676             parseError(token);
1677             return;
1678         }
1679         processEndTagForInBody(token);
1680         break;
1681     case InColumnGroupMode:
1682         ASSERT(insertionMode() == InColumnGroupMode);
1683         if (token.name() == colgroupTag) {
1684             processColgroupEndTagForInColumnGroup();
1685             return;
1686         }
1687         if (token.name() == colTag) {
1688             parseError(token);
1689             return;
1690         }
1691         if (!processColgroupEndTagForInColumnGroup()) {
1692             ASSERT(m_isParsingFragment);
1693             return;
1694         }
1695         processEndTag(token);
1696         break;
1697     case InRowMode:
1698         ASSERT(insertionMode() == InRowMode);
1699         if (token.name() == trTag) {
1700             processTrEndTagForInRow();
1701             return;
1702         }
1703         if (token.name() == tableTag) {
1704             if (!processTrEndTagForInRow()) {
1705                 ASSERT(m_isParsingFragment);
1706                 return;
1707             }
1708             ASSERT(insertionMode() == InTableBodyMode);
1709             processEndTag(token);
1710             return;
1711         }
1712         if (isTableBodyContextTag(token.name())) {
1713             if (!m_tree.openElements()->inTableScope(token.name())) {
1714                 parseError(token);
1715                 return;
1716             }
1717             processFakeEndTag(trTag);
1718             ASSERT(insertionMode() == InTableBodyMode);
1719             processEndTag(token);
1720             return;
1721         }
1722         if (token.name() == bodyTag
1723             || isCaptionColOrColgroupTag(token.name())
1724             || token.name() == htmlTag
1725             || isTableCellContextTag(token.name())) {
1726             parseError(token);
1727             return;
1728         }
1729         processEndTagForInTable(token);
1730         break;
1731     case InCellMode:
1732         ASSERT(insertionMode() == InCellMode);
1733         if (isTableCellContextTag(token.name())) {
1734             if (!m_tree.openElements()->inTableScope(token.name())) {
1735                 parseError(token);
1736                 return;
1737             }
1738             m_tree.generateImpliedEndTags();
1739             if (!m_tree.currentElement()->hasLocalName(token.name()))
1740                 parseError(token);
1741             m_tree.openElements()->popUntil(token.name());
1742             m_tree.openElements()->pop();
1743             m_tree.activeFormattingElements()->clearToLastMarker();
1744             m_insertionMode = InRowMode;
1745             ASSERT(m_tree.currentElement()->hasTagName(trTag));
1746             return;
1747         }
1748         if (token.name() == bodyTag
1749             || isCaptionColOrColgroupTag(token.name())
1750             || token.name() == htmlTag) {
1751             parseError(token);
1752             return;
1753         }
1754         if (token.name() == tableTag || token.name() == trTag || isTableBodyContextTag(token.name())) {
1755             if (!m_tree.openElements()->inTableScope(token.name())) {
1756                 ASSERT(m_isParsingFragment);
1757                 // FIXME: It is unclear what the exact ASSERT should be.
1758                 // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10098
1759                 parseError(token);
1760                 return;
1761             }
1762             closeTheCell();
1763             processEndTag(token);
1764             return;
1765         }
1766         processEndTagForInBody(token);
1767         break;
1768     case InTableBodyMode:
1769         ASSERT(insertionMode() == InTableBodyMode);
1770         if (isTableBodyContextTag(token.name())) {
1771             if (!m_tree.openElements()->inTableScope(token.name())) {
1772                 parseError(token);
1773                 return;
1774             }
1775             m_tree.openElements()->popUntilTableBodyScopeMarker();
1776             m_tree.openElements()->pop();
1777             m_insertionMode = InTableMode;
1778             return;
1779         }
1780         if (token.name() == tableTag) {
1781             // FIXME: This is slow.
1782             if (!m_tree.openElements()->inTableScope(tbodyTag.localName()) && !m_tree.openElements()->inTableScope(theadTag.localName()) && !m_tree.openElements()->inTableScope(tfootTag.localName())) {
1783                 ASSERT(m_isParsingFragment);
1784                 parseError(token);
1785                 return;
1786             }
1787             m_tree.openElements()->popUntilTableBodyScopeMarker();
1788             ASSERT(isTableBodyContextTag(m_tree.currentElement()->localName()));
1789             processFakeEndTag(m_tree.currentElement()->tagQName());
1790             processEndTag(token);
1791             return;
1792         }
1793         if (token.name() == bodyTag
1794             || isCaptionColOrColgroupTag(token.name())
1795             || token.name() == htmlTag
1796             || isTableCellContextTag(token.name())
1797             || token.name() == trTag) {
1798             parseError(token);
1799             return;
1800         }
1801         processEndTagForInTable(token);
1802         break;
1803     case AfterBodyMode:
1804         ASSERT(insertionMode() == AfterBodyMode);
1805         if (token.name() == htmlTag) {
1806             if (m_isParsingFragment) {
1807                 parseError(token);
1808                 return;
1809             }
1810             m_insertionMode = AfterAfterBodyMode;
1811             return;
1812         }
1813         // Fall through.
1814     case AfterAfterBodyMode:
1815         ASSERT(insertionMode() == AfterBodyMode || insertionMode() == AfterAfterBodyMode);
1816         parseError(token);
1817         m_insertionMode = InBodyMode;
1818         processEndTag(token);
1819         break;
1820     case InHeadNoscriptMode:
1821         ASSERT(insertionMode() == InHeadNoscriptMode);
1822         if (token.name() == noscriptTag) {
1823             ASSERT(m_tree.currentElement()->hasTagName(noscriptTag));
1824             m_tree.openElements()->pop();
1825             ASSERT(m_tree.currentElement()->hasTagName(headTag));
1826             setInsertionMode(InHeadMode);
1827             return;
1828         }
1829         if (token.name() != brTag) {
1830             parseError(token);
1831             return;
1832         }
1833         processDefaultForInHeadNoscriptMode(token);
1834         processToken(token);
1835         break;
1836     case TextMode:
1837         if (token.name() == scriptTag) {
1838             // Pause ourselves so that parsing stops until the script can be processed by the caller.
1839             m_isPaused = true;
1840             ASSERT(m_tree.currentElement()->hasTagName(scriptTag));
1841             m_scriptToProcess = m_tree.currentElement();
1842             m_tree.openElements()->pop();
1843             m_insertionMode = m_originalInsertionMode;
1844             return;
1845         }
1846         m_tree.openElements()->pop();
1847         m_insertionMode = m_originalInsertionMode;
1848         break;
1849     case InFramesetMode:
1850         ASSERT(insertionMode() == InFramesetMode);
1851         if (token.name() == framesetTag) {
1852             if (m_tree.currentElement() == m_tree.openElements()->htmlElement()) {
1853                 parseError(token);
1854                 return;
1855             }
1856             m_tree.openElements()->pop();
1857             if (!m_isParsingFragment && !m_tree.currentElement()->hasTagName(framesetTag))
1858                 m_insertionMode = AfterFramesetMode;
1859             return;
1860         }
1861         break;
1862     case AfterFramesetMode:
1863         ASSERT(insertionMode() == AfterFramesetMode);
1864         if (token.name() == htmlTag) {
1865             m_insertionMode = AfterAfterFramesetMode;
1866             return;
1867         }
1868         // Fall through.
1869     case AfterAfterFramesetMode:
1870         ASSERT(insertionMode() == AfterFramesetMode || insertionMode() == AfterAfterFramesetMode);
1871         parseError(token);
1872         break;
1873     case InSelectInTableMode:
1874         ASSERT(insertionMode() == InSelectInTableMode);
1875         if (token.name() == captionTag
1876             || token.name() == tableTag
1877             || isTableBodyContextTag(token.name())
1878             || token.name() == trTag
1879             || isTableCellContextTag(token.name())) {
1880             parseError(token);
1881             if (m_tree.openElements()->inTableScope(token.name())) {
1882                 AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName());
1883                 processEndTag(endSelect);
1884                 processEndTag(token);
1885             }
1886             return;
1887         }
1888         // Fall through.
1889     case InSelectMode:
1890         ASSERT(insertionMode() == InSelectMode || insertionMode() == InSelectInTableMode);
1891         if (token.name() == optgroupTag) {
1892             if (m_tree.currentElement()->hasTagName(optionTag) && m_tree.oneBelowTop()->hasTagName(optgroupTag))
1893                 processFakeEndTag(optionTag);
1894             if (m_tree.currentElement()->hasTagName(optgroupTag)) {
1895                 m_tree.openElements()->pop();
1896                 return;
1897             }
1898             parseError(token);
1899             return;
1900         }
1901         if (token.name() == optionTag) {
1902             if (m_tree.currentElement()->hasTagName(optionTag)) {
1903                 m_tree.openElements()->pop();
1904                 return;
1905             }
1906             parseError(token);
1907             return;
1908         }
1909         if (token.name() == selectTag) {
1910             notImplemented(); // fragment case
1911             m_tree.openElements()->popUntil(selectTag.localName());
1912             m_tree.openElements()->pop();
1913             resetInsertionModeAppropriately();
1914             return;
1915         }
1916         break;
1917     case InTableTextMode:
1918     case InForeignContentMode:
1919         notImplemented();
1920         break;
1921     }
1922 }
1923
1924 void HTMLTreeBuilder::processComment(AtomicHTMLToken& token)
1925 {
1926     ASSERT(token.type() == HTMLToken::Comment);
1927     if (m_insertionMode == InitialMode || m_insertionMode == BeforeHTMLMode || m_insertionMode == AfterAfterBodyMode || m_insertionMode == AfterAfterFramesetMode) {
1928         m_tree.insertCommentOnDocument(token);
1929         return;
1930     }
1931     if (m_insertionMode == AfterBodyMode) {
1932         m_tree.insertCommentOnHTMLHtmlElement(token);
1933         return;
1934     }
1935     m_tree.insertComment(token);
1936 }
1937
1938 void HTMLTreeBuilder::processCharacter(AtomicHTMLToken& token)
1939 {
1940     ASSERT(token.type() == HTMLToken::Character);
1941     // FIXME: We need to figure out how to handle each character individually.
1942     switch (insertionMode()) {
1943     case InitialMode:
1944         ASSERT(insertionMode() == InitialMode);
1945         notImplemented();
1946         processDefaultForInitialMode(token);
1947         // Fall through.
1948     case BeforeHTMLMode:
1949         ASSERT(insertionMode() == BeforeHTMLMode);
1950         notImplemented();
1951         processDefaultForBeforeHTMLMode(token);
1952         // Fall through.
1953     case BeforeHeadMode:
1954         ASSERT(insertionMode() == BeforeHeadMode);
1955         notImplemented();
1956         processDefaultForBeforeHeadMode(token);
1957         // Fall through.
1958     case InHeadMode:
1959         ASSERT(insertionMode() == InHeadMode);
1960         notImplemented();
1961         processDefaultForInHeadMode(token);
1962         // Fall through.
1963     case AfterHeadMode:
1964         ASSERT(insertionMode() == AfterHeadMode);
1965         notImplemented();
1966         processDefaultForAfterHeadMode(token);
1967         // Fall through
1968     case InBodyMode:
1969     case InCaptionMode:
1970     case InCellMode:
1971         ASSERT(insertionMode() == InBodyMode || insertionMode() == InCaptionMode || insertionMode() == InCellMode);
1972         notImplemented();
1973         m_tree.insertTextNode(token);
1974         break;
1975     case InTableMode:
1976     case InTableBodyMode:
1977     case InRowMode:
1978         ASSERT(insertionMode() == InTableMode || insertionMode() == InTableBodyMode || insertionMode() == InRowMode);
1979         notImplemented(); // Crazy pending characters.
1980         m_tree.insertTextNode(token);
1981         break;
1982     case InColumnGroupMode:
1983         ASSERT(insertionMode() == InColumnGroupMode);
1984         notImplemented();
1985         break;
1986     case AfterBodyMode:
1987     case AfterAfterBodyMode:
1988         ASSERT(insertionMode() == AfterBodyMode || insertionMode() == AfterAfterBodyMode);
1989         parseError(token);
1990         m_insertionMode = InBodyMode;
1991         processCharacter(token);
1992         break;
1993     case TextMode:
1994         notImplemented();
1995         m_tree.insertTextNode(token);
1996         break;
1997     case InHeadNoscriptMode:
1998         ASSERT(insertionMode() == InHeadNoscriptMode);
1999         processDefaultForInHeadNoscriptMode(token);
2000         processToken(token);
2001         break;
2002     case InFramesetMode:
2003     case AfterFramesetMode:
2004     case AfterAfterFramesetMode:
2005         ASSERT(insertionMode() == InFramesetMode || insertionMode() == AfterFramesetMode || insertionMode() == AfterAfterFramesetMode);
2006         parseError(token);
2007         break;
2008     case InSelectInTableMode:
2009     case InSelectMode:
2010         ASSERT(insertionMode() == InSelectMode || insertionMode() == InSelectInTableMode);
2011         m_tree.insertTextNode(token);
2012         break;
2013     case InTableTextMode:
2014     case InForeignContentMode:
2015         notImplemented();
2016         break;
2017     }
2018 }
2019
2020 void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken& token)
2021 {
2022     ASSERT(token.type() == HTMLToken::EndOfFile);
2023     switch (insertionMode()) {
2024     case InitialMode:
2025         ASSERT(insertionMode() == InitialMode);
2026         processDefaultForInitialMode(token);
2027         // Fall through.
2028     case BeforeHTMLMode:
2029         ASSERT(insertionMode() == BeforeHTMLMode);
2030         processDefaultForBeforeHTMLMode(token);
2031         // Fall through.
2032     case BeforeHeadMode:
2033         ASSERT(insertionMode() == BeforeHeadMode);
2034         processDefaultForBeforeHeadMode(token);
2035         // Fall through.
2036     case InHeadMode:
2037         ASSERT(insertionMode() == InHeadMode);
2038         processDefaultForInHeadMode(token);
2039         // Fall through.
2040     case AfterHeadMode:
2041         ASSERT(insertionMode() == AfterHeadMode);
2042         processDefaultForAfterHeadMode(token);
2043         // Fall through
2044     case InBodyMode:
2045     case InCellMode:
2046         ASSERT(insertionMode() == InBodyMode || insertionMode() == InCellMode);
2047         notImplemented();
2048         break;
2049     case AfterBodyMode:
2050     case AfterAfterBodyMode:
2051         ASSERT(insertionMode() == AfterBodyMode || insertionMode() == AfterAfterBodyMode);
2052         notImplemented();
2053         break;
2054     case InHeadNoscriptMode:
2055         ASSERT(insertionMode() == InHeadNoscriptMode);
2056         processDefaultForInHeadNoscriptMode(token);
2057         processToken(token);
2058         break;
2059     case AfterFramesetMode:
2060     case AfterAfterFramesetMode:
2061         ASSERT(insertionMode() == AfterFramesetMode || insertionMode() == AfterAfterFramesetMode);
2062         break;
2063     case InFramesetMode:
2064     case InTableMode:
2065     case InTableBodyMode:
2066     case InSelectInTableMode:
2067     case InSelectMode:
2068         ASSERT(insertionMode() == InSelectMode || insertionMode() == InSelectInTableMode || insertionMode() == InTableMode || insertionMode() == InFramesetMode || insertionMode() == InTableBodyMode);
2069         if (m_tree.currentElement() != m_tree.openElements()->htmlElement())
2070             parseError(token);
2071         break;
2072     case InColumnGroupMode:
2073         if (m_tree.currentElement() == m_tree.openElements()->htmlElement()) {
2074             ASSERT(m_isParsingFragment);
2075             return;
2076         }
2077         if (!processColgroupEndTagForInColumnGroup()) {
2078             ASSERT(m_isParsingFragment);
2079             return;
2080         }
2081         processEndOfFile(token);
2082         break;
2083     case TextMode:
2084     case InTableTextMode:
2085     case InCaptionMode:
2086     case InRowMode:
2087     case InForeignContentMode:
2088         notImplemented();
2089         break;
2090     }
2091 }
2092
2093 void HTMLTreeBuilder::processDefaultForInitialMode(AtomicHTMLToken& token)
2094 {
2095     notImplemented();
2096     parseError(token);
2097     setInsertionMode(BeforeHTMLMode);
2098 }
2099
2100 void HTMLTreeBuilder::processDefaultForBeforeHTMLMode(AtomicHTMLToken&)
2101 {
2102     AtomicHTMLToken startHTML(HTMLToken::StartTag, htmlTag.localName());
2103     m_tree.insertHTMLHtmlStartTagBeforeHTML(startHTML);
2104     setInsertionMode(BeforeHeadMode);
2105 }
2106
2107 void HTMLTreeBuilder::processDefaultForBeforeHeadMode(AtomicHTMLToken&)
2108 {
2109     AtomicHTMLToken startHead(HTMLToken::StartTag, headTag.localName());
2110     processStartTag(startHead);
2111 }
2112
2113 void HTMLTreeBuilder::processDefaultForInHeadMode(AtomicHTMLToken&)
2114 {
2115     AtomicHTMLToken endHead(HTMLToken::EndTag, headTag.localName());
2116     processEndTag(endHead);
2117 }
2118
2119 void HTMLTreeBuilder::processDefaultForInHeadNoscriptMode(AtomicHTMLToken&)
2120 {
2121     AtomicHTMLToken endNoscript(HTMLToken::EndTag, noscriptTag.localName());
2122     processEndTag(endNoscript);
2123 }
2124
2125 void HTMLTreeBuilder::processDefaultForAfterHeadMode(AtomicHTMLToken&)
2126 {
2127     AtomicHTMLToken startBody(HTMLToken::StartTag, bodyTag.localName());
2128     processStartTag(startBody);
2129     m_framesetOk = true;
2130 }
2131
2132 bool HTMLTreeBuilder::processStartTagForInHead(AtomicHTMLToken& token)
2133 {
2134     ASSERT(token.type() == HTMLToken::StartTag);
2135     if (token.name() == htmlTag) {
2136         m_tree.insertHTMLHtmlStartTagInBody(token);
2137         return true;
2138     }
2139     // FIXME: Atomize "command".
2140     if (token.name() == baseTag || token.name() == "command" || token.name() == linkTag || token.name() == metaTag) {
2141         m_tree.insertSelfClosingElement(token);
2142         // Note: The custom processing for the <meta> tag is done in HTMLMetaElement::process().
2143         return true;
2144     }
2145     if (token.name() == titleTag) {
2146         processGenericRCDATAStartTag(token);
2147         return true;
2148     }
2149     if (token.name() == noscriptTag) {
2150         if (isScriptingFlagEnabled(m_document->frame())) {
2151             processGenericRawTextStartTag(token);
2152             return true;
2153         }
2154         m_tree.insertElement(token);
2155         setInsertionMode(InHeadNoscriptMode);
2156         return true;
2157     }
2158     if (token.name() == noframesTag || token.name() == styleTag) {
2159         processGenericRawTextStartTag(token);
2160         return true;
2161     }
2162     if (token.name() == scriptTag) {
2163         processScriptStartTag(token);
2164         return true;
2165     }
2166     if (token.name() == headTag) {
2167         parseError(token);
2168         return true;
2169     }
2170     return false;
2171 }
2172
2173 void HTMLTreeBuilder::processGenericRCDATAStartTag(AtomicHTMLToken& token)
2174 {
2175     ASSERT(token.type() == HTMLToken::StartTag);
2176     m_tree.insertElement(token);
2177     m_tokenizer->setState(HTMLTokenizer::RCDATAState);
2178     m_originalInsertionMode = m_insertionMode;
2179     m_insertionMode = TextMode;
2180 }
2181
2182 void HTMLTreeBuilder::processGenericRawTextStartTag(AtomicHTMLToken& token)
2183 {
2184     ASSERT(token.type() == HTMLToken::StartTag);
2185     m_tree.insertElement(token);
2186     m_tokenizer->setState(HTMLTokenizer::RAWTEXTState);
2187     m_originalInsertionMode = m_insertionMode;
2188     m_insertionMode = TextMode;
2189 }
2190
2191 void HTMLTreeBuilder::processScriptStartTag(AtomicHTMLToken& token)
2192 {
2193     ASSERT(token.type() == HTMLToken::StartTag);
2194     m_tree.insertScriptElement(token);
2195     m_tokenizer->setState(HTMLTokenizer::ScriptDataState);
2196     m_originalInsertionMode = m_insertionMode;
2197     m_insertionMode = TextMode;
2198 }
2199
2200 void HTMLTreeBuilder::finished()
2201 {
2202     // We should call m_document->finishedParsing() here, except
2203     // m_legacyTreeBuilder->finished() does it for us.
2204     if (m_legacyTreeBuilder) {
2205         m_legacyTreeBuilder->finished();
2206         return;
2207     }
2208
2209     // Warning, this may delete the parser, so don't try to do anything else after this.
2210     if (!m_isParsingFragment)
2211         m_document->finishedParsing();
2212 }
2213
2214 bool HTMLTreeBuilder::isScriptingFlagEnabled(Frame* frame)
2215 {
2216     if (!frame)
2217         return false;
2218     if (ScriptController* scriptController = frame->script())
2219         return scriptController->canExecuteScripts(NotAboutToExecuteScript);
2220     return false;
2221 }
2222
2223 }