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