2010-07-03 Adam Barth <abarth@webkit.org>
[WebKit-https.git] / WebCore / html / HTMLTreeBuilder.cpp
1 /*
2  * Copyright (C) 2010 Google, Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GOOGLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "HTMLTreeBuilder.h"
28
29 #include "Comment.h"
30 #include "DocumentFragment.h"
31 #include "DocumentType.h"
32 #include "Element.h"
33 #include "Frame.h"
34 #include "HTMLElementFactory.h"
35 #include "HTMLScriptElement.h"
36 #include "HTMLTokenizer.h"
37 #include "HTMLToken.h"
38 #include "HTMLDocument.h"
39 #include "HTMLHtmlElement.h"
40 #include "LegacyHTMLDocumentParser.h"
41 #include "HTMLNames.h"
42 #include "LegacyHTMLTreeBuilder.h"
43 #include "NotImplemented.h"
44 #include "Settings.h"
45 #include "ScriptController.h"
46 #include "Text.h"
47 #include <wtf/UnusedParam.h>
48
49 namespace WebCore {
50
51 using namespace HTMLNames;
52
53 static const int uninitializedLineNumberValue = -1;
54
55 namespace {
56
57 inline bool isTreeBuilderWhiteSpace(UChar cc)
58 {
59     return cc == '\t' || cc == '\x0A' || cc == '\x0C' || cc == '\x0D' || cc == ' ';
60 }
61
62 bool shouldUseLegacyTreeBuilder(Document* document)
63 {
64     return !document->settings() || !document->settings()->html5TreeBuilderEnabled();
65 }
66
67 } // namespace
68
69 HTMLTreeBuilder::HTMLTreeBuilder(HTMLTokenizer* tokenizer, HTMLDocument* document, bool reportErrors)
70     : m_framesetOk(true)
71     , m_document(document)
72     , m_reportErrors(reportErrors)
73     , m_isPaused(false)
74     , m_insertionMode(InitialMode)
75     , m_originalInsertionMode(InitialMode)
76     , m_tokenizer(tokenizer)
77     , m_legacyTreeBuilder(shouldUseLegacyTreeBuilder(document) ? new LegacyHTMLTreeBuilder(document, reportErrors) : 0)
78     , m_lastScriptElementStartLine(uninitializedLineNumberValue)
79     , m_scriptToProcessStartLine(uninitializedLineNumberValue)
80     , m_fragmentScriptingPermission(FragmentScriptingAllowed)
81     , m_isParsingFragment(false)
82 {
83 }
84
85 // FIXME: Member variables should be grouped into self-initializing structs to
86 // minimize code duplication between these constructors.
87 HTMLTreeBuilder::HTMLTreeBuilder(HTMLTokenizer* tokenizer, DocumentFragment* fragment, FragmentScriptingPermission scriptingPermission)
88     : m_framesetOk(true)
89     , m_document(fragment->document())
90     , m_reportErrors(false) // FIXME: Why not report errors in fragments?
91     , m_isPaused(false)
92     , m_insertionMode(InitialMode)
93     , m_originalInsertionMode(InitialMode)
94     , m_tokenizer(tokenizer)
95     , m_legacyTreeBuilder(new LegacyHTMLTreeBuilder(fragment, scriptingPermission))
96     , m_lastScriptElementStartLine(uninitializedLineNumberValue)
97     , m_scriptToProcessStartLine(uninitializedLineNumberValue)
98     , m_fragmentScriptingPermission(scriptingPermission)
99     , m_isParsingFragment(true)
100 {
101 }
102
103 HTMLTreeBuilder::~HTMLTreeBuilder()
104 {
105 }
106
107 static void convertToOldStyle(const AtomicHTMLToken& token, Token& oldStyleToken)
108 {
109     switch (token.type()) {
110     case HTMLToken::Uninitialized:
111     case HTMLToken::DOCTYPE:
112         ASSERT_NOT_REACHED();
113         break;
114     case HTMLToken::EndOfFile:
115         ASSERT_NOT_REACHED();
116         notImplemented();
117         break;
118     case HTMLToken::StartTag:
119     case HTMLToken::EndTag: {
120         oldStyleToken.beginTag = (token.type() == HTMLToken::StartTag);
121         oldStyleToken.selfClosingTag = token.selfClosing();
122         oldStyleToken.tagName = token.name();
123         oldStyleToken.attrs = token.attributes();
124         break;
125     }
126     case HTMLToken::Comment:
127         oldStyleToken.tagName = commentAtom;
128         oldStyleToken.text = token.comment().impl();
129         break;
130     case HTMLToken::Character:
131         oldStyleToken.tagName = textAtom;
132         oldStyleToken.text = token.characters().impl();
133         break;
134     }
135 }
136
137 void HTMLTreeBuilder::handleScriptStartTag()
138 {
139     notImplemented(); // The HTML frgment case?
140     m_tokenizer->setState(HTMLTokenizer::ScriptDataState);
141     notImplemented(); // Save insertion mode.
142 }
143
144 void HTMLTreeBuilder::handleScriptEndTag(Element* scriptElement, int scriptStartLine)
145 {
146     ASSERT(!m_scriptToProcess); // Caller never called takeScriptToProcess!
147     ASSERT(m_scriptToProcessStartLine == uninitializedLineNumberValue); // Caller never called takeScriptToProcess!
148     notImplemented(); // Save insertion mode and insertion point?
149
150     // Pause ourselves so that parsing stops until the script can be processed by the caller.
151     m_isPaused = true;
152     m_scriptToProcess = scriptElement;
153     // Lexer line numbers are 0-based, ScriptSourceCode expects 1-based lines,
154     // so we convert here before passing the line number off to HTMLScriptRunner.
155     m_scriptToProcessStartLine = scriptStartLine + 1;
156 }
157
158 PassRefPtr<Element> HTMLTreeBuilder::takeScriptToProcess(int& scriptStartLine)
159 {
160     // Unpause ourselves, callers may pause us again when processing the script.
161     // The HTML5 spec is written as though scripts are executed inside the tree
162     // builder.  We pause the parser to exit the tree builder, and then resume
163     // before running scripts.
164     m_isPaused = false;
165     scriptStartLine = m_scriptToProcessStartLine;
166     m_scriptToProcessStartLine = uninitializedLineNumberValue;
167     return m_scriptToProcess.release();
168 }
169
170 HTMLTokenizer::State HTMLTreeBuilder::adjustedLexerState(HTMLTokenizer::State state, const AtomicString& tagName, Frame* frame)
171 {
172     if (tagName == textareaTag || tagName == titleTag)
173         return HTMLTokenizer::RCDATAState;
174
175     if (tagName == styleTag || tagName == iframeTag || tagName == xmpTag || tagName == noembedTag
176         || tagName == noframesTag || (tagName == noscriptTag && isScriptingFlagEnabled(frame)))
177         return HTMLTokenizer::RAWTEXTState;
178
179     if (tagName == plaintextTag)
180         return HTMLTokenizer::PLAINTEXTState;
181
182     return state;
183 }
184
185 void HTMLTreeBuilder::passTokenToLegacyParser(HTMLToken& token)
186 {
187     if (token.type() == HTMLToken::DOCTYPE) {
188         DoctypeToken doctypeToken;
189         doctypeToken.m_name.append(token.name().data(), token.name().size());
190         doctypeToken.m_publicID = token.publicIdentifier();
191         doctypeToken.m_systemID = token.systemIdentifier();
192         doctypeToken.m_forceQuirks = token.forceQuirks();
193
194         m_legacyTreeBuilder->parseDoctypeToken(&doctypeToken);
195         return;
196     }
197
198     if (token.type() == HTMLToken::EndOfFile)
199         return;
200
201     // For now, we translate into an old-style token for testing.
202     Token oldStyleToken;
203     AtomicHTMLToken atomicToken(token);
204     convertToOldStyle(atomicToken, oldStyleToken);
205
206     RefPtr<Node> result =  m_legacyTreeBuilder->parseToken(&oldStyleToken);
207     if (token.type() == HTMLToken::StartTag) {
208         // This work is supposed to be done by the parser, but
209         // when using the old parser for we have to do this manually.
210         if (oldStyleToken.tagName == scriptTag) {
211             handleScriptStartTag();
212             m_lastScriptElement = static_pointer_cast<Element>(result);
213             m_lastScriptElementStartLine = m_tokenizer->lineNumber();
214         } else if (oldStyleToken.tagName == preTag || oldStyleToken.tagName == listingTag)
215             m_tokenizer->skipLeadingNewLineForListing();
216         else
217             m_tokenizer->setState(adjustedLexerState(m_tokenizer->state(), oldStyleToken.tagName, m_document->frame()));
218     } else if (token.type() == HTMLToken::EndTag) {
219         if (oldStyleToken.tagName == scriptTag) {
220             if (m_lastScriptElement) {
221                 ASSERT(m_lastScriptElementStartLine != uninitializedLineNumberValue);
222                 if (m_fragmentScriptingPermission == FragmentScriptingNotAllowed) {
223                     // FIXME: This is a horrible hack for platform/Pasteboard.
224                     // Clear the <script> tag when using the Parser to create
225                     // a DocumentFragment for pasting so that javascript content
226                     // does not show up in pasted HTML.
227                     m_lastScriptElement->removeChildren();
228                 } else if (insertionMode() != AfterFramesetMode)
229                     handleScriptEndTag(m_lastScriptElement.get(), m_lastScriptElementStartLine);
230                 m_lastScriptElement = 0;
231                 m_lastScriptElementStartLine = uninitializedLineNumberValue;
232             }
233         } else if (oldStyleToken.tagName == framesetTag)
234             setInsertionMode(AfterFramesetMode);
235     }
236 }
237
238 void HTMLTreeBuilder::constructTreeFromToken(HTMLToken& rawToken)
239 {
240     if (m_legacyTreeBuilder) {
241         passTokenToLegacyParser(rawToken);
242         return;
243     }
244
245     AtomicHTMLToken token(rawToken);
246     processToken(token);
247 }
248
249 void HTMLTreeBuilder::processToken(AtomicHTMLToken& token)
250 {
251     switch (token.type()) {
252     case HTMLToken::Uninitialized:
253         ASSERT_NOT_REACHED();
254         break;
255     case HTMLToken::DOCTYPE:
256         processDoctypeToken(token);
257         break;
258     case HTMLToken::StartTag:
259         processStartTag(token);
260         break;
261     case HTMLToken::EndTag:
262         processEndTag(token);
263         break;
264     case HTMLToken::Comment:
265         processComment(token);
266         return;
267     case HTMLToken::Character:
268         processCharacter(token);
269         break;
270     case HTMLToken::EndOfFile:
271         processEndOfFile(token);
272         break;
273     }
274 }
275
276 void HTMLTreeBuilder::processDoctypeToken(AtomicHTMLToken& token)
277 {
278     if (insertionMode() == InitialMode) {
279         insertDoctype(token);
280         return;
281     }
282     parseError(token);
283 }
284
285 void HTMLTreeBuilder::insertHTMLStartTagBeforeHTML(AtomicHTMLToken& token)
286 {
287     RefPtr<Element> element = HTMLHtmlElement::create(m_document);
288     element->setAttributeMap(token.attributes(), m_fragmentScriptingPermission);
289     m_openElements.pushHTMLHtmlElement(attach(m_document, element.release()));
290 }
291
292 void HTMLTreeBuilder::mergeAttributesFromTokenIntoElement(AtomicHTMLToken& token, Element* element)
293 {
294     if (!token.attributes())
295         return;
296
297     NamedNodeMap* attributes = element->attributes(false);
298     for (unsigned i = 0; i < token.attributes()->length(); ++i) {
299         Attribute* attribute = token.attributes()->attributeItem(i);
300         if (!attributes->getAttributeItem(attribute->name()))
301             element->setAttribute(attribute->name(), attribute->value());
302     }
303 }
304
305 void HTMLTreeBuilder::insertHTMLStartTagInBody(AtomicHTMLToken& token)
306 {
307     parseError(token);
308     mergeAttributesFromTokenIntoElement(token, m_openElements.htmlElement());
309 }
310
311 void HTMLTreeBuilder::processFakePEndTagIfPInScope()
312 {
313     if (!m_openElements.inScope(pTag.localName()))
314         return;
315     AtomicHTMLToken endP(HTMLToken::EndTag, pTag.localName());
316     processEndTag(endP);
317 }
318
319 void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token)
320 {
321     switch (insertionMode()) {
322     case InitialMode:
323         ASSERT(insertionMode() == InitialMode);
324         processDefaultForInitialMode(token);
325         // Fall through.
326     case BeforeHTMLMode:
327         ASSERT(insertionMode() == BeforeHTMLMode);
328         if (token.name() == htmlTag) {
329             insertHTMLStartTagBeforeHTML(token);
330             setInsertionMode(BeforeHeadMode);
331             return;
332         }
333         processDefaultForBeforeHTMLMode(token);
334         // Fall through.
335     case BeforeHeadMode:
336         ASSERT(insertionMode() == BeforeHeadMode);
337         if (token.name() == htmlTag) {
338             insertHTMLStartTagInBody(token);
339             return;
340         }
341         if (token.name() == headTag) {
342             insertHTMLHeadElement(token);
343             setInsertionMode(InHeadMode);
344             return;
345         }
346         processDefaultForBeforeHeadMode(token);
347         // Fall through.
348     case InHeadMode:
349         ASSERT(insertionMode() == InHeadMode);
350         if (processStartTagForInHead(token))
351             return;
352         processDefaultForInHeadMode(token);
353         // Fall through.
354     case AfterHeadMode:
355         ASSERT(insertionMode() == AfterHeadMode);
356         if (token.name() == htmlTag) {
357             insertHTMLStartTagInBody(token);
358             return;
359         }
360         if (token.name() == bodyTag) {
361             m_framesetOk = false;
362             insertHTMLBodyElement(token);
363             m_insertionMode = InBodyMode;
364             return;
365         }
366         if (token.name() == framesetTag) {
367             insertElement(token);
368             setInsertionMode(InFramesetMode);
369             return;
370         }
371         if (token.name() == baseTag || token.name() == linkTag || token.name() == metaTag || token.name() == noframesTag || token.name() == scriptTag || token.name() == styleTag || token.name() == titleTag) {
372             parseError(token);
373             ASSERT(m_headElement);
374             m_openElements.pushHTMLHeadElement(m_headElement);
375             processStartTagForInHead(token);
376             m_openElements.removeHTMLHeadElement(m_headElement.get());
377             return;
378         }
379         if (token.name() == headTag) {
380             parseError(token);
381             return;
382         }
383         processDefaultForAfterHeadMode(token);
384         // Fall through
385     case InBodyMode:
386         ASSERT(insertionMode() == InBodyMode);
387         if (token.name() == htmlTag) {
388             insertHTMLStartTagInBody(token);
389             return;
390         }
391         if (token.name() == baseTag || token.name() == "command" || token.name() == linkTag || token.name() == metaTag || token.name() == noframesTag || token.name() == scriptTag || token.name() == styleTag || token.name() == titleTag) {
392             bool didProcess = processStartTagForInHead(token);
393             ASSERT_UNUSED(didProcess, didProcess);
394             return;
395         }
396         if (token.name() == bodyTag) {
397             parseError(token);
398             notImplemented(); // fragment case
399             mergeAttributesFromTokenIntoElement(token, m_openElements.bodyElement());
400             return;
401         }
402         if (token.name() == framesetTag) {
403             parseError(token);
404             notImplemented(); // fragment case
405             if (!m_framesetOk)
406                 return;
407             ExceptionCode ec = 0;
408             m_openElements.bodyElement()->remove(ec);
409             ASSERT(!ec);
410             m_openElements.popUntil(m_openElements.bodyElement());
411             m_openElements.popHTMLBodyElement();
412             ASSERT(m_openElements.top() == m_openElements.htmlElement());
413             insertElement(token);
414             m_insertionMode = InFramesetMode;
415             return;
416         }
417         if (token.name() == addressTag || token.name() == articleTag || token.name() == asideTag || token.name() == blockquoteTag || token.name() == centerTag || token.name() == "details" || token.name() == dirTag || token.name() == divTag || token.name() == dlTag || token.name() == fieldsetTag || token.name() == "figure" || token.name() == footerTag || token.name() == headerTag || token.name() == hgroupTag || token.name() == menuTag || token.name() == navTag || token.name() == olTag || token.name() == pTag || token.name() == sectionTag || token.name() == ulTag) {
418             processFakePEndTagIfPInScope();
419             insertElement(token);
420             return;
421         }
422         if (token.name() == h1Tag || token.name() == h2Tag || token.name() == h3Tag || token.name() == h4Tag || token.name() == h5Tag || token.name() == h6Tag) {
423             processFakePEndTagIfPInScope();
424             notImplemented();
425             insertElement(token);
426             return;
427         }
428         if (token.name() == preTag || token.name() == listingTag) {
429             processFakePEndTagIfPInScope();
430             insertElement(token);
431             m_tokenizer->skipLeadingNewLineForListing();
432             m_framesetOk = false;
433             return;
434         }
435         if (token.name() == formTag) {
436             notImplemented();
437             processFakePEndTagIfPInScope();
438             insertElement(token);
439             m_formElement = currentElement();
440             return;
441         }
442         if (token.name() == liTag) {
443             notImplemented();
444             processFakePEndTagIfPInScope();
445             insertElement(token);
446             return;
447         }
448         if (token.name() == ddTag || token.name() == dtTag) {
449             notImplemented();
450             processFakePEndTagIfPInScope();
451             insertElement(token);
452             return;
453         }
454         if (token.name() == plaintextTag) {
455             processFakePEndTagIfPInScope();
456             insertElement(token);
457             m_tokenizer->setState(HTMLTokenizer::PLAINTEXTState);
458             return;
459         }
460         if (token.name() == buttonTag) {
461             notImplemented();
462             reconstructTheActiveFormattingElements();
463             insertElement(token);
464             m_framesetOk = false;
465             return;
466         }
467         if (token.name() == aTag) {
468             notImplemented();
469             reconstructTheActiveFormattingElements();
470             insertFormattingElement(token);
471             return;
472         }
473         if (token.name() == bTag || token.name() == bigTag || token.name() == codeTag || token.name() == emTag || token.name() == fontTag || token.name() == iTag || token.name() == sTag || token.name() == smallTag || token.name() == strikeTag || token.name() == strongTag || token.name() == ttTag || token.name() == uTag) {
474             reconstructTheActiveFormattingElements();
475             insertFormattingElement(token);
476             return;
477         }
478         if (token.name() == nobrTag) {
479             reconstructTheActiveFormattingElements();
480             notImplemented();
481             insertFormattingElement(token);
482             return;
483         }
484         if (token.name() == appletTag || token.name() == marqueeTag || token.name() == objectTag) {
485             reconstructTheActiveFormattingElements();
486             insertElement(token);
487             notImplemented();
488             m_framesetOk = false;
489             return;
490         }
491         if (token.name() == tableTag) {
492             notImplemented();
493             insertElement(token);
494             m_framesetOk = false;
495             m_insertionMode = InTableMode;
496             return;
497         }
498         if (token.name() == imageTag) {
499             parseError(token);
500             // Apparently we're not supposed to ask.
501             token.setName(imgTag.localName());
502             // Note the fall through to the imgTag handling below!
503         }
504         if (token.name() == areaTag || token.name() == basefontTag || token.name() == "bgsound" || token.name() == brTag || token.name() == embedTag || token.name() == imgTag || token.name() == inputTag || token.name() == keygenTag || token.name() == wbrTag) {
505             reconstructTheActiveFormattingElements();
506             insertSelfClosingElement(token);
507             m_framesetOk = false;
508             return;
509         }
510         if (token.name() == paramTag || token.name() == sourceTag || token.name() == "track") {
511             insertSelfClosingElement(token);
512             return;
513         }
514         if (token.name() == hrTag) {
515             processFakePEndTagIfPInScope();
516             insertSelfClosingElement(token);
517             m_framesetOk = false;
518             return;
519         }
520         if (token.name() == isindexTag) {
521             parseError(token);
522             notImplemented();
523             return;
524         }
525         if (token.name() == textareaTag) {
526             insertElement(token);
527             m_tokenizer->skipLeadingNewLineForListing();
528             m_tokenizer->setState(HTMLTokenizer::RCDATAState);
529             m_originalInsertionMode = m_insertionMode;
530             m_framesetOk = false;
531             m_insertionMode = TextMode;
532             return;
533         }
534         if (token.name() == xmpTag) {
535             processFakePEndTagIfPInScope();
536             reconstructTheActiveFormattingElements();
537             m_framesetOk = false;
538             insertGenericRawTextElement(token);
539             return;
540         }
541         if (token.name() == iframeTag) {
542             m_framesetOk = false;
543             insertGenericRawTextElement(token);
544             return;
545         }
546         if (token.name() == noembedTag) {
547             insertGenericRawTextElement(token);
548             return;
549         }
550         if (token.name() == noscriptTag && isScriptingFlagEnabled(m_document->frame())) {
551             insertGenericRawTextElement(token);
552             return;
553         }
554         if (token.name() == selectTag) {
555             reconstructTheActiveFormattingElements();
556             insertElement(token);
557             m_framesetOk = false;
558             if (m_insertionMode == InTableMode || m_insertionMode == InCaptionMode || m_insertionMode == InColumnGroupMode || m_insertionMode == InTableBodyMode || m_insertionMode == InRowMode || m_insertionMode == InCellMode)
559                 m_insertionMode = InSelectInTableMode;
560             else
561                 m_insertionMode = InSelectMode;
562             return;
563         }
564         if (token.name() == optgroupTag || token.name() == optionTag) {
565             if (m_openElements.inScope(optionTag.localName())) {
566                 AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName());
567                 processEndTag(endOption);
568             }
569             reconstructTheActiveFormattingElements();
570             insertElement(token);
571             return;
572         }
573         if (token.name() == rpTag || token.name() == rtTag) {
574             if (m_openElements.inScope(rubyTag.localName())) {
575                 generateImpliedEndTags();
576                 if (!currentElement()->hasTagName(rubyTag)) {
577                     parseError(token);
578                     m_openElements.popUntil(rubyTag.localName());
579                 }
580             }
581             insertElement(token);
582             return;
583         }
584         if (token.name() == "math") {
585             // This is the MathML foreign content branch point.
586             notImplemented();
587         }
588         if (token.name() == "svg") {
589             // This is the SVG foreign content branch point.
590             notImplemented();
591         }
592         if (token.name() == captionTag || token.name() == colTag || token.name() == colgroupTag || token.name() == frameTag || token.name() == headTag || token.name() == tbodyTag || token.name() == tdTag || token.name() == tfootTag || token.name() == thTag || token.name() == theadTag || token.name() == trTag) {
593             parseError(token);
594             return;
595         }
596         reconstructTheActiveFormattingElements();
597         insertElement(token);
598         break;
599     case AfterBodyMode:
600     case AfterAfterBodyMode:
601         ASSERT(insertionMode() == AfterBodyMode || insertionMode() == AfterAfterBodyMode);
602         if (token.name() == htmlTag) {
603             insertHTMLStartTagInBody(token);
604             return;
605         }
606         m_insertionMode = InBodyMode;
607         processStartTag(token);
608         break;
609     case InHeadNoscriptMode:
610         ASSERT(insertionMode() == InHeadNoscriptMode);
611         if (token.name() == htmlTag) {
612             insertHTMLStartTagInBody(token);
613             return;
614         }
615         if (token.name() == linkTag || token.name() == metaTag || token.name() == noframesTag || token.name() == styleTag) {
616             bool didProcess = processStartTagForInHead(token);
617             ASSERT_UNUSED(didProcess, didProcess);
618             return;
619         }
620         if (token.name() == htmlTag || token.name() == noscriptTag) {
621             parseError(token);
622             return;
623         }
624         processDefaultForInHeadNoscriptMode(token);
625         processToken(token);
626         break;
627     case InFramesetMode:
628         ASSERT(insertionMode() == InFramesetMode);
629         if (token.name() == htmlTag) {
630             insertHTMLStartTagInBody(token);
631             return;
632         }
633         if (token.name() == framesetTag) {
634             insertElement(token);
635             return;
636         }
637         if (token.name() == frameTag) {
638             insertSelfClosingElement(token);
639             return;
640         }
641         if (token.name() == noframesTag) {
642             processStartTagForInHead(token);
643             return;
644         }
645         parseError(token);
646         break;
647     case AfterFramesetMode:
648     case AfterAfterFramesetMode:
649         ASSERT(insertionMode() == AfterFramesetMode || insertionMode() == AfterAfterFramesetMode);
650         if (token.name() == htmlTag) {
651             insertHTMLStartTagInBody(token);
652             return;
653         }
654         if (token.name() == noframesTag) {
655             processStartTagForInHead(token);
656             return;
657         }
658         parseError(token);
659         break;
660     default:
661         notImplemented();
662     }
663 }
664
665 bool HTMLTreeBuilder::processBodyEndTagForInBody(AtomicHTMLToken& token)
666 {
667     if (!m_openElements.inScope(bodyTag.localName())) {
668         parseError(token);
669         return false;
670     }
671     notImplemented();
672     m_insertionMode = AfterBodyMode;
673     return true;
674 }
675
676 void HTMLTreeBuilder::processEndTag(AtomicHTMLToken& token)
677 {
678     switch (insertionMode()) {
679     case InitialMode:
680         ASSERT(insertionMode() == InitialMode);
681         processDefaultForInitialMode(token);
682         // Fall through.
683     case BeforeHTMLMode:
684         ASSERT(insertionMode() == BeforeHTMLMode);
685         if (token.name() != headTag && token.name() != bodyTag && token.name() != htmlTag && token.name() != brTag) {
686             parseError(token);
687             return;
688         }
689         processDefaultForBeforeHTMLMode(token);
690         // Fall through.
691     case BeforeHeadMode:
692         ASSERT(insertionMode() == BeforeHeadMode);
693         if (token.name() != headTag && token.name() != bodyTag && token.name() != brTag) {
694             parseError(token);
695             return;
696         }
697         processDefaultForBeforeHeadMode(token);
698         // Fall through.
699     case InHeadMode:
700         ASSERT(insertionMode() == InHeadMode);
701         if (token.name() == headTag) {
702             m_openElements.popHTMLHeadElement();
703             setInsertionMode(AfterHeadMode);
704             return;
705         }
706         if (token.name() != bodyTag && token.name() != htmlTag && token.name() != brTag) {
707             parseError(token);
708             return;
709         }
710         processDefaultForInHeadMode(token);
711         // Fall through.
712     case AfterHeadMode:
713         ASSERT(insertionMode() == AfterHeadMode);
714         if (token.name() != bodyTag && token.name() != htmlTag && token.name() != brTag) {
715             parseError(token);
716             return;
717         }
718         processDefaultForAfterHeadMode(token);
719         // Fall through
720     case InBodyMode:
721         ASSERT(insertionMode() == InBodyMode);
722         if (token.name() == bodyTag) {
723             processBodyEndTagForInBody(token);
724             return;
725         }
726         if (token.name() == htmlTag) {
727             if (processBodyEndTagForInBody(token))
728                 processEndTag(token);
729             return;
730         }
731         if (token.name() == addressTag || token.name() == articleTag || token.name() == asideTag || token.name() == blockquoteTag || token.name() == buttonTag || token.name() == centerTag || token.name() == "details" || token.name() == dirTag || token.name() == divTag || token.name() == dlTag || token.name() == fieldsetTag || token.name() == "figure" || token.name() == footerTag || token.name() == headerTag || token.name() == hgroupTag || token.name() == listingTag || token.name() == menuTag || token.name() == navTag || token.name() == olTag || token.name() == preTag || token.name() == sectionTag || token.name() == ulTag) {
732             if (!m_openElements.inScope(token.name())) {
733                 parseError(token);
734                 return;
735             }
736             generateImpliedEndTags();
737             if (currentElement()->tagQName() != token.name())
738                 parseError(token);
739             m_openElements.popUntil(token.name());
740             m_openElements.pop();
741         }
742         if (token.name() == formTag) {
743             RefPtr<Element> node = m_formElement.release();
744             if (!node || !m_openElements.inScope(node.get())) {
745                 parseError(token);
746                 return;
747             }
748             generateImpliedEndTags();
749             if (currentElement() != node.get())
750                 parseError(token);
751             m_openElements.remove(node.get());
752         }
753         if (token.name() == pTag) {
754             if (!m_openElements.inScope(token.name())) {
755                 parseError(token);
756                 notImplemented();
757                 return;
758             }
759             generateImpliedEndTagsWithExclusion(token.name());
760             if (!currentElement()->hasLocalName(token.name()))
761                 parseError(token);
762             m_openElements.popUntil(token.name());
763             m_openElements.pop();
764             return;
765         }
766         if (token.name() == liTag) {
767             if (!m_openElements.inListItemScope(token.name())) {
768                 parseError(token);
769                 return;
770             }
771             generateImpliedEndTagsWithExclusion(token.name());
772             if (!currentElement()->hasLocalName(token.name()))
773                 parseError(token);
774             m_openElements.popUntil(token.name());
775             m_openElements.pop();
776             return;
777         }
778         if (token.name() == ddTag || token.name() == dtTag) {
779             if (!m_openElements.inScope(token.name())) {
780                 parseError(token);
781                 return;
782             }
783             generateImpliedEndTagsWithExclusion(token.name());
784             if (!currentElement()->hasLocalName(token.name()))
785                 parseError(token);
786             m_openElements.popUntil(token.name());
787             m_openElements.pop();
788             return;
789         }
790         if (token.name() == h1Tag || token.name() == h2Tag || token.name() == h3Tag || token.name() == h4Tag || token.name() == h5Tag || token.name() == h6Tag) {
791             if (!m_openElements.inScope(token.name())) {
792                 parseError(token);
793                 return;
794             }
795             generateImpliedEndTags();
796             if (!currentElement()->hasLocalName(token.name()))
797                 parseError(token);
798             m_openElements.popUntil(token.name());
799             m_openElements.pop();
800             return;
801         }
802         if (token.name() == "sarcasm") {
803             notImplemented(); // Take a deep breath.
804             return;
805         }
806         if (token.name() == aTag || token.name() == bTag || token.name() == bigTag || token.name() == codeTag || token.name() == emTag || token.name() == fontTag || token.name() == iTag || token.name() == nobrTag || token.name() == sTag || token.name() == smallTag || token.name() == strikeTag || token.name() == strongTag || token.name() == ttTag || token.name() == uTag) {
807             notImplemented();
808             // FIXME: There's a complicated algorithm that goes here.
809             return;
810         }
811         if (token.name() == appletTag || token.name() == marqueeTag || token.name() == objectTag) {
812             if (!m_openElements.inScope(token.name())) {
813                 parseError(token);
814                 return;
815             }
816             generateImpliedEndTags();
817             if (currentElement()->tagQName() != token.name())
818                 parseError(token);
819             m_openElements.popUntil(token.name());
820             m_openElements.pop();
821             m_activeFormattingElements.clearToLastMarker();
822             return;
823         }
824         if (token.name() == brTag) {
825             parseError(token);
826             reconstructTheActiveFormattingElements();
827             // Notice that we lose the attributes.
828             AtomicHTMLToken startBr(HTMLToken::StartTag, token.name());
829             insertSelfClosingElement(startBr);
830             m_framesetOk = false;
831             return;
832         }
833         // FIXME: We need an iterator over m_openElements to implement this
834         // correctly.
835         notImplemented();
836         if (!m_openElements.inScope(token.name()))
837             return;
838         m_openElements.popUntil(token.name());
839         m_openElements.pop();
840         break;
841     case AfterBodyMode:
842         ASSERT(insertionMode() == AfterBodyMode);
843         if (token.name() == htmlTag) {
844             if (m_isParsingFragment) {
845                 parseError(token);
846                 return;
847             }
848             m_insertionMode = AfterAfterBodyMode;
849             return;
850         }
851         // Fall through.
852     case AfterAfterBodyMode:
853         ASSERT(insertionMode() == AfterBodyMode || insertionMode() == AfterAfterBodyMode);
854         parseError(token);
855         m_insertionMode = InBodyMode;
856         processEndTag(token);
857         break;
858     case InHeadNoscriptMode:
859         ASSERT(insertionMode() == InHeadNoscriptMode);
860         if (token.name() == noscriptTag) {
861             ASSERT(currentElement()->tagQName() == noscriptTag);
862             m_openElements.pop();
863             ASSERT(currentElement()->tagQName() == headTag);
864             setInsertionMode(InHeadMode);
865             return;
866         }
867         if (token.name() != brTag) {
868             parseError(token);
869             return;
870         }
871         processDefaultForInHeadNoscriptMode(token);
872         processToken(token);
873         break;
874     case TextMode:
875         if (token.name() == scriptTag) {
876             // Pause ourselves so that parsing stops until the script can be processed by the caller.
877             m_isPaused = true;
878             ASSERT(currentElement()->tagQName() == scriptTag);
879             m_scriptToProcess = currentElement();
880             m_openElements.pop();
881             m_insertionMode = m_originalInsertionMode;
882             return;
883         }
884         m_openElements.pop();
885         m_insertionMode = m_originalInsertionMode;
886         break;
887     case InFramesetMode:
888         ASSERT(insertionMode() == InFramesetMode);
889         if (token.name() == framesetTag) {
890             if (currentElement() == m_openElements.htmlElement()) {
891                 parseError(token);
892                 return;
893             }
894             m_openElements.pop();
895             if (!m_isParsingFragment && !currentElement()->hasTagName(framesetTag))
896                 m_insertionMode = AfterFramesetMode;
897             return;
898         }
899         break;
900     case AfterFramesetMode:
901         ASSERT(insertionMode() == AfterFramesetMode);
902         if (token.name() == htmlTag) {
903             m_insertionMode = AfterAfterFramesetMode;
904             return;
905         }
906         // Fall through.
907     case AfterAfterFramesetMode:
908         ASSERT(insertionMode() == AfterFramesetMode || insertionMode() == AfterAfterFramesetMode);
909         parseError(token);
910         break;
911     default:
912         notImplemented();
913     }
914 }
915
916 void HTMLTreeBuilder::processComment(AtomicHTMLToken& token)
917 {
918     if (m_insertionMode == InitialMode || m_insertionMode == BeforeHTMLMode || m_insertionMode == AfterAfterBodyMode || m_insertionMode == AfterAfterFramesetMode) {
919         insertCommentOnDocument(token);
920         return;
921     }
922     if (m_insertionMode == AfterBodyMode) {
923         insertCommentOnHTMLHtmlElement(token);
924         return;
925     }
926     insertComment(token);
927 }
928
929 void HTMLTreeBuilder::processCharacter(AtomicHTMLToken& token)
930 {
931     // FIXME: We need to figure out how to handle each character individually.
932     switch (insertionMode()) {
933     case InitialMode:
934         ASSERT(insertionMode() == InitialMode);
935         notImplemented();
936         processDefaultForInitialMode(token);
937         // Fall through.
938     case BeforeHTMLMode:
939         ASSERT(insertionMode() == BeforeHTMLMode);
940         notImplemented();
941         processDefaultForBeforeHTMLMode(token);
942         // Fall through.
943     case BeforeHeadMode:
944         ASSERT(insertionMode() == BeforeHeadMode);
945         notImplemented();
946         processDefaultForBeforeHeadMode(token);
947         // Fall through.
948     case InHeadMode:
949         ASSERT(insertionMode() == InHeadMode);
950         notImplemented();
951         processDefaultForInHeadMode(token);
952         // Fall through.
953     case AfterHeadMode:
954         ASSERT(insertionMode() == AfterHeadMode);
955         notImplemented();
956         processDefaultForAfterHeadMode(token);
957         // Fall through
958     case InBodyMode:
959         ASSERT(insertionMode() == InBodyMode);
960         notImplemented();
961         insertTextNode(token);
962         break;
963     case AfterBodyMode:
964     case AfterAfterBodyMode:
965         ASSERT(insertionMode() == AfterBodyMode || insertionMode() == AfterAfterBodyMode);
966         parseError(token);
967         m_insertionMode = InBodyMode;
968         processCharacter(token);
969         break;
970     case TextMode:
971         notImplemented();
972         insertTextNode(token);
973         break;
974     case InHeadNoscriptMode:
975         ASSERT(insertionMode() == InHeadNoscriptMode);
976         processDefaultForInHeadNoscriptMode(token);
977         processToken(token);
978         break;
979     case InFramesetMode:
980     case AfterFramesetMode:
981     case AfterAfterFramesetMode:
982         ASSERT(insertionMode() == InFramesetMode || insertionMode() == AfterFramesetMode || insertionMode() == AfterAfterFramesetMode);
983         parseError(token);
984         break;
985     default:
986         notImplemented();
987     }
988 }
989
990 void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken& token)
991 {
992     switch (insertionMode()) {
993     case InitialMode:
994         ASSERT(insertionMode() == InitialMode);
995         processDefaultForInitialMode(token);
996         // Fall through.
997     case BeforeHTMLMode:
998         ASSERT(insertionMode() == BeforeHTMLMode);
999         processDefaultForBeforeHTMLMode(token);
1000         // Fall through.
1001     case BeforeHeadMode:
1002         ASSERT(insertionMode() == BeforeHeadMode);
1003         processDefaultForBeforeHeadMode(token);
1004         // Fall through.
1005     case InHeadMode:
1006         ASSERT(insertionMode() == InHeadMode);
1007         processDefaultForInHeadMode(token);
1008         // Fall through.
1009     case AfterHeadMode:
1010         ASSERT(insertionMode() == AfterHeadMode);
1011         processDefaultForAfterHeadMode(token);
1012         // Fall through
1013     case InBodyMode:
1014         ASSERT(insertionMode() == InBodyMode);
1015         notImplemented();
1016         break;
1017     case AfterBodyMode:
1018     case AfterAfterBodyMode:
1019         ASSERT(insertionMode() == AfterBodyMode || insertionMode() == AfterAfterBodyMode);
1020         notImplemented();
1021         break;
1022     case InHeadNoscriptMode:
1023         ASSERT(insertionMode() == InHeadNoscriptMode);
1024         processDefaultForInHeadNoscriptMode(token);
1025         processToken(token);
1026         break;
1027     case InFramesetMode:
1028         ASSERT(insertionMode() == InFramesetMode);
1029         if (currentElement() != m_openElements.htmlElement())
1030             parseError(token);
1031         break;
1032     case AfterFramesetMode:
1033     case AfterAfterFramesetMode:
1034         ASSERT(insertionMode() == AfterFramesetMode || insertionMode() == AfterAfterFramesetMode);
1035         break;
1036     default:
1037         notImplemented();
1038     }
1039 }
1040
1041 void HTMLTreeBuilder::processDefaultForInitialMode(AtomicHTMLToken& token)
1042 {
1043     notImplemented();
1044     parseError(token);
1045     setInsertionMode(BeforeHTMLMode);
1046 }
1047
1048 void HTMLTreeBuilder::processDefaultForBeforeHTMLMode(AtomicHTMLToken&)
1049 {
1050     AtomicHTMLToken startHTML(HTMLToken::StartTag, htmlTag.localName());
1051     insertHTMLStartTagBeforeHTML(startHTML);
1052     setInsertionMode(BeforeHeadMode);
1053 }
1054
1055 void HTMLTreeBuilder::processDefaultForBeforeHeadMode(AtomicHTMLToken&)
1056 {
1057     AtomicHTMLToken startHead(HTMLToken::StartTag, headTag.localName());
1058     processStartTag(startHead);
1059 }
1060
1061 void HTMLTreeBuilder::processDefaultForInHeadMode(AtomicHTMLToken&)
1062 {
1063     AtomicHTMLToken endHead(HTMLToken::EndTag, headTag.localName());
1064     processEndTag(endHead);
1065 }
1066
1067 void HTMLTreeBuilder::processDefaultForInHeadNoscriptMode(AtomicHTMLToken&)
1068 {
1069     AtomicHTMLToken endNoscript(HTMLToken::EndTag, noscriptTag.localName());
1070     processEndTag(endNoscript);
1071 }
1072
1073 void HTMLTreeBuilder::processDefaultForAfterHeadMode(AtomicHTMLToken&)
1074 {
1075     AtomicHTMLToken startBody(HTMLToken::StartTag, bodyTag.localName());
1076     processStartTag(startBody);
1077     m_framesetOk = true;
1078 }
1079
1080 bool HTMLTreeBuilder::processStartTagForInHead(AtomicHTMLToken& token)
1081 {
1082     if (token.name() == htmlTag) {
1083         insertHTMLStartTagInBody(token);
1084         return true;
1085     }
1086     // FIXME: Atomize "command".
1087     if (token.name() == baseTag || token.name() == "command" || token.name() == linkTag || token.name() == metaTag) {
1088         insertSelfClosingElement(token);
1089         // Note: The custom processing for the <meta> tag is done in HTMLMetaElement::process().
1090         return true;
1091     }
1092     if (token.name() == titleTag) {
1093         insertGenericRCDATAElement(token);
1094         return true;
1095     }
1096     if (token.name() == noscriptTag) {
1097         if (isScriptingFlagEnabled(m_document->frame())) {
1098             insertGenericRawTextElement(token);
1099             return true;
1100         }
1101         insertElement(token);
1102         setInsertionMode(InHeadNoscriptMode);
1103         return true;
1104     }
1105     if (token.name() == noframesTag || token.name() == styleTag) {
1106         insertGenericRawTextElement(token);
1107         return true;
1108     }
1109     if (token.name() == scriptTag) {
1110         insertScriptElement(token);
1111         return true;
1112     }
1113     if (token.name() == headTag) {
1114         parseError(token);
1115         return true;
1116     }
1117     return false;
1118 }
1119
1120 void HTMLTreeBuilder::insertDoctype(AtomicHTMLToken& token)
1121 {
1122     ASSERT(token.type() == HTMLToken::DOCTYPE);
1123     attach(m_document, DocumentType::create(m_document, token.name(), String::adopt(token.publicIdentifier()), String::adopt(token.systemIdentifier())));
1124     // FIXME: Move quirks mode detection from DocumentType element to here.
1125     notImplemented();
1126     if (token.forceQuirks())
1127         m_document->setParseMode(Document::Compat);
1128 }
1129
1130 void HTMLTreeBuilder::insertComment(AtomicHTMLToken& token)
1131 {
1132     ASSERT(token.type() == HTMLToken::Comment);
1133     attach(currentElement(), Comment::create(m_document, token.comment()));
1134 }
1135
1136 void HTMLTreeBuilder::insertCommentOnDocument(AtomicHTMLToken& token)
1137 {
1138     ASSERT(token.type() == HTMLToken::Comment);
1139     attach(m_document, Comment::create(m_document, token.comment()));
1140 }
1141
1142 void HTMLTreeBuilder::insertCommentOnHTMLHtmlElement(AtomicHTMLToken& token)
1143 {
1144     ASSERT(token.type() == HTMLToken::Comment);
1145     attach(m_openElements.htmlElement(), Comment::create(m_document, token.comment()));
1146 }
1147
1148 PassRefPtr<Element> HTMLTreeBuilder::createElementAndAttachToCurrent(AtomicHTMLToken& token)
1149 {
1150     ASSERT(token.type() == HTMLToken::StartTag);
1151     return attach(currentElement(), createElement(token));
1152 }
1153
1154 void HTMLTreeBuilder::insertHTMLHtmlElement(AtomicHTMLToken& token)
1155 {
1156     m_openElements.pushHTMLHtmlElement(createElementAndAttachToCurrent(token));
1157 }
1158
1159 void HTMLTreeBuilder::insertHTMLHeadElement(AtomicHTMLToken& token)
1160 {
1161     m_headElement = createElementAndAttachToCurrent(token);
1162     m_openElements.pushHTMLHeadElement(m_headElement);
1163 }
1164
1165 void HTMLTreeBuilder::insertHTMLBodyElement(AtomicHTMLToken& token)
1166 {
1167     m_openElements.pushHTMLBodyElement(createElementAndAttachToCurrent(token));
1168 }
1169
1170 void HTMLTreeBuilder::insertElement(AtomicHTMLToken& token)
1171 {
1172     m_openElements.push(createElementAndAttachToCurrent(token));
1173 }
1174
1175 void HTMLTreeBuilder::insertSelfClosingElement(AtomicHTMLToken& token)
1176 {
1177     ASSERT(token.type() == HTMLToken::StartTag);
1178     attach(currentElement(), createElement(token));
1179     // FIXME: Do we want to acknowledge the token's self-closing flag?
1180     // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#acknowledge-self-closing-flag
1181 }
1182
1183 void HTMLTreeBuilder::insertFormattingElement(AtomicHTMLToken& token)
1184 {
1185     // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#the-stack-of-open-elements
1186     // Possible active formatting elements include:
1187     // a, b, big, code, em, font, i, nobr, s, small, strike, strong, tt, and u.
1188     insertElement(token);
1189     m_activeFormattingElements.append(currentElement());
1190 }
1191
1192 void HTMLTreeBuilder::insertGenericRCDATAElement(AtomicHTMLToken& token)
1193 {
1194     insertElement(token);
1195     m_tokenizer->setState(HTMLTokenizer::RCDATAState);
1196     m_originalInsertionMode = m_insertionMode;
1197     m_insertionMode = TextMode;
1198 }
1199
1200 void HTMLTreeBuilder::insertGenericRawTextElement(AtomicHTMLToken& token)
1201 {
1202     insertElement(token);
1203     m_tokenizer->setState(HTMLTokenizer::RAWTEXTState);
1204     m_originalInsertionMode = m_insertionMode;
1205     m_insertionMode = TextMode;
1206 }
1207
1208 void HTMLTreeBuilder::insertScriptElement(AtomicHTMLToken& token)
1209 {
1210     ASSERT_UNUSED(token, token.type() == HTMLToken::StartTag);
1211     RefPtr<HTMLScriptElement> element = HTMLScriptElement::create(scriptTag, m_document, true);
1212     element->setAttributeMap(token.attributes(), m_fragmentScriptingPermission);
1213     m_openElements.push(attach(currentElement(), element.release()));
1214     m_tokenizer->setState(HTMLTokenizer::ScriptDataState);
1215     m_originalInsertionMode = m_insertionMode;
1216     m_insertionMode = TextMode;
1217 }
1218
1219 void HTMLTreeBuilder::insertTextNode(AtomicHTMLToken& token)
1220 {
1221     attach(currentElement(), Text::create(m_document, token.characters()));
1222 }
1223     
1224 PassRefPtr<Element> HTMLTreeBuilder::createElement(AtomicHTMLToken& token)
1225 {
1226     RefPtr<Element> element = HTMLElementFactory::createHTMLElement(QualifiedName(nullAtom, token.name(), xhtmlNamespaceURI), m_document, 0);
1227     element->setAttributeMap(token.attributes(), m_fragmentScriptingPermission);
1228     return element.release();
1229 }
1230
1231 bool HTMLTreeBuilder::indexOfFirstUnopenFormattingElement(unsigned& firstUnopenElementIndex) const
1232 {
1233     if (m_activeFormattingElements.isEmpty())
1234         return false;
1235     unsigned index = m_activeFormattingElements.size();
1236     do {
1237         --index;
1238         const HTMLFormattingElementList::Entry& entry = m_activeFormattingElements[index];
1239         if (entry.isMarker() || m_openElements.contains(entry.element())) {
1240             firstUnopenElementIndex = index;
1241             return true;
1242         }
1243     } while (index);
1244     return false;
1245 }
1246
1247 void HTMLTreeBuilder::reconstructTheActiveFormattingElements()
1248 {
1249     unsigned firstUnopenElementIndex;
1250     if (!indexOfFirstUnopenFormattingElement(firstUnopenElementIndex))
1251         return;
1252
1253     unsigned unopenEntryIndex = firstUnopenElementIndex;
1254     ASSERT(unopenEntryIndex < m_activeFormattingElements.size());
1255     for (; unopenEntryIndex < m_activeFormattingElements.size(); ++unopenEntryIndex) {
1256         HTMLFormattingElementList::Entry& unopenedEntry = m_activeFormattingElements[unopenEntryIndex];
1257         // FIXME: We're supposed to save the original token in the entry.
1258         AtomicHTMLToken fakeToken(HTMLToken::StartTag, unopenedEntry.element()->localName());
1259         insertElement(fakeToken);
1260         unopenedEntry.replaceElement(currentElement());
1261     }
1262 }
1263
1264 namespace {
1265
1266 bool hasImpliedEndTag(Element* element)
1267 {
1268     return element->hasTagName(ddTag)
1269         || element->hasTagName(dtTag)
1270         || element->hasTagName(liTag)
1271         || element->hasTagName(optionTag)
1272         || element->hasTagName(optgroupTag)
1273         || element->hasTagName(pTag)
1274         || element->hasTagName(rpTag)
1275         || element->hasTagName(rtTag);
1276 }
1277
1278 }
1279
1280 void HTMLTreeBuilder::generateImpliedEndTagsWithExclusion(const AtomicString& tagName)
1281 {
1282     while (hasImpliedEndTag(currentElement()) && !currentElement()->hasLocalName(tagName))
1283         m_openElements.pop();
1284 }
1285
1286 void HTMLTreeBuilder::generateImpliedEndTags()
1287 {
1288     while (hasImpliedEndTag(currentElement()))
1289         m_openElements.pop();
1290 }
1291
1292 void HTMLTreeBuilder::finished()
1293 {
1294     // We should call m_document->finishedParsing() here, except
1295     // m_legacyTreeBuilder->finished() does it for us.
1296     if (m_legacyTreeBuilder) {
1297         m_legacyTreeBuilder->finished();
1298         return;
1299     }
1300
1301     AtomicHTMLToken eofToken(HTMLToken::EndOfFile, nullAtom);
1302     processToken(eofToken);
1303
1304     // Warning, this may delete the parser, so don't try to do anything else after this.
1305     if (!m_isParsingFragment)
1306         m_document->finishedParsing();
1307 }
1308
1309 bool HTMLTreeBuilder::isScriptingFlagEnabled(Frame* frame)
1310 {
1311     if (!frame)
1312         return false;
1313     if (ScriptController* scriptController = frame->script())
1314         return scriptController->canExecuteScripts(NotAboutToExecuteScript);
1315     return false;
1316 }
1317
1318 }