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