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