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