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