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