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