1/*
2 * Copyright (C) 2010 Google, Inc. All Rights Reserved.
3 * Copyright (C) 2011 Apple Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GOOGLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "HTMLTreeBuilder.h"
29
30#include "Comment.h"
31#include "DocumentFragment.h"
32#include "DocumentType.h"
33#include "Frame.h"
34#include "FrameLoader.h"
35#include "FrameLoaderClient.h"
36#include "HTMLElementFactory.h"
37#include "HTMLFormElement.h"
38#include "HTMLHtmlElement.h"
39#include "HTMLOptGroupElement.h"
40#include "HTMLOptionElement.h"
41#include "HTMLParserIdioms.h"
42#include "HTMLScriptElement.h"
43#include "HTMLTemplateElement.h"
44#include "NotImplemented.h"
45#include "SVGElement.h"
46#include "Text.h"
47
48namespace WebCore {
49
50using namespace HTMLNames;
51
52static inline void setAttributes(Element* element, AtomicHTMLToken* token, ParserContentPolicy parserContentPolicy)
53{
54    if (!scriptingContentIsAllowed(parserContentPolicy))
55        element->stripScriptingAttributes(token->attributes());
56    element->parserSetAttributes(token->attributes());
57}
58
59static bool hasImpliedEndTag(const HTMLStackItem* item)
60{
61    return item->hasTagName(ddTag)
62        || item->hasTagName(dtTag)
63        || item->hasTagName(liTag)
64        || isHTMLOptionElement(item->node())
65        || isHTMLOptGroupElement(item->node())
66        || item->hasTagName(pTag)
67        || item->hasTagName(rbTag)
68        || item->hasTagName(rpTag)
69        || item->hasTagName(rtTag)
70        || item->hasTagName(rtcTag);
71}
72
73static bool shouldUseLengthLimit(const ContainerNode* node)
74{
75    return !node->hasTagName(scriptTag)
76        && !node->hasTagName(styleTag)
77        && !node->hasTagName(SVGNames::scriptTag);
78}
79
80static inline bool isAllWhitespace(const String& string)
81{
82    return string.isAllSpecialCharacters<isHTMLSpace>();
83}
84
85static inline void insert(HTMLConstructionSiteTask& task)
86{
87#if ENABLE(TEMPLATE_ELEMENT)
88    if (task.parent->hasTagName(templateTag))
89        task.parent = toHTMLTemplateElement(task.parent.get())->content();
90#endif
91
92    if (ContainerNode* parent = task.child->parentNode())
93        parent->parserRemoveChild(*task.child);
94
95    if (task.nextChild)
96        task.parent->parserInsertBefore(task.child.get(), task.nextChild.get());
97    else
98        task.parent->parserAppendChild(task.child.get());
99}
100
101static inline void executeInsertTask(HTMLConstructionSiteTask& task)
102{
103    ASSERT(task.operation == HTMLConstructionSiteTask::Insert);
104
105    insert(task);
106
107    task.child->beginParsingChildren();
108
109    if (task.selfClosing)
110        task.child->finishParsingChildren();
111}
112
113static inline void executeReparentTask(HTMLConstructionSiteTask& task)
114{
115    ASSERT(task.operation == HTMLConstructionSiteTask::Reparent);
116
117    if (ContainerNode* parent = task.child->parentNode())
118        parent->parserRemoveChild(*task.child);
119
120    task.parent->parserAppendChild(task.child);
121}
122
123static inline void executeInsertAlreadyParsedChildTask(HTMLConstructionSiteTask& task)
124{
125    ASSERT(task.operation == HTMLConstructionSiteTask::InsertAlreadyParsedChild);
126
127    insert(task);
128}
129
130static inline void executeTakeAllChildrenTask(HTMLConstructionSiteTask& task)
131{
132    ASSERT(task.operation == HTMLConstructionSiteTask::TakeAllChildren);
133
134    task.parent->takeAllChildrenFrom(task.oldParent());
135    // Notice that we don't need to manually attach the moved children
136    // because takeAllChildrenFrom does that work for us.
137}
138
139static inline void executeTask(HTMLConstructionSiteTask& task)
140{
141    switch (task.operation) {
142    case HTMLConstructionSiteTask::Insert:
143        executeInsertTask(task);
144        return;
145    // All the cases below this point are only used by the adoption agency.
146    case HTMLConstructionSiteTask::InsertAlreadyParsedChild:
147        executeInsertAlreadyParsedChildTask(task);
148        return;
149    case HTMLConstructionSiteTask::Reparent:
150        executeReparentTask(task);
151        return;
152    case HTMLConstructionSiteTask::TakeAllChildren:
153        executeTakeAllChildrenTask(task);
154        return;
155    }
156    ASSERT_NOT_REACHED();
157}
158
159void HTMLConstructionSite::attachLater(ContainerNode* parent, PassRefPtr<Node> prpChild, bool selfClosing)
160{
161    ASSERT(scriptingContentIsAllowed(m_parserContentPolicy) || !prpChild.get()->isElementNode() || !toScriptElementIfPossible(toElement(prpChild.get())));
162    ASSERT(pluginContentIsAllowed(m_parserContentPolicy) || !prpChild->isPluginElement());
163
164    HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert);
165    task.parent = parent;
166    task.child = prpChild;
167    task.selfClosing = selfClosing;
168
169    if (shouldFosterParent()) {
170        fosterParent(task.child);
171        return;
172    }
173
174    // Add as a sibling of the parent if we have reached the maximum depth allowed.
175    if (m_openElements.stackDepth() > m_maximumDOMTreeDepth && task.parent->parentNode())
176        task.parent = task.parent->parentNode();
177
178    ASSERT(task.parent);
179    m_taskQueue.append(task);
180}
181
182void HTMLConstructionSite::executeQueuedTasks()
183{
184    const size_t size = m_taskQueue.size();
185    if (!size)
186        return;
187
188    // Copy the task queue into a local variable in case executeTask
189    // re-enters the parser.
190    TaskQueue queue = WTF::move(m_taskQueue);
191
192    for (size_t i = 0; i < size; ++i)
193        executeTask(queue[i]);
194
195    // We might be detached now.
196}
197
198HTMLConstructionSite::HTMLConstructionSite(Document& document, ParserContentPolicy parserContentPolicy, unsigned maximumDOMTreeDepth)
199    : m_document(&document)
200    , m_attachmentRoot(&document)
201    , m_parserContentPolicy(parserContentPolicy)
202    , m_isParsingFragment(false)
203    , m_redirectAttachToFosterParent(false)
204    , m_maximumDOMTreeDepth(maximumDOMTreeDepth)
205    , m_inQuirksMode(document.inQuirksMode())
206{
207    ASSERT(m_document->isHTMLDocument() || m_document->isXHTMLDocument());
208}
209
210HTMLConstructionSite::HTMLConstructionSite(DocumentFragment& fragment, ParserContentPolicy parserContentPolicy, unsigned maximumDOMTreeDepth)
211    : m_document(&fragment.document())
212    , m_attachmentRoot(&fragment)
213    , m_parserContentPolicy(parserContentPolicy)
214    , m_isParsingFragment(true)
215    , m_redirectAttachToFosterParent(false)
216    , m_maximumDOMTreeDepth(maximumDOMTreeDepth)
217    , m_inQuirksMode(fragment.document().inQuirksMode())
218{
219    ASSERT(m_document->isHTMLDocument() || m_document->isXHTMLDocument());
220}
221
222HTMLConstructionSite::~HTMLConstructionSite()
223{
224}
225
226void HTMLConstructionSite::detach()
227{
228    m_document = 0;
229    m_attachmentRoot = 0;
230}
231
232void HTMLConstructionSite::setForm(HTMLFormElement* form)
233{
234    // This method should only be needed for HTMLTreeBuilder in the fragment case.
235    ASSERT(!m_form);
236    m_form = form;
237}
238
239PassRefPtr<HTMLFormElement> HTMLConstructionSite::takeForm()
240{
241    return m_form.release();
242}
243
244void HTMLConstructionSite::dispatchDocumentElementAvailableIfNeeded()
245{
246    ASSERT(m_document);
247    if (m_document->frame() && !m_isParsingFragment)
248        m_document->frame()->injectUserScripts(InjectAtDocumentStart);
249}
250
251void HTMLConstructionSite::insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken* token)
252{
253    RefPtr<HTMLHtmlElement> element = HTMLHtmlElement::create(*m_document);
254    setAttributes(element.get(), token, m_parserContentPolicy);
255    attachLater(m_attachmentRoot, element);
256    m_openElements.pushHTMLHtmlElement(HTMLStackItem::create(element, token));
257
258    executeQueuedTasks();
259    element->insertedByParser();
260    dispatchDocumentElementAvailableIfNeeded();
261}
262
263void HTMLConstructionSite::mergeAttributesFromTokenIntoElement(AtomicHTMLToken* token, Element* element)
264{
265    if (token->attributes().isEmpty())
266        return;
267
268    for (unsigned i = 0; i < token->attributes().size(); ++i) {
269        const Attribute& tokenAttribute = token->attributes().at(i);
270        if (!element->elementData() || !element->findAttributeByName(tokenAttribute.name()))
271            element->setAttribute(tokenAttribute.name(), tokenAttribute.value());
272    }
273}
274
275void HTMLConstructionSite::insertHTMLHtmlStartTagInBody(AtomicHTMLToken* token)
276{
277    // Fragments do not have a root HTML element, so any additional HTML elements
278    // encountered during fragment parsing should be ignored.
279    if (m_isParsingFragment)
280        return;
281
282    mergeAttributesFromTokenIntoElement(token, m_openElements.htmlElement());
283}
284
285void HTMLConstructionSite::insertHTMLBodyStartTagInBody(AtomicHTMLToken* token)
286{
287    mergeAttributesFromTokenIntoElement(token, m_openElements.bodyElement());
288}
289
290void HTMLConstructionSite::setDefaultCompatibilityMode()
291{
292    if (m_isParsingFragment)
293        return;
294    if (m_document->isSrcdocDocument())
295        return;
296    setCompatibilityMode(DocumentCompatibilityMode::QuirksMode);
297}
298
299void HTMLConstructionSite::setCompatibilityMode(DocumentCompatibilityMode mode)
300{
301    m_inQuirksMode = (mode == DocumentCompatibilityMode::QuirksMode);
302    m_document->setCompatibilityMode(mode);
303}
304
305void HTMLConstructionSite::setCompatibilityModeFromDoctype(const String& name, const String& publicId, const String& systemId)
306{
307    // There are three possible compatibility modes:
308    // Quirks - quirks mode emulates WinIE and NS4. CSS parsing is also relaxed in this mode, e.g., unit types can
309    // be omitted from numbers.
310    // Limited Quirks - This mode is identical to no-quirks mode except for its treatment of line-height in the inline box model.
311    // No Quirks - no quirks apply. Web pages will obey the specifications to the letter.
312
313    // Check for Quirks Mode.
314    if (name != "html"
315        || publicId.startsWith("+//Silmaril//dtd html Pro v0r11 19970101//", false)
316        || publicId.startsWith("-//AdvaSoft Ltd//DTD HTML 3.0 asWedit + extensions//", false)
317        || publicId.startsWith("-//AS//DTD HTML 3.0 asWedit + extensions//", false)
318        || publicId.startsWith("-//IETF//DTD HTML 2.0 Level 1//", false)
319        || publicId.startsWith("-//IETF//DTD HTML 2.0 Level 2//", false)
320        || publicId.startsWith("-//IETF//DTD HTML 2.0 Strict Level 1//", false)
321        || publicId.startsWith("-//IETF//DTD HTML 2.0 Strict Level 2//", false)
322        || publicId.startsWith("-//IETF//DTD HTML 2.0 Strict//", false)
323        || publicId.startsWith("-//IETF//DTD HTML 2.0//", false)
324        || publicId.startsWith("-//IETF//DTD HTML 2.1E//", false)
325        || publicId.startsWith("-//IETF//DTD HTML 3.0//", false)
326        || publicId.startsWith("-//IETF//DTD HTML 3.2 Final//", false)
327        || publicId.startsWith("-//IETF//DTD HTML 3.2//", false)
328        || publicId.startsWith("-//IETF//DTD HTML 3//", false)
329        || publicId.startsWith("-//IETF//DTD HTML Level 0//", false)
330        || publicId.startsWith("-//IETF//DTD HTML Level 1//", false)
331        || publicId.startsWith("-//IETF//DTD HTML Level 2//", false)
332        || publicId.startsWith("-//IETF//DTD HTML Level 3//", false)
333        || publicId.startsWith("-//IETF//DTD HTML Strict Level 0//", false)
334        || publicId.startsWith("-//IETF//DTD HTML Strict Level 1//", false)
335        || publicId.startsWith("-//IETF//DTD HTML Strict Level 2//", false)
336        || publicId.startsWith("-//IETF//DTD HTML Strict Level 3//", false)
337        || publicId.startsWith("-//IETF//DTD HTML Strict//", false)
338        || publicId.startsWith("-//IETF//DTD HTML//", false)
339        || publicId.startsWith("-//Metrius//DTD Metrius Presentational//", false)
340        || publicId.startsWith("-//Microsoft//DTD Internet Explorer 2.0 HTML Strict//", false)
341        || publicId.startsWith("-//Microsoft//DTD Internet Explorer 2.0 HTML//", false)
342        || publicId.startsWith("-//Microsoft//DTD Internet Explorer 2.0 Tables//", false)
343        || publicId.startsWith("-//Microsoft//DTD Internet Explorer 3.0 HTML Strict//", false)
344        || publicId.startsWith("-//Microsoft//DTD Internet Explorer 3.0 HTML//", false)
345        || publicId.startsWith("-//Microsoft//DTD Internet Explorer 3.0 Tables//", false)
346        || publicId.startsWith("-//Netscape Comm. Corp.//DTD HTML//", false)
347        || publicId.startsWith("-//Netscape Comm. Corp.//DTD Strict HTML//", false)
348        || publicId.startsWith("-//O'Reilly and Associates//DTD HTML 2.0//", false)
349        || publicId.startsWith("-//O'Reilly and Associates//DTD HTML Extended 1.0//", false)
350        || publicId.startsWith("-//O'Reilly and Associates//DTD HTML Extended Relaxed 1.0//", false)
351        || publicId.startsWith("-//SoftQuad Software//DTD HoTMetaL PRO 6.0::19990601::extensions to HTML 4.0//", false)
352        || publicId.startsWith("-//SoftQuad//DTD HoTMetaL PRO 4.0::19971010::extensions to HTML 4.0//", false)
353        || publicId.startsWith("-//Spyglass//DTD HTML 2.0 Extended//", false)
354        || publicId.startsWith("-//SQ//DTD HTML 2.0 HoTMetaL + extensions//", false)
355        || publicId.startsWith("-//Sun Microsystems Corp.//DTD HotJava HTML//", false)
356        || publicId.startsWith("-//Sun Microsystems Corp.//DTD HotJava Strict HTML//", false)
357        || publicId.startsWith("-//W3C//DTD HTML 3 1995-03-24//", false)
358        || publicId.startsWith("-//W3C//DTD HTML 3.2 Draft//", false)
359        || publicId.startsWith("-//W3C//DTD HTML 3.2 Final//", false)
360        || publicId.startsWith("-//W3C//DTD HTML 3.2//", false)
361        || publicId.startsWith("-//W3C//DTD HTML 3.2S Draft//", false)
362        || publicId.startsWith("-//W3C//DTD HTML 4.0 Frameset//", false)
363        || publicId.startsWith("-//W3C//DTD HTML 4.0 Transitional//", false)
364        || publicId.startsWith("-//W3C//DTD HTML Experimental 19960712//", false)
365        || publicId.startsWith("-//W3C//DTD HTML Experimental 970421//", false)
366        || publicId.startsWith("-//W3C//DTD W3 HTML//", false)
367        || publicId.startsWith("-//W3O//DTD W3 HTML 3.0//", false)
368        || equalIgnoringCase(publicId, "-//W3O//DTD W3 HTML Strict 3.0//EN//")
369        || publicId.startsWith("-//WebTechs//DTD Mozilla HTML 2.0//", false)
370        || publicId.startsWith("-//WebTechs//DTD Mozilla HTML//", false)
371        || equalIgnoringCase(publicId, "-/W3C/DTD HTML 4.0 Transitional/EN")
372        || equalIgnoringCase(publicId, "HTML")
373        || equalIgnoringCase(systemId, "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd")
374        || (systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Frameset//", false))
375        || (systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Transitional//", false))) {
376        setCompatibilityMode(DocumentCompatibilityMode::QuirksMode);
377        return;
378    }
379
380    // Check for Limited Quirks Mode.
381    if (publicId.startsWith("-//W3C//DTD XHTML 1.0 Frameset//", false)
382        || publicId.startsWith("-//W3C//DTD XHTML 1.0 Transitional//", false)
383        || (!systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Frameset//", false))
384        || (!systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Transitional//", false))) {
385        setCompatibilityMode(DocumentCompatibilityMode::LimitedQuirksMode);
386        return;
387    }
388
389    // Otherwise we are No Quirks Mode.
390    setCompatibilityMode(DocumentCompatibilityMode::NoQuirksMode);
391}
392
393void HTMLConstructionSite::finishedParsing()
394{
395    m_document->finishedParsing();
396}
397
398void HTMLConstructionSite::insertDoctype(AtomicHTMLToken* token)
399{
400    ASSERT(token->type() == HTMLToken::DOCTYPE);
401
402    const String& publicId = StringImpl::create8BitIfPossible(token->publicIdentifier());
403    const String& systemId = StringImpl::create8BitIfPossible(token->systemIdentifier());
404    RefPtr<DocumentType> doctype = DocumentType::create(*m_document, token->name(), publicId, systemId);
405    attachLater(m_attachmentRoot, doctype.release());
406
407    // DOCTYPE nodes are only processed when parsing fragments w/o contextElements, which
408    // never occurs.  However, if we ever chose to support such, this code is subtly wrong,
409    // because context-less fragments can determine their own quirks mode, and thus change
410    // parsing rules (like <p> inside <table>).  For now we ASSERT that we never hit this code
411    // in a fragment, as changing the owning document's compatibility mode would be wrong.
412    ASSERT(!m_isParsingFragment);
413    if (m_isParsingFragment)
414        return;
415
416    if (token->forceQuirks())
417        setCompatibilityMode(DocumentCompatibilityMode::QuirksMode);
418    else {
419        setCompatibilityModeFromDoctype(token->name(), publicId, systemId);
420    }
421}
422
423void HTMLConstructionSite::insertComment(AtomicHTMLToken* token)
424{
425    ASSERT(token->type() == HTMLToken::Comment);
426    attachLater(currentNode(), Comment::create(ownerDocumentForCurrentNode(), token->comment()));
427}
428
429void HTMLConstructionSite::insertCommentOnDocument(AtomicHTMLToken* token)
430{
431    ASSERT(token->type() == HTMLToken::Comment);
432    attachLater(m_attachmentRoot, Comment::create(*m_document, token->comment()));
433}
434
435void HTMLConstructionSite::insertCommentOnHTMLHtmlElement(AtomicHTMLToken* token)
436{
437    ASSERT(token->type() == HTMLToken::Comment);
438    ContainerNode* parent = m_openElements.rootNode();
439    attachLater(parent, Comment::create(parent->document(), token->comment()));
440}
441
442void HTMLConstructionSite::insertHTMLHeadElement(AtomicHTMLToken* token)
443{
444    ASSERT(!shouldFosterParent());
445    m_head = HTMLStackItem::create(createHTMLElement(token), token);
446    attachLater(currentNode(), m_head->element());
447    m_openElements.pushHTMLHeadElement(m_head);
448}
449
450void HTMLConstructionSite::insertHTMLBodyElement(AtomicHTMLToken* token)
451{
452    ASSERT(!shouldFosterParent());
453    RefPtr<Element> body = createHTMLElement(token);
454    attachLater(currentNode(), body);
455    m_openElements.pushHTMLBodyElement(HTMLStackItem::create(body.release(), token));
456}
457
458void HTMLConstructionSite::insertHTMLFormElement(AtomicHTMLToken* token, bool isDemoted)
459{
460    RefPtr<Element> element = createHTMLElement(token);
461    ASSERT(isHTMLFormElement(element.get()));
462    RefPtr<HTMLFormElement> form = static_pointer_cast<HTMLFormElement>(element.release());
463    if (!insideTemplateElement())
464        m_form = form;
465    form->setDemoted(isDemoted);
466    attachLater(currentNode(), form);
467    m_openElements.push(HTMLStackItem::create(form.release(), token));
468}
469
470void HTMLConstructionSite::insertHTMLElement(AtomicHTMLToken* token)
471{
472    RefPtr<Element> element = createHTMLElement(token);
473    attachLater(currentNode(), element);
474    m_openElements.push(HTMLStackItem::create(element.release(), token));
475}
476
477void HTMLConstructionSite::insertSelfClosingHTMLElement(AtomicHTMLToken* token)
478{
479    ASSERT(token->type() == HTMLToken::StartTag);
480    // Normally HTMLElementStack is responsible for calling finishParsingChildren,
481    // but self-closing elements are never in the element stack so the stack
482    // doesn't get a chance to tell them that we're done parsing their children.
483    attachLater(currentNode(), createHTMLElement(token), true);
484    // FIXME: Do we want to acknowledge the token's self-closing flag?
485    // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#acknowledge-self-closing-flag
486}
487
488void HTMLConstructionSite::insertFormattingElement(AtomicHTMLToken* token)
489{
490    // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#the-stack-of-open-elements
491    // Possible active formatting elements include:
492    // a, b, big, code, em, font, i, nobr, s, small, strike, strong, tt, and u.
493    insertHTMLElement(token);
494    m_activeFormattingElements.append(currentElementRecord()->stackItem());
495}
496
497void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken* token)
498{
499    // http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#already-started
500    // http://html5.org/specs/dom-parsing.html#dom-range-createcontextualfragment
501    // For createContextualFragment, the specifications say to mark it parser-inserted and already-started and later unmark them.
502    // However, we short circuit that logic to avoid the subtree traversal to find script elements since scripts can never see
503    // those flags or effects thereof.
504    const bool parserInserted = m_parserContentPolicy != AllowScriptingContentAndDoNotMarkAlreadyStarted;
505    const bool alreadyStarted = m_isParsingFragment && parserInserted;
506    RefPtr<HTMLScriptElement> element = HTMLScriptElement::create(scriptTag, ownerDocumentForCurrentNode(), parserInserted, alreadyStarted);
507    setAttributes(element.get(), token, m_parserContentPolicy);
508    if (scriptingContentIsAllowed(m_parserContentPolicy))
509        attachLater(currentNode(), element);
510    m_openElements.push(HTMLStackItem::create(element.release(), token));
511}
512
513void HTMLConstructionSite::insertForeignElement(AtomicHTMLToken* token, const AtomicString& namespaceURI)
514{
515    ASSERT(token->type() == HTMLToken::StartTag);
516    notImplemented(); // parseError when xmlns or xmlns:xlink are wrong.
517
518    RefPtr<Element> element = createElement(token, namespaceURI);
519    if (scriptingContentIsAllowed(m_parserContentPolicy) || !toScriptElementIfPossible(element.get()))
520        attachLater(currentNode(), element, token->selfClosing());
521    if (!token->selfClosing())
522        m_openElements.push(HTMLStackItem::create(element.release(), token, namespaceURI));
523}
524
525void HTMLConstructionSite::insertTextNode(const String& characters, WhitespaceMode whitespaceMode)
526{
527    HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert);
528    task.parent = currentNode();
529
530    if (shouldFosterParent())
531        findFosterSite(task);
532
533#if ENABLE(TEMPLATE_ELEMENT)
534    if (task.parent->hasTagName(templateTag))
535        task.parent = toHTMLTemplateElement(task.parent.get())->content();
536#endif
537
538    // Strings composed entirely of whitespace are likely to be repeated.
539    // Turn them into AtomicString so we share a single string for each.
540    bool shouldUseAtomicString = whitespaceMode == AllWhitespace
541        || (whitespaceMode == WhitespaceUnknown && isAllWhitespace(characters));
542
543    unsigned currentPosition = 0;
544    unsigned lengthLimit = shouldUseLengthLimit(task.parent.get()) ? Text::defaultLengthLimit : std::numeric_limits<unsigned>::max();
545
546    // FIXME: Splitting text nodes into smaller chunks contradicts HTML5 spec, but is currently necessary
547    // for performance, see <https://bugs.webkit.org/show_bug.cgi?id=55898>.
548
549    Node* previousChild = task.nextChild ? task.nextChild->previousSibling() : task.parent->lastChild();
550    if (previousChild && previousChild->isTextNode()) {
551        // FIXME: We're only supposed to append to this text node if it
552        // was the last text node inserted by the parser.
553        Text* textNode = toText(previousChild);
554        currentPosition = textNode->parserAppendData(characters, 0, lengthLimit);
555    }
556
557    while (currentPosition < characters.length()) {
558        RefPtr<Text> textNode = Text::createWithLengthLimit(task.parent->document(), shouldUseAtomicString ? AtomicString(characters).string() : characters, currentPosition, lengthLimit);
559        // If we have a whole string of unbreakable characters the above could lead to an infinite loop. Exceeding the length limit is the lesser evil.
560        if (!textNode->length()) {
561            String substring = characters.substring(currentPosition);
562            textNode = Text::create(task.parent->document(), shouldUseAtomicString ? AtomicString(substring).string() : substring);
563        }
564
565        currentPosition += textNode->length();
566        ASSERT(currentPosition <= characters.length());
567        task.child = textNode.release();
568
569        executeTask(task);
570    }
571}
572
573void HTMLConstructionSite::reparent(HTMLElementStack::ElementRecord& newParent, HTMLElementStack::ElementRecord& child)
574{
575    HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Reparent);
576    task.parent = newParent.node();
577    task.child = child.element();
578    m_taskQueue.append(task);
579}
580
581void HTMLConstructionSite::reparent(HTMLElementStack::ElementRecord& newParent, HTMLStackItem& child)
582{
583    HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Reparent);
584    task.parent = newParent.node();
585    task.child = child.element();
586    m_taskQueue.append(task);
587}
588
589void HTMLConstructionSite::insertAlreadyParsedChild(HTMLStackItem& newParent, HTMLElementStack::ElementRecord& child)
590{
591    if (newParent.causesFosterParenting()) {
592        fosterParent(child.element());
593        return;
594    }
595
596    HTMLConstructionSiteTask task(HTMLConstructionSiteTask::InsertAlreadyParsedChild);
597    task.parent = newParent.node();
598    task.child = child.element();
599    m_taskQueue.append(task);
600}
601
602void HTMLConstructionSite::takeAllChildren(HTMLStackItem& newParent, HTMLElementStack::ElementRecord& oldParent)
603{
604    HTMLConstructionSiteTask task(HTMLConstructionSiteTask::TakeAllChildren);
605    task.parent = newParent.node();
606    task.child = oldParent.node();
607    m_taskQueue.append(task);
608}
609
610PassRefPtr<Element> HTMLConstructionSite::createElement(AtomicHTMLToken* token, const AtomicString& namespaceURI)
611{
612    QualifiedName tagName(nullAtom, token->name(), namespaceURI);
613    RefPtr<Element> element = ownerDocumentForCurrentNode().createElement(tagName, true);
614    setAttributes(element.get(), token, m_parserContentPolicy);
615    return element.release();
616}
617
618inline Document& HTMLConstructionSite::ownerDocumentForCurrentNode()
619{
620#if ENABLE(TEMPLATE_ELEMENT)
621    if (currentNode()->hasTagName(templateTag))
622        return toHTMLTemplateElement(currentElement())->content()->document();
623#endif
624    return currentNode()->document();
625}
626
627inline bool HTMLConstructionSite::insideTemplateElement()
628{
629    return !ownerDocumentForCurrentNode().frame();
630}
631
632PassRefPtr<Element> HTMLConstructionSite::createHTMLElement(AtomicHTMLToken* token)
633{
634    QualifiedName tagName(nullAtom, token->name(), xhtmlNamespaceURI);
635    // FIXME: This can't use HTMLConstructionSite::createElement because we
636    // have to pass the current form element.  We should rework form association
637    // to occur after construction to allow better code sharing here.
638    // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#create-an-element-for-the-token
639    Document& ownerDocument = ownerDocumentForCurrentNode();
640    bool insideTemplateElement = !ownerDocument.frame();
641    RefPtr<Element> element = HTMLElementFactory::createElement(tagName, ownerDocument, insideTemplateElement ? nullptr : form(), true);
642    setAttributes(element.get(), token, m_parserContentPolicy);
643    ASSERT(element->isHTMLElement());
644    return element.release();
645}
646
647PassRefPtr<HTMLStackItem> HTMLConstructionSite::createElementFromSavedToken(HTMLStackItem* item)
648{
649    RefPtr<Element> element;
650    // NOTE: Moving from item -> token -> item copies the Attribute vector twice!
651    AtomicHTMLToken fakeToken(HTMLToken::StartTag, item->localName(), item->attributes());
652    if (item->namespaceURI() == HTMLNames::xhtmlNamespaceURI)
653        element = createHTMLElement(&fakeToken);
654    else
655        element = createElement(&fakeToken, item->namespaceURI());
656    return HTMLStackItem::create(element.release(), &fakeToken, item->namespaceURI());
657}
658
659bool HTMLConstructionSite::indexOfFirstUnopenFormattingElement(unsigned& firstUnopenElementIndex) const
660{
661    if (m_activeFormattingElements.isEmpty())
662        return false;
663    unsigned index = m_activeFormattingElements.size();
664    do {
665        --index;
666        const HTMLFormattingElementList::Entry& entry = m_activeFormattingElements.at(index);
667        if (entry.isMarker() || m_openElements.contains(entry.element())) {
668            firstUnopenElementIndex = index + 1;
669            return firstUnopenElementIndex < m_activeFormattingElements.size();
670        }
671    } while (index);
672    firstUnopenElementIndex = index;
673    return true;
674}
675
676void HTMLConstructionSite::reconstructTheActiveFormattingElements()
677{
678    unsigned firstUnopenElementIndex;
679    if (!indexOfFirstUnopenFormattingElement(firstUnopenElementIndex))
680        return;
681
682    unsigned unopenEntryIndex = firstUnopenElementIndex;
683    ASSERT(unopenEntryIndex < m_activeFormattingElements.size());
684    for (; unopenEntryIndex < m_activeFormattingElements.size(); ++unopenEntryIndex) {
685        HTMLFormattingElementList::Entry& unopenedEntry = m_activeFormattingElements.at(unopenEntryIndex);
686        RefPtr<HTMLStackItem> reconstructed = createElementFromSavedToken(unopenedEntry.stackItem().get());
687        attachLater(currentNode(), reconstructed->node());
688        m_openElements.push(reconstructed);
689        unopenedEntry.replaceElement(reconstructed.release());
690    }
691}
692
693void HTMLConstructionSite::generateImpliedEndTagsWithExclusion(const AtomicString& tagName)
694{
695    while (hasImpliedEndTag(currentStackItem()) && !currentStackItem()->matchesHTMLTag(tagName))
696        m_openElements.pop();
697}
698
699void HTMLConstructionSite::generateImpliedEndTags()
700{
701    while (hasImpliedEndTag(currentStackItem()))
702        m_openElements.pop();
703}
704
705bool HTMLConstructionSite::inQuirksMode()
706{
707    return m_inQuirksMode;
708}
709
710void HTMLConstructionSite::findFosterSite(HTMLConstructionSiteTask& task)
711{
712#if ENABLE(TEMPLATE_ELEMENT)
713    // When a node is to be foster parented, the last template element with no table element is below it in the stack of open elements is the foster parent element (NOT the template's parent!)
714    HTMLElementStack::ElementRecord* lastTemplateElement = m_openElements.topmost(templateTag.localName());
715    if (lastTemplateElement && !m_openElements.inTableScope(tableTag)) {
716        task.parent = lastTemplateElement->element();
717        return;
718    }
719
720#endif
721
722    HTMLElementStack::ElementRecord* lastTableElementRecord = m_openElements.topmost(tableTag.localName());
723    if (lastTableElementRecord) {
724        Element* lastTableElement = lastTableElementRecord->element();
725        ContainerNode* parent = lastTableElement->parentNode();
726        // When parsing HTML fragments, we skip step 4.2 ("Let root be a new html element with no attributes") for efficiency,
727        // and instead use the DocumentFragment as a root node. So we must treat the root node (DocumentFragment) as if it is a html element here.
728        bool parentCanBeFosterParent = parent && (parent->isElementNode() || (m_isParsingFragment && parent == m_openElements.rootNode()));
729#if ENABLE(TEMPLATE_ELEMENT)
730        parentCanBeFosterParent = parentCanBeFosterParent || (parent && parent->isDocumentFragment() && toDocumentFragment(parent)->isTemplateContent());
731#endif
732        if (parentCanBeFosterParent) {
733            task.parent = parent;
734            task.nextChild = lastTableElement;
735            return;
736        }
737        task.parent = lastTableElementRecord->next()->element();
738        return;
739    }
740    // Fragment case
741    task.parent = m_openElements.rootNode(); // DocumentFragment
742}
743
744bool HTMLConstructionSite::shouldFosterParent() const
745{
746    return m_redirectAttachToFosterParent
747        && currentStackItem()->isElementNode()
748        && currentStackItem()->causesFosterParenting();
749}
750
751void HTMLConstructionSite::fosterParent(PassRefPtr<Node> node)
752{
753    HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert);
754    findFosterSite(task);
755    task.child = node;
756    ASSERT(task.parent);
757
758    m_taskQueue.append(task);
759}
760
761}
762