[HTMLTemplateElement] <template> should be able to be a foster parent
[WebKit-https.git] / Source / WebCore / html / parser / HTMLConstructionSite.cpp
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 "AtomicHTMLToken.h"
31 #include "Comment.h"
32 #include "DocumentFragment.h"
33 #include "DocumentType.h"
34 #include "Element.h"
35 #include "Frame.h"
36 #include "FrameLoader.h"
37 #include "FrameLoaderClient.h"
38 #include "HTMLDocument.h"
39 #include "HTMLElementFactory.h"
40 #include "HTMLFormElement.h"
41 #include "HTMLHtmlElement.h"
42 #include "HTMLNames.h"
43 #include "HTMLParserIdioms.h"
44 #include "HTMLPlugInElement.h"
45 #include "HTMLScriptElement.h"
46 #include "HTMLStackItem.h"
47 #include "HTMLTemplateElement.h"
48 #include "HTMLToken.h"
49 #include "HTMLTokenizer.h"
50 #include "LocalizedStrings.h"
51 #include "NotImplemented.h"
52 #include "Settings.h"
53 #include "Text.h"
54 #include <wtf/UnusedParam.h>
55
56 namespace WebCore {
57
58 using namespace HTMLNames;
59
60 static inline void setAttributes(Element* element, AtomicHTMLToken* token, ParserContentPolicy parserContentPolicy)
61 {
62     if (!scriptingContentIsAllowed(parserContentPolicy))
63         element->stripJavaScriptAttributes(token->attributes());
64     element->parserSetAttributes(token->attributes());
65 }
66
67 static bool hasImpliedEndTag(const HTMLStackItem* item)
68 {
69     return item->hasTagName(ddTag)
70         || item->hasTagName(dtTag)
71         || item->hasTagName(liTag)
72         || item->hasTagName(optionTag)
73         || item->hasTagName(optgroupTag)
74         || item->hasTagName(pTag)
75         || item->hasTagName(rpTag)
76         || item->hasTagName(rtTag);
77 }
78
79 static inline bool isAllWhitespace(const String& string)
80 {
81     return string.isAllSpecialCharacters<isHTMLSpace>();
82 }
83
84 static inline void executeTask(HTMLConstructionSiteTask& task)
85 {
86 #if ENABLE(TEMPLATE_ELEMENT)
87     if (task.parent->hasTagName(templateTag))
88         task.parent = toHTMLTemplateElement(task.parent.get())->content();
89 #endif
90
91     if (task.nextChild)
92         task.parent->parserInsertBefore(task.child.get(), task.nextChild.get());
93     else
94         task.parent->parserAppendChild(task.child.get());
95
96     // JavaScript run from beforeload (or DOM Mutation or event handlers)
97     // might have removed the child, in which case we should not attach it.
98
99     if (task.child->parentNode() && task.parent->attached() && !task.child->attached())
100         task.child->attach();
101
102     task.child->beginParsingChildren();
103
104     if (task.selfClosing)
105         task.child->finishParsingChildren();
106 }
107
108 void HTMLConstructionSite::attachLater(ContainerNode* parent, PassRefPtr<Node> prpChild, bool selfClosing)
109 {
110     ASSERT(scriptingContentIsAllowed(m_parserContentPolicy) || !prpChild.get()->isElementNode() || !toScriptElementIfPossible(toElement(prpChild.get())));
111     ASSERT(pluginContentIsAllowed(m_parserContentPolicy) || !prpChild->isPluginElement());
112
113     HTMLConstructionSiteTask task;
114     task.parent = parent;
115     task.child = prpChild;
116     task.selfClosing = selfClosing;
117
118     if (shouldFosterParent()) {
119         fosterParent(task.child);
120         return;
121     }
122
123     // Add as a sibling of the parent if we have reached the maximum depth allowed.
124     if (m_openElements.stackDepth() > m_maximumDOMTreeDepth && task.parent->parentNode())
125         task.parent = task.parent->parentNode();
126
127     ASSERT(task.parent);
128     m_attachmentQueue.append(task);
129 }
130
131 void HTMLConstructionSite::executeQueuedTasks()
132 {
133     const size_t size = m_attachmentQueue.size();
134     if (!size)
135         return;
136
137     // Copy the task queue into a local variable in case executeTask
138     // re-enters the parser.
139     AttachmentQueue queue;
140     queue.swap(m_attachmentQueue);
141
142     for (size_t i = 0; i < size; ++i)
143         executeTask(queue[i]);
144
145     // We might be detached now.
146 }
147
148 HTMLConstructionSite::HTMLConstructionSite(Document* document, ParserContentPolicy parserContentPolicy, unsigned maximumDOMTreeDepth)
149     : m_document(document)
150     , m_attachmentRoot(document)
151     , m_parserContentPolicy(parserContentPolicy)
152     , m_isParsingFragment(false)
153     , m_redirectAttachToFosterParent(false)
154     , m_maximumDOMTreeDepth(maximumDOMTreeDepth)
155     , m_inQuirksMode(document->inQuirksMode())
156 {
157     ASSERT(m_document->isHTMLDocument() || m_document->isXHTMLDocument());
158 }
159
160 HTMLConstructionSite::HTMLConstructionSite(DocumentFragment* fragment, ParserContentPolicy parserContentPolicy, unsigned maximumDOMTreeDepth)
161     : m_document(fragment->document())
162     , m_attachmentRoot(fragment)
163     , m_parserContentPolicy(parserContentPolicy)
164     , m_isParsingFragment(true)
165     , m_redirectAttachToFosterParent(false)
166     , m_maximumDOMTreeDepth(maximumDOMTreeDepth)
167     , m_inQuirksMode(fragment->document()->inQuirksMode())
168 {
169     ASSERT(m_document->isHTMLDocument() || m_document->isXHTMLDocument());
170 }
171
172 HTMLConstructionSite::~HTMLConstructionSite()
173 {
174 }
175
176 void HTMLConstructionSite::detach()
177 {
178     m_document = 0;
179     m_attachmentRoot = 0;
180 }
181
182 void HTMLConstructionSite::setForm(HTMLFormElement* form)
183 {
184     // This method should only be needed for HTMLTreeBuilder in the fragment case.
185     ASSERT(!m_form);
186     m_form = form;
187 }
188
189 PassRefPtr<HTMLFormElement> HTMLConstructionSite::takeForm()
190 {
191     return m_form.release();
192 }
193
194 void HTMLConstructionSite::dispatchDocumentElementAvailableIfNeeded()
195 {
196     ASSERT(m_document);
197     if (m_document->frame() && !m_isParsingFragment)
198         m_document->frame()->loader()->dispatchDocumentElementAvailable();
199 }
200
201 void HTMLConstructionSite::insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken* token)
202 {
203     RefPtr<HTMLHtmlElement> element = HTMLHtmlElement::create(m_document);
204     setAttributes(element.get(), token, m_parserContentPolicy);
205     attachLater(m_attachmentRoot, element);
206     m_openElements.pushHTMLHtmlElement(HTMLStackItem::create(element, token));
207
208     executeQueuedTasks();
209     element->insertedByParser();
210     dispatchDocumentElementAvailableIfNeeded();
211 }
212
213 void HTMLConstructionSite::mergeAttributesFromTokenIntoElement(AtomicHTMLToken* token, Element* element)
214 {
215     if (token->attributes().isEmpty())
216         return;
217
218     for (unsigned i = 0; i < token->attributes().size(); ++i) {
219         const Attribute& tokenAttribute = token->attributes().at(i);
220         if (!element->elementData() || !element->getAttributeItem(tokenAttribute.name()))
221             element->setAttribute(tokenAttribute.name(), tokenAttribute.value());
222     }
223 }
224
225 void HTMLConstructionSite::insertHTMLHtmlStartTagInBody(AtomicHTMLToken* token)
226 {
227     // Fragments do not have a root HTML element, so any additional HTML elements
228     // encountered during fragment parsing should be ignored.
229     if (m_isParsingFragment)
230         return;
231
232     mergeAttributesFromTokenIntoElement(token, m_openElements.htmlElement());
233 }
234
235 void HTMLConstructionSite::insertHTMLBodyStartTagInBody(AtomicHTMLToken* token)
236 {
237     mergeAttributesFromTokenIntoElement(token, m_openElements.bodyElement());
238 }
239
240 void HTMLConstructionSite::setDefaultCompatibilityMode()
241 {
242     if (m_isParsingFragment)
243         return;
244     if (m_document->isSrcdocDocument())
245         return;
246     setCompatibilityMode(Document::QuirksMode);
247 }
248
249 void HTMLConstructionSite::setCompatibilityMode(Document::CompatibilityMode mode)
250 {
251     m_inQuirksMode = (mode == Document::QuirksMode);
252     m_document->setCompatibilityMode(mode);
253 }
254
255 void HTMLConstructionSite::setCompatibilityModeFromDoctype(const String& name, const String& publicId, const String& systemId)
256 {
257     // There are three possible compatibility modes:
258     // Quirks - quirks mode emulates WinIE and NS4. CSS parsing is also relaxed in this mode, e.g., unit types can
259     // be omitted from numbers.
260     // Limited Quirks - This mode is identical to no-quirks mode except for its treatment of line-height in the inline box model.  
261     // No Quirks - no quirks apply. Web pages will obey the specifications to the letter.
262
263     // Check for Quirks Mode.
264     if (name != "html"
265         || publicId.startsWith("+//Silmaril//dtd html Pro v0r11 19970101//", false)
266         || publicId.startsWith("-//AdvaSoft Ltd//DTD HTML 3.0 asWedit + extensions//", false)
267         || publicId.startsWith("-//AS//DTD HTML 3.0 asWedit + extensions//", false)
268         || publicId.startsWith("-//IETF//DTD HTML 2.0 Level 1//", false)
269         || publicId.startsWith("-//IETF//DTD HTML 2.0 Level 2//", false)
270         || publicId.startsWith("-//IETF//DTD HTML 2.0 Strict Level 1//", false)
271         || publicId.startsWith("-//IETF//DTD HTML 2.0 Strict Level 2//", false)
272         || publicId.startsWith("-//IETF//DTD HTML 2.0 Strict//", false)
273         || publicId.startsWith("-//IETF//DTD HTML 2.0//", false)
274         || publicId.startsWith("-//IETF//DTD HTML 2.1E//", false)
275         || publicId.startsWith("-//IETF//DTD HTML 3.0//", false)
276         || publicId.startsWith("-//IETF//DTD HTML 3.2 Final//", false)
277         || publicId.startsWith("-//IETF//DTD HTML 3.2//", false)
278         || publicId.startsWith("-//IETF//DTD HTML 3//", false)
279         || publicId.startsWith("-//IETF//DTD HTML Level 0//", false)
280         || publicId.startsWith("-//IETF//DTD HTML Level 1//", false)
281         || publicId.startsWith("-//IETF//DTD HTML Level 2//", false)
282         || publicId.startsWith("-//IETF//DTD HTML Level 3//", false)
283         || publicId.startsWith("-//IETF//DTD HTML Strict Level 0//", false)
284         || publicId.startsWith("-//IETF//DTD HTML Strict Level 1//", false)
285         || publicId.startsWith("-//IETF//DTD HTML Strict Level 2//", false)
286         || publicId.startsWith("-//IETF//DTD HTML Strict Level 3//", false)
287         || publicId.startsWith("-//IETF//DTD HTML Strict//", false)
288         || publicId.startsWith("-//IETF//DTD HTML//", false)
289         || publicId.startsWith("-//Metrius//DTD Metrius Presentational//", false)
290         || publicId.startsWith("-//Microsoft//DTD Internet Explorer 2.0 HTML Strict//", false)
291         || publicId.startsWith("-//Microsoft//DTD Internet Explorer 2.0 HTML//", false)
292         || publicId.startsWith("-//Microsoft//DTD Internet Explorer 2.0 Tables//", false)
293         || publicId.startsWith("-//Microsoft//DTD Internet Explorer 3.0 HTML Strict//", false)
294         || publicId.startsWith("-//Microsoft//DTD Internet Explorer 3.0 HTML//", false)
295         || publicId.startsWith("-//Microsoft//DTD Internet Explorer 3.0 Tables//", false)
296         || publicId.startsWith("-//Netscape Comm. Corp.//DTD HTML//", false)
297         || publicId.startsWith("-//Netscape Comm. Corp.//DTD Strict HTML//", false)
298         || publicId.startsWith("-//O'Reilly and Associates//DTD HTML 2.0//", false)
299         || publicId.startsWith("-//O'Reilly and Associates//DTD HTML Extended 1.0//", false)
300         || publicId.startsWith("-//O'Reilly and Associates//DTD HTML Extended Relaxed 1.0//", false)
301         || publicId.startsWith("-//SoftQuad Software//DTD HoTMetaL PRO 6.0::19990601::extensions to HTML 4.0//", false)
302         || publicId.startsWith("-//SoftQuad//DTD HoTMetaL PRO 4.0::19971010::extensions to HTML 4.0//", false)
303         || publicId.startsWith("-//Spyglass//DTD HTML 2.0 Extended//", false)
304         || publicId.startsWith("-//SQ//DTD HTML 2.0 HoTMetaL + extensions//", false)
305         || publicId.startsWith("-//Sun Microsystems Corp.//DTD HotJava HTML//", false)
306         || publicId.startsWith("-//Sun Microsystems Corp.//DTD HotJava Strict HTML//", false)
307         || publicId.startsWith("-//W3C//DTD HTML 3 1995-03-24//", false)
308         || publicId.startsWith("-//W3C//DTD HTML 3.2 Draft//", false)
309         || publicId.startsWith("-//W3C//DTD HTML 3.2 Final//", false)
310         || publicId.startsWith("-//W3C//DTD HTML 3.2//", false)
311         || publicId.startsWith("-//W3C//DTD HTML 3.2S Draft//", false)
312         || publicId.startsWith("-//W3C//DTD HTML 4.0 Frameset//", false)
313         || publicId.startsWith("-//W3C//DTD HTML 4.0 Transitional//", false)
314         || publicId.startsWith("-//W3C//DTD HTML Experimental 19960712//", false)
315         || publicId.startsWith("-//W3C//DTD HTML Experimental 970421//", false)
316         || publicId.startsWith("-//W3C//DTD W3 HTML//", false)
317         || publicId.startsWith("-//W3O//DTD W3 HTML 3.0//", false)
318         || equalIgnoringCase(publicId, "-//W3O//DTD W3 HTML Strict 3.0//EN//")
319         || publicId.startsWith("-//WebTechs//DTD Mozilla HTML 2.0//", false)
320         || publicId.startsWith("-//WebTechs//DTD Mozilla HTML//", false)
321         || equalIgnoringCase(publicId, "-/W3C/DTD HTML 4.0 Transitional/EN")
322         || equalIgnoringCase(publicId, "HTML")
323         || equalIgnoringCase(systemId, "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd")
324         || (systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Frameset//", false))
325         || (systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Transitional//", false))) {
326         setCompatibilityMode(Document::QuirksMode);
327         return;
328     }
329
330     // Check for Limited Quirks Mode.
331     if (publicId.startsWith("-//W3C//DTD XHTML 1.0 Frameset//", false)
332         || publicId.startsWith("-//W3C//DTD XHTML 1.0 Transitional//", false)
333         || (!systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Frameset//", false))
334         || (!systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Transitional//", false))) {
335         setCompatibilityMode(Document::LimitedQuirksMode);
336         return;
337     }
338
339     // Otherwise we are No Quirks Mode.
340     setCompatibilityMode(Document::NoQuirksMode);
341 }
342
343 void HTMLConstructionSite::finishedParsing()
344 {
345     m_document->finishedParsing();
346 }
347
348 void HTMLConstructionSite::insertDoctype(AtomicHTMLToken* token)
349 {
350     ASSERT(token->type() == HTMLToken::DOCTYPE);
351
352     const String& publicId = String::adopt(token->publicIdentifier());
353     const String& systemId = String::adopt(token->systemIdentifier());
354     RefPtr<DocumentType> doctype = DocumentType::create(m_document, token->name(), publicId, systemId);
355     attachLater(m_attachmentRoot, doctype.release());
356
357     // DOCTYPE nodes are only processed when parsing fragments w/o contextElements, which
358     // never occurs.  However, if we ever chose to support such, this code is subtly wrong,
359     // because context-less fragments can determine their own quirks mode, and thus change
360     // parsing rules (like <p> inside <table>).  For now we ASSERT that we never hit this code
361     // in a fragment, as changing the owning document's compatibility mode would be wrong.
362     ASSERT(!m_isParsingFragment);
363     if (m_isParsingFragment)
364         return;
365
366     if (token->forceQuirks())
367         setCompatibilityMode(Document::QuirksMode);
368     else {
369         setCompatibilityModeFromDoctype(token->name(), publicId, systemId);
370     }
371 }
372
373 void HTMLConstructionSite::insertComment(AtomicHTMLToken* token)
374 {
375     ASSERT(token->type() == HTMLToken::Comment);
376     attachLater(currentNode(), Comment::create(ownerDocumentForCurrentNode(), token->comment()));
377 }
378
379 void HTMLConstructionSite::insertCommentOnDocument(AtomicHTMLToken* token)
380 {
381     ASSERT(token->type() == HTMLToken::Comment);
382     attachLater(m_attachmentRoot, Comment::create(m_document, token->comment()));
383 }
384
385 void HTMLConstructionSite::insertCommentOnHTMLHtmlElement(AtomicHTMLToken* token)
386 {
387     ASSERT(token->type() == HTMLToken::Comment);
388     ContainerNode* parent = m_openElements.rootNode();
389     attachLater(parent, Comment::create(parent->document(), token->comment()));
390 }
391
392 void HTMLConstructionSite::insertHTMLHeadElement(AtomicHTMLToken* token)
393 {
394     ASSERT(!shouldFosterParent());
395     m_head = HTMLStackItem::create(createHTMLElement(token), token);
396     attachLater(currentNode(), m_head->element());
397     m_openElements.pushHTMLHeadElement(m_head);
398 }
399
400 void HTMLConstructionSite::insertHTMLBodyElement(AtomicHTMLToken* token)
401 {
402     ASSERT(!shouldFosterParent());
403     RefPtr<Element> body = createHTMLElement(token);
404     attachLater(currentNode(), body);
405     m_openElements.pushHTMLBodyElement(HTMLStackItem::create(body.release(), token));
406     if (Frame* frame = m_document->frame())
407         frame->loader()->client()->dispatchWillInsertBody();
408 }
409
410 void HTMLConstructionSite::insertHTMLFormElement(AtomicHTMLToken* token, bool isDemoted)
411 {
412     RefPtr<Element> element = createHTMLElement(token);
413     ASSERT(element->hasTagName(formTag));
414     m_form = static_pointer_cast<HTMLFormElement>(element.release());
415     m_form->setDemoted(isDemoted);
416     attachLater(currentNode(), m_form);
417     m_openElements.push(HTMLStackItem::create(m_form, token));
418 }
419
420 void HTMLConstructionSite::insertHTMLElement(AtomicHTMLToken* token)
421 {
422     RefPtr<Element> element = createHTMLElement(token);
423     attachLater(currentNode(), element);
424     m_openElements.push(HTMLStackItem::create(element.release(), token));
425 }
426
427 void HTMLConstructionSite::insertSelfClosingHTMLElement(AtomicHTMLToken* token)
428 {
429     ASSERT(token->type() == HTMLToken::StartTag);
430     // Normally HTMLElementStack is responsible for calling finishParsingChildren,
431     // but self-closing elements are never in the element stack so the stack
432     // doesn't get a chance to tell them that we're done parsing their children.
433     attachLater(currentNode(), createHTMLElement(token), true);
434     // FIXME: Do we want to acknowledge the token's self-closing flag?
435     // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#acknowledge-self-closing-flag
436 }
437
438 void HTMLConstructionSite::insertFormattingElement(AtomicHTMLToken* token)
439 {
440     // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#the-stack-of-open-elements
441     // Possible active formatting elements include:
442     // a, b, big, code, em, font, i, nobr, s, small, strike, strong, tt, and u.
443     insertHTMLElement(token);
444     m_activeFormattingElements.append(currentElementRecord()->stackItem());
445 }
446
447 void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken* token)
448 {
449     // http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#already-started
450     // http://html5.org/specs/dom-parsing.html#dom-range-createcontextualfragment
451     // For createContextualFragment, the specifications say to mark it parser-inserted and already-started and later unmark them.
452     // However, we short circuit that logic to avoid the subtree traversal to find script elements since scripts can never see
453     // those flags or effects thereof.
454     const bool parserInserted = m_parserContentPolicy != AllowScriptingContentAndDoNotMarkAlreadyStarted;
455     const bool alreadyStarted = m_isParsingFragment && parserInserted;
456     RefPtr<HTMLScriptElement> element = HTMLScriptElement::create(scriptTag, ownerDocumentForCurrentNode(), parserInserted, alreadyStarted);
457     setAttributes(element.get(), token, m_parserContentPolicy);
458     if (scriptingContentIsAllowed(m_parserContentPolicy))
459         attachLater(currentNode(), element);
460     m_openElements.push(HTMLStackItem::create(element.release(), token));
461 }
462
463 void HTMLConstructionSite::insertForeignElement(AtomicHTMLToken* token, const AtomicString& namespaceURI)
464 {
465     ASSERT(token->type() == HTMLToken::StartTag);
466     notImplemented(); // parseError when xmlns or xmlns:xlink are wrong.
467
468     RefPtr<Element> element = createElement(token, namespaceURI);
469     if (scriptingContentIsAllowed(m_parserContentPolicy) || !toScriptElementIfPossible(element.get()))
470         attachLater(currentNode(), element, token->selfClosing());
471     if (!token->selfClosing())
472         m_openElements.push(HTMLStackItem::create(element.release(), token, namespaceURI));
473 }
474
475 void HTMLConstructionSite::insertTextNode(const String& characters, WhitespaceMode whitespaceMode)
476 {
477     HTMLConstructionSiteTask task;
478     task.parent = currentNode();
479
480     if (shouldFosterParent())
481         findFosterSite(task);
482
483 #if ENABLE(TEMPLATE_ELEMENT)
484     if (task.parent->hasTagName(templateTag))
485         task.parent = toHTMLTemplateElement(task.parent.get())->content();
486 #endif
487
488     // Strings composed entirely of whitespace are likely to be repeated.
489     // Turn them into AtomicString so we share a single string for each.
490     bool shouldUseAtomicString = whitespaceMode == AllWhitespace
491         || (whitespaceMode == WhitespaceUnknown && isAllWhitespace(characters));
492
493     unsigned currentPosition = 0;
494
495     // FIXME: Splitting text nodes into smaller chunks contradicts HTML5 spec, but is currently necessary
496     // for performance, see <https://bugs.webkit.org/show_bug.cgi?id=55898>.
497
498     Node* previousChild = task.nextChild ? task.nextChild->previousSibling() : task.parent->lastChild();
499     if (previousChild && previousChild->isTextNode()) {
500         // FIXME: We're only supposed to append to this text node if it
501         // was the last text node inserted by the parser.
502         CharacterData* textNode = static_cast<CharacterData*>(previousChild);
503         currentPosition = textNode->parserAppendData(characters, 0, Text::defaultLengthLimit);
504     }
505
506     while (currentPosition < characters.length()) {
507         RefPtr<Text> textNode = Text::createWithLengthLimit(task.parent->document(), shouldUseAtomicString ? AtomicString(characters).string() : characters, currentPosition);
508         // 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.
509         if (!textNode->length()) {
510             String substring = characters.substring(currentPosition);
511             textNode = Text::create(task.parent->document(), shouldUseAtomicString ? AtomicString(substring).string() : substring);
512         }
513
514         currentPosition += textNode->length();
515         ASSERT(currentPosition <= characters.length());
516         task.child = textNode.release();
517
518         executeTask(task);
519     }
520 }
521
522 PassRefPtr<Element> HTMLConstructionSite::createElement(AtomicHTMLToken* token, const AtomicString& namespaceURI)
523 {
524     QualifiedName tagName(nullAtom, token->name(), namespaceURI);
525     RefPtr<Element> element = ownerDocumentForCurrentNode()->createElement(tagName, true);
526     setAttributes(element.get(), token, m_parserContentPolicy);
527     return element.release();
528 }
529
530 inline Document* HTMLConstructionSite::ownerDocumentForCurrentNode()
531 {
532 #if ENABLE(TEMPLATE_ELEMENT)
533     if (currentNode()->hasTagName(templateTag))
534         return toHTMLTemplateElement(currentElement())->content()->document();
535 #endif
536     return currentNode()->document();
537 }
538
539 PassRefPtr<Element> HTMLConstructionSite::createHTMLElement(AtomicHTMLToken* token)
540 {
541     QualifiedName tagName(nullAtom, token->name(), xhtmlNamespaceURI);
542     // FIXME: This can't use HTMLConstructionSite::createElement because we
543     // have to pass the current form element.  We should rework form association
544     // to occur after construction to allow better code sharing here.
545     RefPtr<Element> element = HTMLElementFactory::createHTMLElement(tagName, ownerDocumentForCurrentNode(), form(), true);
546     setAttributes(element.get(), token, m_parserContentPolicy);
547     ASSERT(element->isHTMLElement());
548     return element.release();
549 }
550
551 PassRefPtr<HTMLStackItem> HTMLConstructionSite::createElementFromSavedToken(HTMLStackItem* item)
552 {
553     RefPtr<Element> element;
554     // NOTE: Moving from item -> token -> item copies the Attribute vector twice!
555     AtomicHTMLToken fakeToken(HTMLToken::StartTag, item->localName(), item->attributes());
556     if (item->namespaceURI() == HTMLNames::xhtmlNamespaceURI)
557         element = createHTMLElement(&fakeToken);
558     else
559         element = createElement(&fakeToken, item->namespaceURI());
560     return HTMLStackItem::create(element.release(), &fakeToken, item->namespaceURI());
561 }
562
563 bool HTMLConstructionSite::indexOfFirstUnopenFormattingElement(unsigned& firstUnopenElementIndex) const
564 {
565     if (m_activeFormattingElements.isEmpty())
566         return false;
567     unsigned index = m_activeFormattingElements.size();
568     do {
569         --index;
570         const HTMLFormattingElementList::Entry& entry = m_activeFormattingElements.at(index);
571         if (entry.isMarker() || m_openElements.contains(entry.element())) {
572             firstUnopenElementIndex = index + 1;
573             return firstUnopenElementIndex < m_activeFormattingElements.size();
574         }
575     } while (index);
576     firstUnopenElementIndex = index;
577     return true;
578 }
579
580 void HTMLConstructionSite::reconstructTheActiveFormattingElements()
581 {
582     unsigned firstUnopenElementIndex;
583     if (!indexOfFirstUnopenFormattingElement(firstUnopenElementIndex))
584         return;
585
586     unsigned unopenEntryIndex = firstUnopenElementIndex;
587     ASSERT(unopenEntryIndex < m_activeFormattingElements.size());
588     for (; unopenEntryIndex < m_activeFormattingElements.size(); ++unopenEntryIndex) {
589         HTMLFormattingElementList::Entry& unopenedEntry = m_activeFormattingElements.at(unopenEntryIndex);
590         RefPtr<HTMLStackItem> reconstructed = createElementFromSavedToken(unopenedEntry.stackItem().get());
591         attachLater(currentNode(), reconstructed->node());
592         m_openElements.push(reconstructed);
593         unopenedEntry.replaceElement(reconstructed.release());
594     }
595 }
596
597 void HTMLConstructionSite::generateImpliedEndTagsWithExclusion(const AtomicString& tagName)
598 {
599     while (hasImpliedEndTag(currentStackItem()) && !currentStackItem()->hasLocalName(tagName))
600         m_openElements.pop();
601 }
602
603 void HTMLConstructionSite::generateImpliedEndTags()
604 {
605     while (hasImpliedEndTag(currentStackItem()))
606         m_openElements.pop();
607 }
608
609 bool HTMLConstructionSite::inQuirksMode()
610 {
611     return m_inQuirksMode;
612 }
613
614 void HTMLConstructionSite::findFosterSite(HTMLConstructionSiteTask& task)
615 {
616 #if ENABLE(TEMPLATE_ELEMENT)
617     // 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!)
618     HTMLElementStack::ElementRecord* lastTemplateElement = m_openElements.topmost(templateTag.localName());
619     if (lastTemplateElement && !m_openElements.inTableScope(tableTag)) {
620         task.parent = lastTemplateElement->element();
621         return;
622     }
623
624 #endif
625
626     HTMLElementStack::ElementRecord* lastTableElementRecord = m_openElements.topmost(tableTag.localName());
627     if (lastTableElementRecord) {
628         Element* lastTableElement = lastTableElementRecord->element();
629         ContainerNode* parent = lastTableElement->parentNode();
630         // When parsing HTML fragments, we skip step 4.2 ("Let root be a new html element with no attributes") for efficiency,
631         // 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.
632         bool parentCanBeFosterParent = parent && (parent->isElementNode() || (m_isParsingFragment && parent == m_openElements.rootNode()));
633 #if ENABLE(TEMPLATE_ELEMENT)
634         parentCanBeFosterParent = parentCanBeFosterParent || (parent && parent->isDocumentFragment() && static_cast<DocumentFragment*>(parent)->isTemplateContent());
635 #endif
636         if (parentCanBeFosterParent) {
637             task.parent = parent;
638             task.nextChild = lastTableElement;
639             return;
640         }
641         task.parent = lastTableElementRecord->next()->element();
642         return;
643     }
644     // Fragment case
645     task.parent = m_openElements.rootNode(); // DocumentFragment
646 }
647
648 bool HTMLConstructionSite::shouldFosterParent() const
649 {
650     return m_redirectAttachToFosterParent
651         && currentStackItem()->isElementNode()
652         && currentStackItem()->causesFosterParenting();
653 }
654
655 void HTMLConstructionSite::fosterParent(PassRefPtr<Node> node)
656 {
657     HTMLConstructionSiteTask task;
658     findFosterSite(task);
659     task.child = node;
660     ASSERT(task.parent);
661
662     m_attachmentQueue.append(task);
663 }
664
665 }