350819b0b7c77f34c4a76a138eb416b6de25a27a
[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 isAllWhitespace(const String& string)
81 {
82     return string.isAllSpecialCharacters<isHTMLSpace>();
83 }
84
85 static inline void insert(HTMLConstructionSiteTask& task)
86 {
87 #if ENABLE(TEMPLATE_ELEMENT)
88     if (is<HTMLTemplateElement>(*task.parent))
89         task.parent = downcast<HTMLTemplateElement>(*task.parent).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
101 static 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
113 static 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
123 static inline void executeInsertAlreadyParsedChildTask(HTMLConstructionSiteTask& task)
124 {
125     ASSERT(task.operation == HTMLConstructionSiteTask::InsertAlreadyParsedChild);
126
127     insert(task);
128 }
129
130 static 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
139 static 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
159 void HTMLConstructionSite::attachLater(ContainerNode* parent, PassRefPtr<Node> prpChild, bool selfClosing)
160 {
161     ASSERT(scriptingContentIsAllowed(m_parserContentPolicy) || !is<Element>(*prpChild) || !toScriptElementIfPossible(downcast<Element>(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
182 void 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
198 HTMLConstructionSite::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
210 HTMLConstructionSite::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
222 HTMLConstructionSite::~HTMLConstructionSite()
223 {
224 }
225
226 void HTMLConstructionSite::detach()
227 {
228     m_document = 0;
229     m_attachmentRoot = 0;
230 }
231
232 void 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
239 PassRefPtr<HTMLFormElement> HTMLConstructionSite::takeForm()
240 {
241     return m_form.release();
242 }
243
244 void HTMLConstructionSite::dispatchDocumentElementAvailableIfNeeded()
245 {
246     ASSERT(m_document);
247     if (m_document->frame() && !m_isParsingFragment)
248         m_document->frame()->injectUserScripts(InjectAtDocumentStart);
249 }
250
251 void 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
263 void 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
275 void 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
285 void HTMLConstructionSite::insertHTMLBodyStartTagInBody(AtomicHTMLToken* token)
286 {
287     mergeAttributesFromTokenIntoElement(token, m_openElements.bodyElement());
288 }
289
290 void HTMLConstructionSite::setDefaultCompatibilityMode()
291 {
292     if (m_isParsingFragment)
293         return;
294     if (m_document->isSrcdocDocument())
295         return;
296     setCompatibilityMode(DocumentCompatibilityMode::QuirksMode);
297 }
298
299 void HTMLConstructionSite::setCompatibilityMode(DocumentCompatibilityMode mode)
300 {
301     m_inQuirksMode = (mode == DocumentCompatibilityMode::QuirksMode);
302     m_document->setCompatibilityMode(mode);
303 }
304
305 void 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
393 void HTMLConstructionSite::finishedParsing()
394 {
395     m_document->finishedParsing();
396 }
397
398 void 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
423 void HTMLConstructionSite::insertComment(AtomicHTMLToken* token)
424 {
425     ASSERT(token->type() == HTMLToken::Comment);
426     attachLater(currentNode(), Comment::create(ownerDocumentForCurrentNode(), token->comment()));
427 }
428
429 void HTMLConstructionSite::insertCommentOnDocument(AtomicHTMLToken* token)
430 {
431     ASSERT(token->type() == HTMLToken::Comment);
432     attachLater(m_attachmentRoot, Comment::create(*m_document, token->comment()));
433 }
434
435 void 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
442 void 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
450 void 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
458 void HTMLConstructionSite::insertHTMLFormElement(AtomicHTMLToken* token, bool isDemoted)
459 {
460     RefPtr<Element> element = createHTMLElement(token);
461     ASSERT(is<HTMLFormElement>(*element));
462     m_form = static_pointer_cast<HTMLFormElement>(element.release());
463     m_form->setDemoted(isDemoted);
464     attachLater(currentNode(), m_form);
465     m_openElements.push(HTMLStackItem::create(m_form, token));
466 }
467
468 void HTMLConstructionSite::insertHTMLElement(AtomicHTMLToken* token)
469 {
470     RefPtr<Element> element = createHTMLElement(token);
471     attachLater(currentNode(), element);
472     m_openElements.push(HTMLStackItem::create(element.release(), token));
473 }
474
475 void HTMLConstructionSite::insertSelfClosingHTMLElement(AtomicHTMLToken* token)
476 {
477     ASSERT(token->type() == HTMLToken::StartTag);
478     // Normally HTMLElementStack is responsible for calling finishParsingChildren,
479     // but self-closing elements are never in the element stack so the stack
480     // doesn't get a chance to tell them that we're done parsing their children.
481     attachLater(currentNode(), createHTMLElement(token), true);
482     // FIXME: Do we want to acknowledge the token's self-closing flag?
483     // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#acknowledge-self-closing-flag
484 }
485
486 void HTMLConstructionSite::insertFormattingElement(AtomicHTMLToken* token)
487 {
488     // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#the-stack-of-open-elements
489     // Possible active formatting elements include:
490     // a, b, big, code, em, font, i, nobr, s, small, strike, strong, tt, and u.
491     insertHTMLElement(token);
492     m_activeFormattingElements.append(currentElementRecord()->stackItem());
493 }
494
495 void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken* token)
496 {
497     // http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#already-started
498     // http://html5.org/specs/dom-parsing.html#dom-range-createcontextualfragment
499     // For createContextualFragment, the specifications say to mark it parser-inserted and already-started and later unmark them.
500     // However, we short circuit that logic to avoid the subtree traversal to find script elements since scripts can never see
501     // those flags or effects thereof.
502     const bool parserInserted = m_parserContentPolicy != AllowScriptingContentAndDoNotMarkAlreadyStarted;
503     const bool alreadyStarted = m_isParsingFragment && parserInserted;
504     RefPtr<HTMLScriptElement> element = HTMLScriptElement::create(scriptTag, ownerDocumentForCurrentNode(), parserInserted, alreadyStarted);
505     setAttributes(element.get(), token, m_parserContentPolicy);
506     if (scriptingContentIsAllowed(m_parserContentPolicy))
507         attachLater(currentNode(), element);
508     m_openElements.push(HTMLStackItem::create(element.release(), token));
509 }
510
511 void HTMLConstructionSite::insertForeignElement(AtomicHTMLToken* token, const AtomicString& namespaceURI)
512 {
513     ASSERT(token->type() == HTMLToken::StartTag);
514     notImplemented(); // parseError when xmlns or xmlns:xlink are wrong.
515
516     RefPtr<Element> element = createElement(token, namespaceURI);
517     if (scriptingContentIsAllowed(m_parserContentPolicy) || !toScriptElementIfPossible(element.get()))
518         attachLater(currentNode(), element, token->selfClosing());
519     if (!token->selfClosing())
520         m_openElements.push(HTMLStackItem::create(element.release(), token, namespaceURI));
521 }
522
523 void HTMLConstructionSite::insertTextNode(const String& characters, WhitespaceMode whitespaceMode)
524 {
525     HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert);
526     task.parent = currentNode();
527
528     if (shouldFosterParent())
529         findFosterSite(task);
530
531 #if ENABLE(TEMPLATE_ELEMENT)
532     if (is<HTMLTemplateElement>(*task.parent))
533         task.parent = downcast<HTMLTemplateElement>(*task.parent).content();
534 #endif
535
536     // Strings composed entirely of whitespace are likely to be repeated.
537     // Turn them into AtomicString so we share a single string for each.
538     bool shouldUseAtomicString = whitespaceMode == AllWhitespace
539         || (whitespaceMode == WhitespaceUnknown && isAllWhitespace(characters));
540
541     unsigned currentPosition = 0;
542     unsigned lengthLimit = shouldUseLengthLimit(task.parent.get()) ? Text::defaultLengthLimit : std::numeric_limits<unsigned>::max();
543
544     // FIXME: Splitting text nodes into smaller chunks contradicts HTML5 spec, but is currently necessary
545     // for performance, see <https://bugs.webkit.org/show_bug.cgi?id=55898>.
546
547     Node* previousChild = task.nextChild ? task.nextChild->previousSibling() : task.parent->lastChild();
548     if (is<Text>(previousChild)) {
549         // FIXME: We're only supposed to append to this text node if it
550         // was the last text node inserted by the parser.
551         Text& textNode = downcast<Text>(*previousChild);
552         currentPosition = textNode.parserAppendData(characters, 0, lengthLimit);
553     }
554
555     while (currentPosition < characters.length()) {
556         Ref<Text> textNode = Text::createWithLengthLimit(task.parent->document(), shouldUseAtomicString ? AtomicString(characters).string() : characters, currentPosition, lengthLimit);
557         // 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.
558         if (!textNode->length()) {
559             String substring = characters.substring(currentPosition);
560             textNode = Text::create(task.parent->document(), shouldUseAtomicString ? AtomicString(substring).string() : substring);
561         }
562
563         currentPosition += textNode->length();
564         ASSERT(currentPosition <= characters.length());
565         task.child = WTF::move(textNode);
566
567         executeTask(task);
568     }
569 }
570
571 void HTMLConstructionSite::reparent(HTMLElementStack::ElementRecord& newParent, HTMLElementStack::ElementRecord& child)
572 {
573     HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Reparent);
574     task.parent = newParent.node();
575     task.child = child.element();
576     m_taskQueue.append(task);
577 }
578
579 void HTMLConstructionSite::reparent(HTMLElementStack::ElementRecord& newParent, HTMLStackItem& 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::insertAlreadyParsedChild(HTMLStackItem& newParent, HTMLElementStack::ElementRecord& child)
588 {
589     if (newParent.causesFosterParenting()) {
590         fosterParent(child.element());
591         return;
592     }
593
594     HTMLConstructionSiteTask task(HTMLConstructionSiteTask::InsertAlreadyParsedChild);
595     task.parent = newParent.node();
596     task.child = child.element();
597     m_taskQueue.append(task);
598 }
599
600 void HTMLConstructionSite::takeAllChildren(HTMLStackItem& newParent, HTMLElementStack::ElementRecord& oldParent)
601 {
602     HTMLConstructionSiteTask task(HTMLConstructionSiteTask::TakeAllChildren);
603     task.parent = newParent.node();
604     task.child = oldParent.node();
605     m_taskQueue.append(task);
606 }
607
608 PassRefPtr<Element> HTMLConstructionSite::createElement(AtomicHTMLToken* token, const AtomicString& namespaceURI)
609 {
610     QualifiedName tagName(nullAtom, token->name(), namespaceURI);
611     RefPtr<Element> element = ownerDocumentForCurrentNode().createElement(tagName, true);
612     setAttributes(element.get(), token, m_parserContentPolicy);
613     return element.release();
614 }
615
616 inline Document& HTMLConstructionSite::ownerDocumentForCurrentNode()
617 {
618 #if ENABLE(TEMPLATE_ELEMENT)
619     if (is<HTMLTemplateElement>(*currentNode()))
620         return downcast<HTMLTemplateElement>(*currentElement()).content()->document();
621 #endif
622     return currentNode()->document();
623 }
624
625 PassRefPtr<Element> HTMLConstructionSite::createHTMLElement(AtomicHTMLToken* token)
626 {
627     QualifiedName tagName(nullAtom, token->name(), xhtmlNamespaceURI);
628     // FIXME: This can't use HTMLConstructionSite::createElement because we
629     // have to pass the current form element.  We should rework form association
630     // to occur after construction to allow better code sharing here.
631     // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#create-an-element-for-the-token
632     Document& ownerDocument = ownerDocumentForCurrentNode();
633     bool insideTemplateElement = !ownerDocument.frame();
634     RefPtr<Element> element = HTMLElementFactory::createElement(tagName, ownerDocument, insideTemplateElement ? nullptr : form(), true);
635     setAttributes(element.get(), token, m_parserContentPolicy);
636     ASSERT(element->isHTMLElement());
637     return element.release();
638 }
639
640 PassRefPtr<HTMLStackItem> HTMLConstructionSite::createElementFromSavedToken(HTMLStackItem* item)
641 {
642     RefPtr<Element> element;
643     // NOTE: Moving from item -> token -> item copies the Attribute vector twice!
644     AtomicHTMLToken fakeToken(HTMLToken::StartTag, item->localName(), item->attributes());
645     if (item->namespaceURI() == HTMLNames::xhtmlNamespaceURI)
646         element = createHTMLElement(&fakeToken);
647     else
648         element = createElement(&fakeToken, item->namespaceURI());
649     return HTMLStackItem::create(element.release(), &fakeToken, item->namespaceURI());
650 }
651
652 bool HTMLConstructionSite::indexOfFirstUnopenFormattingElement(unsigned& firstUnopenElementIndex) const
653 {
654     if (m_activeFormattingElements.isEmpty())
655         return false;
656     unsigned index = m_activeFormattingElements.size();
657     do {
658         --index;
659         const HTMLFormattingElementList::Entry& entry = m_activeFormattingElements.at(index);
660         if (entry.isMarker() || m_openElements.contains(entry.element())) {
661             firstUnopenElementIndex = index + 1;
662             return firstUnopenElementIndex < m_activeFormattingElements.size();
663         }
664     } while (index);
665     firstUnopenElementIndex = index;
666     return true;
667 }
668
669 void HTMLConstructionSite::reconstructTheActiveFormattingElements()
670 {
671     unsigned firstUnopenElementIndex;
672     if (!indexOfFirstUnopenFormattingElement(firstUnopenElementIndex))
673         return;
674
675     unsigned unopenEntryIndex = firstUnopenElementIndex;
676     ASSERT(unopenEntryIndex < m_activeFormattingElements.size());
677     for (; unopenEntryIndex < m_activeFormattingElements.size(); ++unopenEntryIndex) {
678         HTMLFormattingElementList::Entry& unopenedEntry = m_activeFormattingElements.at(unopenEntryIndex);
679         RefPtr<HTMLStackItem> reconstructed = createElementFromSavedToken(unopenedEntry.stackItem().get());
680         attachLater(currentNode(), reconstructed->node());
681         m_openElements.push(reconstructed);
682         unopenedEntry.replaceElement(reconstructed.release());
683     }
684 }
685
686 void HTMLConstructionSite::generateImpliedEndTagsWithExclusion(const AtomicString& tagName)
687 {
688     while (hasImpliedEndTag(currentStackItem()) && !currentStackItem()->matchesHTMLTag(tagName))
689         m_openElements.pop();
690 }
691
692 void HTMLConstructionSite::generateImpliedEndTags()
693 {
694     while (hasImpliedEndTag(currentStackItem()))
695         m_openElements.pop();
696 }
697
698 bool HTMLConstructionSite::inQuirksMode()
699 {
700     return m_inQuirksMode;
701 }
702
703 void HTMLConstructionSite::findFosterSite(HTMLConstructionSiteTask& task)
704 {
705 #if ENABLE(TEMPLATE_ELEMENT)
706     // 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!)
707     HTMLElementStack::ElementRecord* lastTemplateElement = m_openElements.topmost(templateTag.localName());
708     if (lastTemplateElement && !m_openElements.inTableScope(tableTag)) {
709         task.parent = lastTemplateElement->element();
710         return;
711     }
712
713 #endif
714
715     HTMLElementStack::ElementRecord* lastTableElementRecord = m_openElements.topmost(tableTag.localName());
716     if (lastTableElementRecord) {
717         Element* lastTableElement = lastTableElementRecord->element();
718         ContainerNode* parent = lastTableElement->parentNode();
719         // When parsing HTML fragments, we skip step 4.2 ("Let root be a new html element with no attributes") for efficiency,
720         // 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.
721         bool parentCanBeFosterParent = parent && (parent->isElementNode() || (m_isParsingFragment && parent == m_openElements.rootNode()));
722 #if ENABLE(TEMPLATE_ELEMENT)
723         parentCanBeFosterParent = parentCanBeFosterParent || (is<DocumentFragment>(parent) && downcast<DocumentFragment>(parent)->isTemplateContent());
724 #endif
725         if (parentCanBeFosterParent) {
726             task.parent = parent;
727             task.nextChild = lastTableElement;
728             return;
729         }
730         task.parent = lastTableElementRecord->next()->element();
731         return;
732     }
733     // Fragment case
734     task.parent = m_openElements.rootNode(); // DocumentFragment
735 }
736
737 bool HTMLConstructionSite::shouldFosterParent() const
738 {
739     return m_redirectAttachToFosterParent
740         && currentStackItem()->isElementNode()
741         && currentStackItem()->causesFosterParenting();
742 }
743
744 void HTMLConstructionSite::fosterParent(PassRefPtr<Node> node)
745 {
746     HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert);
747     findFosterSite(task);
748     task.child = node;
749     ASSERT(task.parent);
750
751     m_taskQueue.append(task);
752 }
753
754 }