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