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