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