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