Have is<>(T*) function do a null check on the pointer argument
[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     RefPtr<HTMLFormElement> form = static_pointer_cast<HTMLFormElement>(element.release());
463     if (!insideTemplateElement())
464         m_form = form;
465     form->setDemoted(isDemoted);
466     attachLater(currentNode(), form);
467     m_openElements.push(HTMLStackItem::create(form.release(), token));
468 }
469
470 void HTMLConstructionSite::insertHTMLElement(AtomicHTMLToken* token)
471 {
472     RefPtr<Element> element = createHTMLElement(token);
473     attachLater(currentNode(), element);
474     m_openElements.push(HTMLStackItem::create(element.release(), token));
475 }
476
477 void HTMLConstructionSite::insertSelfClosingHTMLElement(AtomicHTMLToken* token)
478 {
479     ASSERT(token->type() == HTMLToken::StartTag);
480     // Normally HTMLElementStack is responsible for calling finishParsingChildren,
481     // but self-closing elements are never in the element stack so the stack
482     // doesn't get a chance to tell them that we're done parsing their children.
483     attachLater(currentNode(), createHTMLElement(token), true);
484     // FIXME: Do we want to acknowledge the token's self-closing flag?
485     // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#acknowledge-self-closing-flag
486 }
487
488 void HTMLConstructionSite::insertFormattingElement(AtomicHTMLToken* token)
489 {
490     // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#the-stack-of-open-elements
491     // Possible active formatting elements include:
492     // a, b, big, code, em, font, i, nobr, s, small, strike, strong, tt, and u.
493     insertHTMLElement(token);
494     m_activeFormattingElements.append(currentElementRecord()->stackItem());
495 }
496
497 void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken* token)
498 {
499     // http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#already-started
500     // http://html5.org/specs/dom-parsing.html#dom-range-createcontextualfragment
501     // For createContextualFragment, the specifications say to mark it parser-inserted and already-started and later unmark them.
502     // However, we short circuit that logic to avoid the subtree traversal to find script elements since scripts can never see
503     // those flags or effects thereof.
504     const bool parserInserted = m_parserContentPolicy != AllowScriptingContentAndDoNotMarkAlreadyStarted;
505     const bool alreadyStarted = m_isParsingFragment && parserInserted;
506     RefPtr<HTMLScriptElement> element = HTMLScriptElement::create(scriptTag, ownerDocumentForCurrentNode(), parserInserted, alreadyStarted);
507     setAttributes(element.get(), token, m_parserContentPolicy);
508     if (scriptingContentIsAllowed(m_parserContentPolicy))
509         attachLater(currentNode(), element);
510     m_openElements.push(HTMLStackItem::create(element.release(), token));
511 }
512
513 void HTMLConstructionSite::insertForeignElement(AtomicHTMLToken* token, const AtomicString& namespaceURI)
514 {
515     ASSERT(token->type() == HTMLToken::StartTag);
516     notImplemented(); // parseError when xmlns or xmlns:xlink are wrong.
517
518     RefPtr<Element> element = createElement(token, namespaceURI);
519     if (scriptingContentIsAllowed(m_parserContentPolicy) || !toScriptElementIfPossible(element.get()))
520         attachLater(currentNode(), element, token->selfClosing());
521     if (!token->selfClosing())
522         m_openElements.push(HTMLStackItem::create(element.release(), token, namespaceURI));
523 }
524
525 void HTMLConstructionSite::insertTextNode(const String& characters, WhitespaceMode whitespaceMode)
526 {
527     HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert);
528     task.parent = currentNode();
529
530     if (shouldFosterParent())
531         findFosterSite(task);
532
533 #if ENABLE(TEMPLATE_ELEMENT)
534     if (is<HTMLTemplateElement>(*task.parent))
535         task.parent = downcast<HTMLTemplateElement>(*task.parent).content();
536 #endif
537
538     // Strings composed entirely of whitespace are likely to be repeated.
539     // Turn them into AtomicString so we share a single string for each.
540     bool shouldUseAtomicString = whitespaceMode == AllWhitespace
541         || (whitespaceMode == WhitespaceUnknown && isAllWhitespace(characters));
542
543     unsigned currentPosition = 0;
544     unsigned lengthLimit = shouldUseLengthLimit(task.parent.get()) ? Text::defaultLengthLimit : std::numeric_limits<unsigned>::max();
545
546     // FIXME: Splitting text nodes into smaller chunks contradicts HTML5 spec, but is currently necessary
547     // for performance, see <https://bugs.webkit.org/show_bug.cgi?id=55898>.
548
549     Node* previousChild = task.nextChild ? task.nextChild->previousSibling() : task.parent->lastChild();
550     if (is<Text>(previousChild)) {
551         // FIXME: We're only supposed to append to this text node if it
552         // was the last text node inserted by the parser.
553         Text& textNode = downcast<Text>(*previousChild);
554         currentPosition = textNode.parserAppendData(characters, 0, lengthLimit);
555     }
556
557     while (currentPosition < characters.length()) {
558         RefPtr<Text> textNode = Text::createWithLengthLimit(task.parent->document(), shouldUseAtomicString ? AtomicString(characters).string() : characters, currentPosition, lengthLimit);
559         // If we have a whole string of unbreakable characters the above could lead to an infinite loop. Exceeding the length limit is the lesser evil.
560         if (!textNode->length()) {
561             String substring = characters.substring(currentPosition);
562             textNode = Text::create(task.parent->document(), shouldUseAtomicString ? AtomicString(substring).string() : substring);
563         }
564
565         currentPosition += textNode->length();
566         ASSERT(currentPosition <= characters.length());
567         task.child = textNode.release();
568
569         executeTask(task);
570     }
571 }
572
573 void HTMLConstructionSite::reparent(HTMLElementStack::ElementRecord& newParent, HTMLElementStack::ElementRecord& child)
574 {
575     HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Reparent);
576     task.parent = newParent.node();
577     task.child = child.element();
578     m_taskQueue.append(task);
579 }
580
581 void HTMLConstructionSite::reparent(HTMLElementStack::ElementRecord& newParent, HTMLStackItem& child)
582 {
583     HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Reparent);
584     task.parent = newParent.node();
585     task.child = child.element();
586     m_taskQueue.append(task);
587 }
588
589 void HTMLConstructionSite::insertAlreadyParsedChild(HTMLStackItem& newParent, HTMLElementStack::ElementRecord& child)
590 {
591     if (newParent.causesFosterParenting()) {
592         fosterParent(child.element());
593         return;
594     }
595
596     HTMLConstructionSiteTask task(HTMLConstructionSiteTask::InsertAlreadyParsedChild);
597     task.parent = newParent.node();
598     task.child = child.element();
599     m_taskQueue.append(task);
600 }
601
602 void HTMLConstructionSite::takeAllChildren(HTMLStackItem& newParent, HTMLElementStack::ElementRecord& oldParent)
603 {
604     HTMLConstructionSiteTask task(HTMLConstructionSiteTask::TakeAllChildren);
605     task.parent = newParent.node();
606     task.child = oldParent.node();
607     m_taskQueue.append(task);
608 }
609
610 PassRefPtr<Element> HTMLConstructionSite::createElement(AtomicHTMLToken* token, const AtomicString& namespaceURI)
611 {
612     QualifiedName tagName(nullAtom, token->name(), namespaceURI);
613     RefPtr<Element> element = ownerDocumentForCurrentNode().createElement(tagName, true);
614     setAttributes(element.get(), token, m_parserContentPolicy);
615     return element.release();
616 }
617
618 inline Document& HTMLConstructionSite::ownerDocumentForCurrentNode()
619 {
620 #if ENABLE(TEMPLATE_ELEMENT)
621     if (is<HTMLTemplateElement>(*currentNode()))
622         return downcast<HTMLTemplateElement>(*currentElement()).content()->document();
623 #endif
624     return currentNode()->document();
625 }
626
627 inline bool HTMLConstructionSite::insideTemplateElement()
628 {
629     return !ownerDocumentForCurrentNode().frame();
630 }
631
632 PassRefPtr<Element> HTMLConstructionSite::createHTMLElement(AtomicHTMLToken* token)
633 {
634     QualifiedName tagName(nullAtom, token->name(), xhtmlNamespaceURI);
635     // FIXME: This can't use HTMLConstructionSite::createElement because we
636     // have to pass the current form element.  We should rework form association
637     // to occur after construction to allow better code sharing here.
638     // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#create-an-element-for-the-token
639     Document& ownerDocument = ownerDocumentForCurrentNode();
640     bool insideTemplateElement = !ownerDocument.frame();
641     RefPtr<Element> element = HTMLElementFactory::createElement(tagName, ownerDocument, insideTemplateElement ? nullptr : form(), true);
642     setAttributes(element.get(), token, m_parserContentPolicy);
643     ASSERT(element->isHTMLElement());
644     return element.release();
645 }
646
647 PassRefPtr<HTMLStackItem> HTMLConstructionSite::createElementFromSavedToken(HTMLStackItem* item)
648 {
649     RefPtr<Element> element;
650     // NOTE: Moving from item -> token -> item copies the Attribute vector twice!
651     AtomicHTMLToken fakeToken(HTMLToken::StartTag, item->localName(), item->attributes());
652     if (item->namespaceURI() == HTMLNames::xhtmlNamespaceURI)
653         element = createHTMLElement(&fakeToken);
654     else
655         element = createElement(&fakeToken, item->namespaceURI());
656     return HTMLStackItem::create(element.release(), &fakeToken, item->namespaceURI());
657 }
658
659 bool HTMLConstructionSite::indexOfFirstUnopenFormattingElement(unsigned& firstUnopenElementIndex) const
660 {
661     if (m_activeFormattingElements.isEmpty())
662         return false;
663     unsigned index = m_activeFormattingElements.size();
664     do {
665         --index;
666         const HTMLFormattingElementList::Entry& entry = m_activeFormattingElements.at(index);
667         if (entry.isMarker() || m_openElements.contains(entry.element())) {
668             firstUnopenElementIndex = index + 1;
669             return firstUnopenElementIndex < m_activeFormattingElements.size();
670         }
671     } while (index);
672     firstUnopenElementIndex = index;
673     return true;
674 }
675
676 void HTMLConstructionSite::reconstructTheActiveFormattingElements()
677 {
678     unsigned firstUnopenElementIndex;
679     if (!indexOfFirstUnopenFormattingElement(firstUnopenElementIndex))
680         return;
681
682     unsigned unopenEntryIndex = firstUnopenElementIndex;
683     ASSERT(unopenEntryIndex < m_activeFormattingElements.size());
684     for (; unopenEntryIndex < m_activeFormattingElements.size(); ++unopenEntryIndex) {
685         HTMLFormattingElementList::Entry& unopenedEntry = m_activeFormattingElements.at(unopenEntryIndex);
686         RefPtr<HTMLStackItem> reconstructed = createElementFromSavedToken(unopenedEntry.stackItem().get());
687         attachLater(currentNode(), reconstructed->node());
688         m_openElements.push(reconstructed);
689         unopenedEntry.replaceElement(reconstructed.release());
690     }
691 }
692
693 void HTMLConstructionSite::generateImpliedEndTagsWithExclusion(const AtomicString& tagName)
694 {
695     while (hasImpliedEndTag(currentStackItem()) && !currentStackItem()->matchesHTMLTag(tagName))
696         m_openElements.pop();
697 }
698
699 void HTMLConstructionSite::generateImpliedEndTags()
700 {
701     while (hasImpliedEndTag(currentStackItem()))
702         m_openElements.pop();
703 }
704
705 bool HTMLConstructionSite::inQuirksMode()
706 {
707     return m_inQuirksMode;
708 }
709
710 void HTMLConstructionSite::findFosterSite(HTMLConstructionSiteTask& task)
711 {
712 #if ENABLE(TEMPLATE_ELEMENT)
713     // When a node is to be foster parented, the last template element with no table element is below it in the stack of open elements is the foster parent element (NOT the template's parent!)
714     HTMLElementStack::ElementRecord* lastTemplateElement = m_openElements.topmost(templateTag.localName());
715     if (lastTemplateElement && !m_openElements.inTableScope(tableTag)) {
716         task.parent = lastTemplateElement->element();
717         return;
718     }
719
720 #endif
721
722     HTMLElementStack::ElementRecord* lastTableElementRecord = m_openElements.topmost(tableTag.localName());
723     if (lastTableElementRecord) {
724         Element* lastTableElement = lastTableElementRecord->element();
725         ContainerNode* parent = lastTableElement->parentNode();
726         // When parsing HTML fragments, we skip step 4.2 ("Let root be a new html element with no attributes") for efficiency,
727         // and instead use the DocumentFragment as a root node. So we must treat the root node (DocumentFragment) as if it is a html element here.
728         bool parentCanBeFosterParent = parent && (parent->isElementNode() || (m_isParsingFragment && parent == m_openElements.rootNode()));
729 #if ENABLE(TEMPLATE_ELEMENT)
730         parentCanBeFosterParent = parentCanBeFosterParent || (is<DocumentFragment>(parent) && downcast<DocumentFragment>(parent)->isTemplateContent());
731 #endif
732         if (parentCanBeFosterParent) {
733             task.parent = parent;
734             task.nextChild = lastTableElement;
735             return;
736         }
737         task.parent = lastTableElementRecord->next()->element();
738         return;
739     }
740     // Fragment case
741     task.parent = m_openElements.rootNode(); // DocumentFragment
742 }
743
744 bool HTMLConstructionSite::shouldFosterParent() const
745 {
746     return m_redirectAttachToFosterParent
747         && currentStackItem()->isElementNode()
748         && currentStackItem()->causesFosterParenting();
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 }