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