2 * Copyright (C) 2010 Google, Inc. All Rights Reserved.
3 * Copyright (C) 2011 Apple Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
28 #include "HTMLTreeBuilder.h"
30 #include "AtomicHTMLToken.h"
32 #include "DocumentFragment.h"
33 #include "DocumentType.h"
36 #include "FrameLoader.h"
37 #include "FrameLoaderClient.h"
38 #include "HTMLDocument.h"
39 #include "HTMLElementFactory.h"
40 #include "HTMLFormElement.h"
41 #include "HTMLHtmlElement.h"
42 #include "HTMLNames.h"
43 #include "HTMLParserIdioms.h"
44 #include "HTMLPlugInElement.h"
45 #include "HTMLScriptElement.h"
46 #include "HTMLStackItem.h"
47 #include "HTMLTemplateElement.h"
48 #include "HTMLToken.h"
49 #include "HTMLTokenizer.h"
50 #include "LocalizedStrings.h"
51 #include "NotImplemented.h"
54 #include <wtf/UnusedParam.h>
58 using namespace HTMLNames;
60 static inline void setAttributes(Element* element, AtomicHTMLToken* token, ParserContentPolicy parserContentPolicy)
62 if (!scriptingContentIsAllowed(parserContentPolicy))
63 element->stripJavaScriptAttributes(token->attributes());
64 element->parserSetAttributes(token->attributes());
67 static bool hasImpliedEndTag(const HTMLStackItem* item)
69 return item->hasTagName(ddTag)
70 || item->hasTagName(dtTag)
71 || item->hasTagName(liTag)
72 || item->hasTagName(optionTag)
73 || item->hasTagName(optgroupTag)
74 || item->hasTagName(pTag)
75 || item->hasTagName(rpTag)
76 || item->hasTagName(rtTag);
79 static inline bool isAllWhitespace(const String& string)
81 return string.isAllSpecialCharacters<isHTMLSpace>();
84 static inline void executeTask(HTMLConstructionSiteTask& task)
86 #if ENABLE(TEMPLATE_ELEMENT)
87 if (task.parent->hasTagName(templateTag))
88 task.parent = toHTMLTemplateElement(task.parent.get())->content();
92 task.parent->parserInsertBefore(task.child.get(), task.nextChild.get());
94 task.parent->parserAppendChild(task.child.get());
96 // JavaScript run from beforeload (or DOM Mutation or event handlers)
97 // might have removed the child, in which case we should not attach it.
99 if (task.child->parentNode() && task.parent->attached() && !task.child->attached())
100 task.child->attach();
102 task.child->beginParsingChildren();
104 if (task.selfClosing)
105 task.child->finishParsingChildren();
108 void HTMLConstructionSite::attachLater(ContainerNode* parent, PassRefPtr<Node> prpChild, bool selfClosing)
110 ASSERT(scriptingContentIsAllowed(m_parserContentPolicy) || !prpChild.get()->isElementNode() || !toScriptElementIfPossible(toElement(prpChild.get())));
111 ASSERT(pluginContentIsAllowed(m_parserContentPolicy) || !prpChild->isPluginElement());
113 HTMLConstructionSiteTask task;
114 task.parent = parent;
115 task.child = prpChild;
116 task.selfClosing = selfClosing;
118 if (shouldFosterParent()) {
119 fosterParent(task.child);
123 // Add as a sibling of the parent if we have reached the maximum depth allowed.
124 if (m_openElements.stackDepth() > m_maximumDOMTreeDepth && task.parent->parentNode())
125 task.parent = task.parent->parentNode();
128 m_attachmentQueue.append(task);
131 void HTMLConstructionSite::executeQueuedTasks()
133 const size_t size = m_attachmentQueue.size();
137 // Copy the task queue into a local variable in case executeTask
138 // re-enters the parser.
139 AttachmentQueue queue;
140 queue.swap(m_attachmentQueue);
142 for (size_t i = 0; i < size; ++i)
143 executeTask(queue[i]);
145 // We might be detached now.
148 HTMLConstructionSite::HTMLConstructionSite(Document* document, ParserContentPolicy parserContentPolicy, unsigned maximumDOMTreeDepth)
149 : m_document(document)
150 , m_attachmentRoot(document)
151 , m_parserContentPolicy(parserContentPolicy)
152 , m_isParsingFragment(false)
153 , m_redirectAttachToFosterParent(false)
154 , m_maximumDOMTreeDepth(maximumDOMTreeDepth)
155 , m_inQuirksMode(document->inQuirksMode())
157 ASSERT(m_document->isHTMLDocument() || m_document->isXHTMLDocument());
160 HTMLConstructionSite::HTMLConstructionSite(DocumentFragment* fragment, ParserContentPolicy parserContentPolicy, unsigned maximumDOMTreeDepth)
161 : m_document(fragment->document())
162 , m_attachmentRoot(fragment)
163 , m_parserContentPolicy(parserContentPolicy)
164 , m_isParsingFragment(true)
165 , m_redirectAttachToFosterParent(false)
166 , m_maximumDOMTreeDepth(maximumDOMTreeDepth)
167 , m_inQuirksMode(fragment->document()->inQuirksMode())
169 ASSERT(m_document->isHTMLDocument() || m_document->isXHTMLDocument());
172 HTMLConstructionSite::~HTMLConstructionSite()
176 void HTMLConstructionSite::detach()
179 m_attachmentRoot = 0;
182 void HTMLConstructionSite::setForm(HTMLFormElement* form)
184 // This method should only be needed for HTMLTreeBuilder in the fragment case.
189 PassRefPtr<HTMLFormElement> HTMLConstructionSite::takeForm()
191 return m_form.release();
194 void HTMLConstructionSite::dispatchDocumentElementAvailableIfNeeded()
197 if (m_document->frame() && !m_isParsingFragment)
198 m_document->frame()->loader()->dispatchDocumentElementAvailable();
201 void HTMLConstructionSite::insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken* token)
203 RefPtr<HTMLHtmlElement> element = HTMLHtmlElement::create(m_document);
204 setAttributes(element.get(), token, m_parserContentPolicy);
205 attachLater(m_attachmentRoot, element);
206 m_openElements.pushHTMLHtmlElement(HTMLStackItem::create(element, token));
208 executeQueuedTasks();
209 element->insertedByParser();
210 dispatchDocumentElementAvailableIfNeeded();
213 void HTMLConstructionSite::mergeAttributesFromTokenIntoElement(AtomicHTMLToken* token, Element* element)
215 if (token->attributes().isEmpty())
218 for (unsigned i = 0; i < token->attributes().size(); ++i) {
219 const Attribute& tokenAttribute = token->attributes().at(i);
220 if (!element->elementData() || !element->getAttributeItem(tokenAttribute.name()))
221 element->setAttribute(tokenAttribute.name(), tokenAttribute.value());
225 void HTMLConstructionSite::insertHTMLHtmlStartTagInBody(AtomicHTMLToken* token)
227 // Fragments do not have a root HTML element, so any additional HTML elements
228 // encountered during fragment parsing should be ignored.
229 if (m_isParsingFragment)
232 mergeAttributesFromTokenIntoElement(token, m_openElements.htmlElement());
235 void HTMLConstructionSite::insertHTMLBodyStartTagInBody(AtomicHTMLToken* token)
237 mergeAttributesFromTokenIntoElement(token, m_openElements.bodyElement());
240 void HTMLConstructionSite::setDefaultCompatibilityMode()
242 if (m_isParsingFragment)
244 if (m_document->isSrcdocDocument())
246 setCompatibilityMode(Document::QuirksMode);
249 void HTMLConstructionSite::setCompatibilityMode(Document::CompatibilityMode mode)
251 m_inQuirksMode = (mode == Document::QuirksMode);
252 m_document->setCompatibilityMode(mode);
255 void HTMLConstructionSite::setCompatibilityModeFromDoctype(const String& name, const String& publicId, const String& systemId)
257 // There are three possible compatibility modes:
258 // Quirks - quirks mode emulates WinIE and NS4. CSS parsing is also relaxed in this mode, e.g., unit types can
259 // be omitted from numbers.
260 // Limited Quirks - This mode is identical to no-quirks mode except for its treatment of line-height in the inline box model.
261 // No Quirks - no quirks apply. Web pages will obey the specifications to the letter.
263 // Check for Quirks Mode.
265 || publicId.startsWith("+//Silmaril//dtd html Pro v0r11 19970101//", false)
266 || publicId.startsWith("-//AdvaSoft Ltd//DTD HTML 3.0 asWedit + extensions//", false)
267 || publicId.startsWith("-//AS//DTD HTML 3.0 asWedit + extensions//", false)
268 || publicId.startsWith("-//IETF//DTD HTML 2.0 Level 1//", false)
269 || publicId.startsWith("-//IETF//DTD HTML 2.0 Level 2//", false)
270 || publicId.startsWith("-//IETF//DTD HTML 2.0 Strict Level 1//", false)
271 || publicId.startsWith("-//IETF//DTD HTML 2.0 Strict Level 2//", false)
272 || publicId.startsWith("-//IETF//DTD HTML 2.0 Strict//", false)
273 || publicId.startsWith("-//IETF//DTD HTML 2.0//", false)
274 || publicId.startsWith("-//IETF//DTD HTML 2.1E//", false)
275 || publicId.startsWith("-//IETF//DTD HTML 3.0//", false)
276 || publicId.startsWith("-//IETF//DTD HTML 3.2 Final//", false)
277 || publicId.startsWith("-//IETF//DTD HTML 3.2//", false)
278 || publicId.startsWith("-//IETF//DTD HTML 3//", false)
279 || publicId.startsWith("-//IETF//DTD HTML Level 0//", false)
280 || publicId.startsWith("-//IETF//DTD HTML Level 1//", false)
281 || publicId.startsWith("-//IETF//DTD HTML Level 2//", false)
282 || publicId.startsWith("-//IETF//DTD HTML Level 3//", false)
283 || publicId.startsWith("-//IETF//DTD HTML Strict Level 0//", false)
284 || publicId.startsWith("-//IETF//DTD HTML Strict Level 1//", false)
285 || publicId.startsWith("-//IETF//DTD HTML Strict Level 2//", false)
286 || publicId.startsWith("-//IETF//DTD HTML Strict Level 3//", false)
287 || publicId.startsWith("-//IETF//DTD HTML Strict//", false)
288 || publicId.startsWith("-//IETF//DTD HTML//", false)
289 || publicId.startsWith("-//Metrius//DTD Metrius Presentational//", false)
290 || publicId.startsWith("-//Microsoft//DTD Internet Explorer 2.0 HTML Strict//", false)
291 || publicId.startsWith("-//Microsoft//DTD Internet Explorer 2.0 HTML//", false)
292 || publicId.startsWith("-//Microsoft//DTD Internet Explorer 2.0 Tables//", false)
293 || publicId.startsWith("-//Microsoft//DTD Internet Explorer 3.0 HTML Strict//", false)
294 || publicId.startsWith("-//Microsoft//DTD Internet Explorer 3.0 HTML//", false)
295 || publicId.startsWith("-//Microsoft//DTD Internet Explorer 3.0 Tables//", false)
296 || publicId.startsWith("-//Netscape Comm. Corp.//DTD HTML//", false)
297 || publicId.startsWith("-//Netscape Comm. Corp.//DTD Strict HTML//", false)
298 || publicId.startsWith("-//O'Reilly and Associates//DTD HTML 2.0//", false)
299 || publicId.startsWith("-//O'Reilly and Associates//DTD HTML Extended 1.0//", false)
300 || publicId.startsWith("-//O'Reilly and Associates//DTD HTML Extended Relaxed 1.0//", false)
301 || publicId.startsWith("-//SoftQuad Software//DTD HoTMetaL PRO 6.0::19990601::extensions to HTML 4.0//", false)
302 || publicId.startsWith("-//SoftQuad//DTD HoTMetaL PRO 4.0::19971010::extensions to HTML 4.0//", false)
303 || publicId.startsWith("-//Spyglass//DTD HTML 2.0 Extended//", false)
304 || publicId.startsWith("-//SQ//DTD HTML 2.0 HoTMetaL + extensions//", false)
305 || publicId.startsWith("-//Sun Microsystems Corp.//DTD HotJava HTML//", false)
306 || publicId.startsWith("-//Sun Microsystems Corp.//DTD HotJava Strict HTML//", false)
307 || publicId.startsWith("-//W3C//DTD HTML 3 1995-03-24//", false)
308 || publicId.startsWith("-//W3C//DTD HTML 3.2 Draft//", false)
309 || publicId.startsWith("-//W3C//DTD HTML 3.2 Final//", false)
310 || publicId.startsWith("-//W3C//DTD HTML 3.2//", false)
311 || publicId.startsWith("-//W3C//DTD HTML 3.2S Draft//", false)
312 || publicId.startsWith("-//W3C//DTD HTML 4.0 Frameset//", false)
313 || publicId.startsWith("-//W3C//DTD HTML 4.0 Transitional//", false)
314 || publicId.startsWith("-//W3C//DTD HTML Experimental 19960712//", false)
315 || publicId.startsWith("-//W3C//DTD HTML Experimental 970421//", false)
316 || publicId.startsWith("-//W3C//DTD W3 HTML//", false)
317 || publicId.startsWith("-//W3O//DTD W3 HTML 3.0//", false)
318 || equalIgnoringCase(publicId, "-//W3O//DTD W3 HTML Strict 3.0//EN//")
319 || publicId.startsWith("-//WebTechs//DTD Mozilla HTML 2.0//", false)
320 || publicId.startsWith("-//WebTechs//DTD Mozilla HTML//", false)
321 || equalIgnoringCase(publicId, "-/W3C/DTD HTML 4.0 Transitional/EN")
322 || equalIgnoringCase(publicId, "HTML")
323 || equalIgnoringCase(systemId, "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd")
324 || (systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Frameset//", false))
325 || (systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Transitional//", false))) {
326 setCompatibilityMode(Document::QuirksMode);
330 // Check for Limited Quirks Mode.
331 if (publicId.startsWith("-//W3C//DTD XHTML 1.0 Frameset//", false)
332 || publicId.startsWith("-//W3C//DTD XHTML 1.0 Transitional//", false)
333 || (!systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Frameset//", false))
334 || (!systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Transitional//", false))) {
335 setCompatibilityMode(Document::LimitedQuirksMode);
339 // Otherwise we are No Quirks Mode.
340 setCompatibilityMode(Document::NoQuirksMode);
343 void HTMLConstructionSite::finishedParsing()
345 m_document->finishedParsing();
348 void HTMLConstructionSite::insertDoctype(AtomicHTMLToken* token)
350 ASSERT(token->type() == HTMLToken::DOCTYPE);
352 const String& publicId = String::adopt(token->publicIdentifier());
353 const String& systemId = String::adopt(token->systemIdentifier());
354 RefPtr<DocumentType> doctype = DocumentType::create(m_document, token->name(), publicId, systemId);
355 attachLater(m_attachmentRoot, doctype.release());
357 // DOCTYPE nodes are only processed when parsing fragments w/o contextElements, which
358 // never occurs. However, if we ever chose to support such, this code is subtly wrong,
359 // because context-less fragments can determine their own quirks mode, and thus change
360 // parsing rules (like <p> inside <table>). For now we ASSERT that we never hit this code
361 // in a fragment, as changing the owning document's compatibility mode would be wrong.
362 ASSERT(!m_isParsingFragment);
363 if (m_isParsingFragment)
366 if (token->forceQuirks())
367 setCompatibilityMode(Document::QuirksMode);
369 setCompatibilityModeFromDoctype(token->name(), publicId, systemId);
373 void HTMLConstructionSite::insertComment(AtomicHTMLToken* token)
375 ASSERT(token->type() == HTMLToken::Comment);
376 attachLater(currentNode(), Comment::create(ownerDocumentForCurrentNode(), token->comment()));
379 void HTMLConstructionSite::insertCommentOnDocument(AtomicHTMLToken* token)
381 ASSERT(token->type() == HTMLToken::Comment);
382 attachLater(m_attachmentRoot, Comment::create(m_document, token->comment()));
385 void HTMLConstructionSite::insertCommentOnHTMLHtmlElement(AtomicHTMLToken* token)
387 ASSERT(token->type() == HTMLToken::Comment);
388 ContainerNode* parent = m_openElements.rootNode();
389 attachLater(parent, Comment::create(parent->document(), token->comment()));
392 void HTMLConstructionSite::insertHTMLHeadElement(AtomicHTMLToken* token)
394 ASSERT(!shouldFosterParent());
395 m_head = HTMLStackItem::create(createHTMLElement(token), token);
396 attachLater(currentNode(), m_head->element());
397 m_openElements.pushHTMLHeadElement(m_head);
400 void HTMLConstructionSite::insertHTMLBodyElement(AtomicHTMLToken* token)
402 ASSERT(!shouldFosterParent());
403 RefPtr<Element> body = createHTMLElement(token);
404 attachLater(currentNode(), body);
405 m_openElements.pushHTMLBodyElement(HTMLStackItem::create(body.release(), token));
406 if (Frame* frame = m_document->frame())
407 frame->loader()->client()->dispatchWillInsertBody();
410 void HTMLConstructionSite::insertHTMLFormElement(AtomicHTMLToken* token, bool isDemoted)
412 RefPtr<Element> element = createHTMLElement(token);
413 ASSERT(element->hasTagName(formTag));
414 m_form = static_pointer_cast<HTMLFormElement>(element.release());
415 m_form->setDemoted(isDemoted);
416 attachLater(currentNode(), m_form);
417 m_openElements.push(HTMLStackItem::create(m_form, token));
420 void HTMLConstructionSite::insertHTMLElement(AtomicHTMLToken* token)
422 RefPtr<Element> element = createHTMLElement(token);
423 attachLater(currentNode(), element);
424 m_openElements.push(HTMLStackItem::create(element.release(), token));
427 void HTMLConstructionSite::insertSelfClosingHTMLElement(AtomicHTMLToken* token)
429 ASSERT(token->type() == HTMLToken::StartTag);
430 // Normally HTMLElementStack is responsible for calling finishParsingChildren,
431 // but self-closing elements are never in the element stack so the stack
432 // doesn't get a chance to tell them that we're done parsing their children.
433 attachLater(currentNode(), createHTMLElement(token), true);
434 // FIXME: Do we want to acknowledge the token's self-closing flag?
435 // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#acknowledge-self-closing-flag
438 void HTMLConstructionSite::insertFormattingElement(AtomicHTMLToken* token)
440 // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#the-stack-of-open-elements
441 // Possible active formatting elements include:
442 // a, b, big, code, em, font, i, nobr, s, small, strike, strong, tt, and u.
443 insertHTMLElement(token);
444 m_activeFormattingElements.append(currentElementRecord()->stackItem());
447 void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken* token)
449 // http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#already-started
450 // http://html5.org/specs/dom-parsing.html#dom-range-createcontextualfragment
451 // For createContextualFragment, the specifications say to mark it parser-inserted and already-started and later unmark them.
452 // However, we short circuit that logic to avoid the subtree traversal to find script elements since scripts can never see
453 // those flags or effects thereof.
454 const bool parserInserted = m_parserContentPolicy != AllowScriptingContentAndDoNotMarkAlreadyStarted;
455 const bool alreadyStarted = m_isParsingFragment && parserInserted;
456 RefPtr<HTMLScriptElement> element = HTMLScriptElement::create(scriptTag, ownerDocumentForCurrentNode(), parserInserted, alreadyStarted);
457 setAttributes(element.get(), token, m_parserContentPolicy);
458 if (scriptingContentIsAllowed(m_parserContentPolicy))
459 attachLater(currentNode(), element);
460 m_openElements.push(HTMLStackItem::create(element.release(), token));
463 void HTMLConstructionSite::insertForeignElement(AtomicHTMLToken* token, const AtomicString& namespaceURI)
465 ASSERT(token->type() == HTMLToken::StartTag);
466 notImplemented(); // parseError when xmlns or xmlns:xlink are wrong.
468 RefPtr<Element> element = createElement(token, namespaceURI);
469 if (scriptingContentIsAllowed(m_parserContentPolicy) || !toScriptElementIfPossible(element.get()))
470 attachLater(currentNode(), element, token->selfClosing());
471 if (!token->selfClosing())
472 m_openElements.push(HTMLStackItem::create(element.release(), token, namespaceURI));
475 void HTMLConstructionSite::insertTextNode(const String& characters, WhitespaceMode whitespaceMode)
477 HTMLConstructionSiteTask task;
478 task.parent = currentNode();
480 if (shouldFosterParent())
481 findFosterSite(task);
483 #if ENABLE(TEMPLATE_ELEMENT)
484 if (task.parent->hasTagName(templateTag))
485 task.parent = toHTMLTemplateElement(task.parent.get())->content();
488 // Strings composed entirely of whitespace are likely to be repeated.
489 // Turn them into AtomicString so we share a single string for each.
490 bool shouldUseAtomicString = whitespaceMode == AllWhitespace
491 || (whitespaceMode == WhitespaceUnknown && isAllWhitespace(characters));
493 unsigned currentPosition = 0;
495 // FIXME: Splitting text nodes into smaller chunks contradicts HTML5 spec, but is currently necessary
496 // for performance, see <https://bugs.webkit.org/show_bug.cgi?id=55898>.
498 Node* previousChild = task.nextChild ? task.nextChild->previousSibling() : task.parent->lastChild();
499 if (previousChild && previousChild->isTextNode()) {
500 // FIXME: We're only supposed to append to this text node if it
501 // was the last text node inserted by the parser.
502 CharacterData* textNode = static_cast<CharacterData*>(previousChild);
503 currentPosition = textNode->parserAppendData(characters, 0, Text::defaultLengthLimit);
506 while (currentPosition < characters.length()) {
507 RefPtr<Text> textNode = Text::createWithLengthLimit(task.parent->document(), shouldUseAtomicString ? AtomicString(characters).string() : characters, currentPosition);
508 // 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.
509 if (!textNode->length()) {
510 String substring = characters.substring(currentPosition);
511 textNode = Text::create(task.parent->document(), shouldUseAtomicString ? AtomicString(substring).string() : substring);
514 currentPosition += textNode->length();
515 ASSERT(currentPosition <= characters.length());
516 task.child = textNode.release();
522 PassRefPtr<Element> HTMLConstructionSite::createElement(AtomicHTMLToken* token, const AtomicString& namespaceURI)
524 QualifiedName tagName(nullAtom, token->name(), namespaceURI);
525 RefPtr<Element> element = ownerDocumentForCurrentNode()->createElement(tagName, true);
526 setAttributes(element.get(), token, m_parserContentPolicy);
527 return element.release();
530 inline Document* HTMLConstructionSite::ownerDocumentForCurrentNode()
532 #if ENABLE(TEMPLATE_ELEMENT)
533 if (currentNode()->hasTagName(templateTag))
534 return toHTMLTemplateElement(currentElement())->content()->document();
536 return currentNode()->document();
539 PassRefPtr<Element> HTMLConstructionSite::createHTMLElement(AtomicHTMLToken* token)
541 QualifiedName tagName(nullAtom, token->name(), xhtmlNamespaceURI);
542 // FIXME: This can't use HTMLConstructionSite::createElement because we
543 // have to pass the current form element. We should rework form association
544 // to occur after construction to allow better code sharing here.
545 RefPtr<Element> element = HTMLElementFactory::createHTMLElement(tagName, ownerDocumentForCurrentNode(), form(), true);
546 setAttributes(element.get(), token, m_parserContentPolicy);
547 ASSERT(element->isHTMLElement());
548 return element.release();
551 PassRefPtr<HTMLStackItem> HTMLConstructionSite::createElementFromSavedToken(HTMLStackItem* item)
553 RefPtr<Element> element;
554 // NOTE: Moving from item -> token -> item copies the Attribute vector twice!
555 AtomicHTMLToken fakeToken(HTMLToken::StartTag, item->localName(), item->attributes());
556 if (item->namespaceURI() == HTMLNames::xhtmlNamespaceURI)
557 element = createHTMLElement(&fakeToken);
559 element = createElement(&fakeToken, item->namespaceURI());
560 return HTMLStackItem::create(element.release(), &fakeToken, item->namespaceURI());
563 bool HTMLConstructionSite::indexOfFirstUnopenFormattingElement(unsigned& firstUnopenElementIndex) const
565 if (m_activeFormattingElements.isEmpty())
567 unsigned index = m_activeFormattingElements.size();
570 const HTMLFormattingElementList::Entry& entry = m_activeFormattingElements.at(index);
571 if (entry.isMarker() || m_openElements.contains(entry.element())) {
572 firstUnopenElementIndex = index + 1;
573 return firstUnopenElementIndex < m_activeFormattingElements.size();
576 firstUnopenElementIndex = index;
580 void HTMLConstructionSite::reconstructTheActiveFormattingElements()
582 unsigned firstUnopenElementIndex;
583 if (!indexOfFirstUnopenFormattingElement(firstUnopenElementIndex))
586 unsigned unopenEntryIndex = firstUnopenElementIndex;
587 ASSERT(unopenEntryIndex < m_activeFormattingElements.size());
588 for (; unopenEntryIndex < m_activeFormattingElements.size(); ++unopenEntryIndex) {
589 HTMLFormattingElementList::Entry& unopenedEntry = m_activeFormattingElements.at(unopenEntryIndex);
590 RefPtr<HTMLStackItem> reconstructed = createElementFromSavedToken(unopenedEntry.stackItem().get());
591 attachLater(currentNode(), reconstructed->node());
592 m_openElements.push(reconstructed);
593 unopenedEntry.replaceElement(reconstructed.release());
597 void HTMLConstructionSite::generateImpliedEndTagsWithExclusion(const AtomicString& tagName)
599 while (hasImpliedEndTag(currentStackItem()) && !currentStackItem()->hasLocalName(tagName))
600 m_openElements.pop();
603 void HTMLConstructionSite::generateImpliedEndTags()
605 while (hasImpliedEndTag(currentStackItem()))
606 m_openElements.pop();
609 bool HTMLConstructionSite::inQuirksMode()
611 return m_inQuirksMode;
614 void HTMLConstructionSite::findFosterSite(HTMLConstructionSiteTask& task)
616 #if ENABLE(TEMPLATE_ELEMENT)
617 // 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!)
618 HTMLElementStack::ElementRecord* lastTemplateElement = m_openElements.topmost(templateTag.localName());
619 if (lastTemplateElement && !m_openElements.inTableScope(tableTag)) {
620 task.parent = lastTemplateElement->element();
626 HTMLElementStack::ElementRecord* lastTableElementRecord = m_openElements.topmost(tableTag.localName());
627 if (lastTableElementRecord) {
628 Element* lastTableElement = lastTableElementRecord->element();
629 ContainerNode* parent = lastTableElement->parentNode();
630 // When parsing HTML fragments, we skip step 4.2 ("Let root be a new html element with no attributes") for efficiency,
631 // 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.
632 if (parent && (parent->isElementNode() || (m_isParsingFragment && parent == m_openElements.rootNode()))) {
633 task.parent = parent;
634 task.nextChild = lastTableElement;
637 task.parent = lastTableElementRecord->next()->element();
641 task.parent = m_openElements.rootNode(); // DocumentFragment
644 bool HTMLConstructionSite::shouldFosterParent() const
646 return m_redirectAttachToFosterParent
647 && currentStackItem()->isElementNode()
648 && currentStackItem()->causesFosterParenting();
651 void HTMLConstructionSite::fosterParent(PassRefPtr<Node> node)
653 HTMLConstructionSiteTask task;
654 findFosterSite(task);
658 m_attachmentQueue.append(task);