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