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