HTMLConstructionSite.cpp [plain text]
#include "config.h"
#include "HTMLTreeBuilder.h"
#include "Comment.h"
#include "DocumentFragment.h"
#include "DocumentType.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
#include "HTMLElementFactory.h"
#include "HTMLFormElement.h"
#include "HTMLHtmlElement.h"
#include "HTMLImageElement.h"
#include "HTMLOptGroupElement.h"
#include "HTMLOptionElement.h"
#include "HTMLParserIdioms.h"
#include "HTMLPictureElement.h"
#include "HTMLScriptElement.h"
#include "HTMLTemplateElement.h"
#include "NotImplemented.h"
#include "SVGElement.h"
#include "Text.h"
namespace WebCore {
using namespace HTMLNames;
static inline void setAttributes(Element* element, AtomicHTMLToken* token, ParserContentPolicy parserContentPolicy)
{
if (!scriptingContentIsAllowed(parserContentPolicy))
element->stripScriptingAttributes(token->attributes());
element->parserSetAttributes(token->attributes());
}
static bool hasImpliedEndTag(const HTMLStackItem& item)
{
return item.hasTagName(ddTag)
|| item.hasTagName(dtTag)
|| item.hasTagName(liTag)
|| is<HTMLOptionElement>(item.node())
|| is<HTMLOptGroupElement>(item.node())
|| item.hasTagName(pTag)
|| item.hasTagName(rbTag)
|| item.hasTagName(rpTag)
|| item.hasTagName(rtTag)
|| item.hasTagName(rtcTag);
}
static bool shouldUseLengthLimit(const ContainerNode* node)
{
return !node->hasTagName(scriptTag)
&& !node->hasTagName(styleTag)
&& !node->hasTagName(SVGNames::scriptTag);
}
static inline bool causesFosterParenting(const HTMLStackItem& item)
{
return item.hasTagName(HTMLNames::tableTag)
|| item.hasTagName(HTMLNames::tbodyTag)
|| item.hasTagName(HTMLNames::tfootTag)
|| item.hasTagName(HTMLNames::theadTag)
|| item.hasTagName(HTMLNames::trTag);
}
static inline bool isAllWhitespace(const String& string)
{
return string.isAllSpecialCharacters<isHTMLSpace>();
}
static inline void insert(HTMLConstructionSiteTask& task)
{
#if ENABLE(TEMPLATE_ELEMENT)
if (is<HTMLTemplateElement>(*task.parent))
task.parent = downcast<HTMLTemplateElement>(*task.parent).content();
#endif
if (ContainerNode* parent = task.child->parentNode())
parent->parserRemoveChild(*task.child);
if (task.nextChild)
task.parent->parserInsertBefore(task.child.get(), task.nextChild.get());
else
task.parent->parserAppendChild(task.child.get());
}
static inline void executeInsertTask(HTMLConstructionSiteTask& task)
{
ASSERT(task.operation == HTMLConstructionSiteTask::Insert);
insert(task);
task.child->beginParsingChildren();
if (task.selfClosing)
task.child->finishParsingChildren();
}
static inline void executeReparentTask(HTMLConstructionSiteTask& task)
{
ASSERT(task.operation == HTMLConstructionSiteTask::Reparent);
if (ContainerNode* parent = task.child->parentNode())
parent->parserRemoveChild(*task.child);
task.parent->parserAppendChild(task.child);
}
static inline void executeInsertAlreadyParsedChildTask(HTMLConstructionSiteTask& task)
{
ASSERT(task.operation == HTMLConstructionSiteTask::InsertAlreadyParsedChild);
insert(task);
}
static inline void executeTakeAllChildrenTask(HTMLConstructionSiteTask& task)
{
ASSERT(task.operation == HTMLConstructionSiteTask::TakeAllChildren);
task.parent->takeAllChildrenFrom(task.oldParent());
}
static inline void executeTask(HTMLConstructionSiteTask& task)
{
switch (task.operation) {
case HTMLConstructionSiteTask::Insert:
executeInsertTask(task);
return;
case HTMLConstructionSiteTask::InsertAlreadyParsedChild:
executeInsertAlreadyParsedChildTask(task);
return;
case HTMLConstructionSiteTask::Reparent:
executeReparentTask(task);
return;
case HTMLConstructionSiteTask::TakeAllChildren:
executeTakeAllChildrenTask(task);
return;
}
ASSERT_NOT_REACHED();
}
void HTMLConstructionSite::attachLater(ContainerNode* parent, PassRefPtr<Node> prpChild, bool selfClosing)
{
ASSERT(scriptingContentIsAllowed(m_parserContentPolicy) || !is<Element>(*prpChild) || !toScriptElementIfPossible(downcast<Element>(prpChild.get())));
ASSERT(pluginContentIsAllowed(m_parserContentPolicy) || !prpChild->isPluginElement());
HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert);
task.parent = parent;
task.child = prpChild;
task.selfClosing = selfClosing;
if (shouldFosterParent()) {
fosterParent(task.child);
return;
}
if (m_openElements.stackDepth() > m_maximumDOMTreeDepth && task.parent->parentNode())
task.parent = task.parent->parentNode();
ASSERT(task.parent);
m_taskQueue.append(task);
}
void HTMLConstructionSite::executeQueuedTasks()
{
const size_t size = m_taskQueue.size();
if (!size)
return;
TaskQueue queue = WTF::move(m_taskQueue);
for (size_t i = 0; i < size; ++i)
executeTask(queue[i]);
}
HTMLConstructionSite::HTMLConstructionSite(Document& document, ParserContentPolicy parserContentPolicy, unsigned maximumDOMTreeDepth)
: m_document(&document)
, m_attachmentRoot(&document)
, m_parserContentPolicy(parserContentPolicy)
, m_isParsingFragment(false)
, m_redirectAttachToFosterParent(false)
, m_maximumDOMTreeDepth(maximumDOMTreeDepth)
, m_inQuirksMode(document.inQuirksMode())
{
ASSERT(m_document->isHTMLDocument() || m_document->isXHTMLDocument());
}
HTMLConstructionSite::HTMLConstructionSite(DocumentFragment& fragment, ParserContentPolicy parserContentPolicy, unsigned maximumDOMTreeDepth)
: m_document(&fragment.document())
, m_attachmentRoot(&fragment)
, m_parserContentPolicy(parserContentPolicy)
, m_isParsingFragment(true)
, m_redirectAttachToFosterParent(false)
, m_maximumDOMTreeDepth(maximumDOMTreeDepth)
, m_inQuirksMode(fragment.document().inQuirksMode())
{
ASSERT(m_document->isHTMLDocument() || m_document->isXHTMLDocument());
}
HTMLConstructionSite::~HTMLConstructionSite()
{
}
void HTMLConstructionSite::detach()
{
m_document = 0;
m_attachmentRoot = 0;
}
void HTMLConstructionSite::setForm(HTMLFormElement* form)
{
ASSERT(!m_form);
m_form = form;
}
PassRefPtr<HTMLFormElement> HTMLConstructionSite::takeForm()
{
return m_form.release();
}
void HTMLConstructionSite::dispatchDocumentElementAvailableIfNeeded()
{
ASSERT(m_document);
if (m_document->frame() && !m_isParsingFragment)
m_document->frame()->injectUserScripts(InjectAtDocumentStart);
}
void HTMLConstructionSite::insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken* token)
{
Ref<HTMLHtmlElement> element = HTMLHtmlElement::create(*m_document);
setAttributes(element.ptr(), token, m_parserContentPolicy);
attachLater(m_attachmentRoot, element.ptr());
m_openElements.pushHTMLHtmlElement(HTMLStackItem::create(element.copyRef(), *token));
executeQueuedTasks();
element->insertedByParser();
dispatchDocumentElementAvailableIfNeeded();
}
void HTMLConstructionSite::mergeAttributesFromTokenIntoElement(AtomicHTMLToken* token, Element* element)
{
if (token->attributes().isEmpty())
return;
for (unsigned i = 0; i < token->attributes().size(); ++i) {
const Attribute& tokenAttribute = token->attributes().at(i);
if (!element->elementData() || !element->findAttributeByName(tokenAttribute.name()))
element->setAttribute(tokenAttribute.name(), tokenAttribute.value());
}
}
void HTMLConstructionSite::insertHTMLHtmlStartTagInBody(AtomicHTMLToken* token)
{
if (m_isParsingFragment)
return;
mergeAttributesFromTokenIntoElement(token, &m_openElements.htmlElement());
}
void HTMLConstructionSite::insertHTMLBodyStartTagInBody(AtomicHTMLToken* token)
{
mergeAttributesFromTokenIntoElement(token, &m_openElements.bodyElement());
}
void HTMLConstructionSite::setDefaultCompatibilityMode()
{
if (m_isParsingFragment)
return;
if (m_document->isSrcdocDocument())
return;
setCompatibilityMode(DocumentCompatibilityMode::QuirksMode);
}
void HTMLConstructionSite::setCompatibilityMode(DocumentCompatibilityMode mode)
{
m_inQuirksMode = (mode == DocumentCompatibilityMode::QuirksMode);
m_document->setCompatibilityMode(mode);
}
void HTMLConstructionSite::setCompatibilityModeFromDoctype(const String& name, const String& publicId, const String& systemId)
{
if (name != "html"
|| publicId.startsWith("+//Silmaril//dtd html Pro v0r11 19970101//", false)
|| publicId.startsWith("-//AdvaSoft Ltd//DTD HTML 3.0 asWedit + extensions//", false)
|| publicId.startsWith("-//AS//DTD HTML 3.0 asWedit + extensions//", false)
|| publicId.startsWith("-//IETF//DTD HTML 2.0 Level 1//", false)
|| publicId.startsWith("-//IETF//DTD HTML 2.0 Level 2//", false)
|| publicId.startsWith("-//IETF//DTD HTML 2.0 Strict Level 1//", false)
|| publicId.startsWith("-//IETF//DTD HTML 2.0 Strict Level 2//", false)
|| publicId.startsWith("-//IETF//DTD HTML 2.0 Strict//", false)
|| publicId.startsWith("-//IETF//DTD HTML 2.0//", false)
|| publicId.startsWith("-//IETF//DTD HTML 2.1E//", false)
|| publicId.startsWith("-//IETF//DTD HTML 3.0//", false)
|| publicId.startsWith("-//IETF//DTD HTML 3.2 Final//", false)
|| publicId.startsWith("-//IETF//DTD HTML 3.2//", false)
|| publicId.startsWith("-//IETF//DTD HTML 3//", false)
|| publicId.startsWith("-//IETF//DTD HTML Level 0//", false)
|| publicId.startsWith("-//IETF//DTD HTML Level 1//", false)
|| publicId.startsWith("-//IETF//DTD HTML Level 2//", false)
|| publicId.startsWith("-//IETF//DTD HTML Level 3//", false)
|| publicId.startsWith("-//IETF//DTD HTML Strict Level 0//", false)
|| publicId.startsWith("-//IETF//DTD HTML Strict Level 1//", false)
|| publicId.startsWith("-//IETF//DTD HTML Strict Level 2//", false)
|| publicId.startsWith("-//IETF//DTD HTML Strict Level 3//", false)
|| publicId.startsWith("-//IETF//DTD HTML Strict//", false)
|| publicId.startsWith("-//IETF//DTD HTML//", false)
|| publicId.startsWith("-//Metrius//DTD Metrius Presentational//", false)
|| publicId.startsWith("-//Microsoft//DTD Internet Explorer 2.0 HTML Strict//", false)
|| publicId.startsWith("-//Microsoft//DTD Internet Explorer 2.0 HTML//", false)
|| publicId.startsWith("-//Microsoft//DTD Internet Explorer 2.0 Tables//", false)
|| publicId.startsWith("-//Microsoft//DTD Internet Explorer 3.0 HTML Strict//", false)
|| publicId.startsWith("-//Microsoft//DTD Internet Explorer 3.0 HTML//", false)
|| publicId.startsWith("-//Microsoft//DTD Internet Explorer 3.0 Tables//", false)
|| publicId.startsWith("-//Netscape Comm. Corp.//DTD HTML//", false)
|| publicId.startsWith("-//Netscape Comm. Corp.//DTD Strict HTML//", false)
|| publicId.startsWith("-//O'Reilly and Associates//DTD HTML 2.0//", false)
|| publicId.startsWith("-//O'Reilly and Associates//DTD HTML Extended 1.0//", false)
|| publicId.startsWith("-//O'Reilly and Associates//DTD HTML Extended Relaxed 1.0//", false)
|| publicId.startsWith("-//SoftQuad Software//DTD HoTMetaL PRO 6.0::19990601::extensions to HTML 4.0//", false)
|| publicId.startsWith("-//SoftQuad//DTD HoTMetaL PRO 4.0::19971010::extensions to HTML 4.0//", false)
|| publicId.startsWith("-//Spyglass//DTD HTML 2.0 Extended//", false)
|| publicId.startsWith("-//SQ//DTD HTML 2.0 HoTMetaL + extensions//", false)
|| publicId.startsWith("-//Sun Microsystems Corp.//DTD HotJava HTML//", false)
|| publicId.startsWith("-//Sun Microsystems Corp.//DTD HotJava Strict HTML//", false)
|| publicId.startsWith("-//W3C//DTD HTML 3 1995-03-24//", false)
|| publicId.startsWith("-//W3C//DTD HTML 3.2 Draft//", false)
|| publicId.startsWith("-//W3C//DTD HTML 3.2 Final//", false)
|| publicId.startsWith("-//W3C//DTD HTML 3.2//", false)
|| publicId.startsWith("-//W3C//DTD HTML 3.2S Draft//", false)
|| publicId.startsWith("-//W3C//DTD HTML 4.0 Frameset//", false)
|| publicId.startsWith("-//W3C//DTD HTML 4.0 Transitional//", false)
|| publicId.startsWith("-//W3C//DTD HTML Experimental 19960712//", false)
|| publicId.startsWith("-//W3C//DTD HTML Experimental 970421//", false)
|| publicId.startsWith("-//W3C//DTD W3 HTML//", false)
|| publicId.startsWith("-//W3O//DTD W3 HTML 3.0//", false)
|| equalIgnoringCase(publicId, "-//W3O//DTD W3 HTML Strict 3.0//EN//")
|| publicId.startsWith("-//WebTechs//DTD Mozilla HTML 2.0//", false)
|| publicId.startsWith("-//WebTechs//DTD Mozilla HTML//", false)
|| equalIgnoringCase(publicId, "-/W3C/DTD HTML 4.0 Transitional/EN")
|| equalIgnoringCase(publicId, "HTML")
|| equalIgnoringCase(systemId, "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd")
|| (systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Frameset//", false))
|| (systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Transitional//", false))) {
setCompatibilityMode(DocumentCompatibilityMode::QuirksMode);
return;
}
if (publicId.startsWith("-//W3C//DTD XHTML 1.0 Frameset//", false)
|| publicId.startsWith("-//W3C//DTD XHTML 1.0 Transitional//", false)
|| (!systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Frameset//", false))
|| (!systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Transitional//", false))) {
setCompatibilityMode(DocumentCompatibilityMode::LimitedQuirksMode);
return;
}
setCompatibilityMode(DocumentCompatibilityMode::NoQuirksMode);
}
void HTMLConstructionSite::finishedParsing()
{
m_document->finishedParsing();
}
void HTMLConstructionSite::insertDoctype(AtomicHTMLToken* token)
{
ASSERT(token->type() == HTMLToken::DOCTYPE);
String publicId = token->publicIdentifier();
String systemId = token->systemIdentifier();
RefPtr<DocumentType> doctype = DocumentType::create(*m_document, token->name(), publicId, systemId);
attachLater(m_attachmentRoot, doctype.release());
ASSERT(!m_isParsingFragment);
if (m_isParsingFragment)
return;
if (token->forceQuirks())
setCompatibilityMode(DocumentCompatibilityMode::QuirksMode);
else
setCompatibilityModeFromDoctype(token->name(), publicId, systemId);
}
void HTMLConstructionSite::insertComment(AtomicHTMLToken* token)
{
ASSERT(token->type() == HTMLToken::Comment);
attachLater(¤tNode(), Comment::create(ownerDocumentForCurrentNode(), token->comment()));
}
void HTMLConstructionSite::insertCommentOnDocument(AtomicHTMLToken* token)
{
ASSERT(token->type() == HTMLToken::Comment);
attachLater(m_attachmentRoot, Comment::create(*m_document, token->comment()));
}
void HTMLConstructionSite::insertCommentOnHTMLHtmlElement(AtomicHTMLToken* token)
{
ASSERT(token->type() == HTMLToken::Comment);
ContainerNode& parent = m_openElements.rootNode();
attachLater(&parent, Comment::create(parent.document(), token->comment()));
}
void HTMLConstructionSite::insertHTMLHeadElement(AtomicHTMLToken* token)
{
ASSERT(!shouldFosterParent());
m_head = HTMLStackItem::create(*createHTMLElement(token), *token);
attachLater(¤tNode(), &m_head->element());
m_openElements.pushHTMLHeadElement(m_head);
}
void HTMLConstructionSite::insertHTMLBodyElement(AtomicHTMLToken* token)
{
ASSERT(!shouldFosterParent());
RefPtr<Element> body = createHTMLElement(token);
attachLater(¤tNode(), body.get());
m_openElements.pushHTMLBodyElement(HTMLStackItem::create(body.releaseNonNull(), *token));
}
void HTMLConstructionSite::insertHTMLFormElement(AtomicHTMLToken* token, bool isDemoted)
{
RefPtr<Element> element = createHTMLElement(token);
ASSERT(is<HTMLFormElement>(*element));
m_form = static_pointer_cast<HTMLFormElement>(element.release());
m_form->setDemoted(isDemoted);
attachLater(¤tNode(), m_form);
m_openElements.push(HTMLStackItem::create(*m_form, *token));
}
void HTMLConstructionSite::insertHTMLElement(AtomicHTMLToken* token)
{
RefPtr<Element> element = createHTMLElement(token);
attachLater(¤tNode(), element);
m_openElements.push(HTMLStackItem::create(element.releaseNonNull(), *token));
}
void HTMLConstructionSite::insertSelfClosingHTMLElement(AtomicHTMLToken* token)
{
ASSERT(token->type() == HTMLToken::StartTag);
attachLater(¤tNode(), createHTMLElement(token), true);
}
void HTMLConstructionSite::insertFormattingElement(AtomicHTMLToken* token)
{
insertHTMLElement(token);
m_activeFormattingElements.append(¤tStackItem());
}
void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken* token)
{
const bool parserInserted = m_parserContentPolicy != AllowScriptingContentAndDoNotMarkAlreadyStarted;
const bool alreadyStarted = m_isParsingFragment && parserInserted;
RefPtr<HTMLScriptElement> element = HTMLScriptElement::create(scriptTag, ownerDocumentForCurrentNode(), parserInserted, alreadyStarted);
setAttributes(element.get(), token, m_parserContentPolicy);
if (scriptingContentIsAllowed(m_parserContentPolicy))
attachLater(¤tNode(), element);
m_openElements.push(HTMLStackItem::create(element.releaseNonNull(), *token));
}
void HTMLConstructionSite::insertForeignElement(AtomicHTMLToken* token, const AtomicString& namespaceURI)
{
ASSERT(token->type() == HTMLToken::StartTag);
notImplemented();
RefPtr<Element> element = createElement(token, namespaceURI);
if (scriptingContentIsAllowed(m_parserContentPolicy) || !toScriptElementIfPossible(element.get()))
attachLater(¤tNode(), element, token->selfClosing());
if (!token->selfClosing())
m_openElements.push(HTMLStackItem::create(element.releaseNonNull(), *token, namespaceURI));
}
void HTMLConstructionSite::insertTextNode(const String& characters, WhitespaceMode whitespaceMode)
{
HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert);
task.parent = ¤tNode();
if (shouldFosterParent())
findFosterSite(task);
#if ENABLE(TEMPLATE_ELEMENT)
if (is<HTMLTemplateElement>(*task.parent))
task.parent = downcast<HTMLTemplateElement>(*task.parent).content();
#endif
bool shouldUseAtomicString = whitespaceMode == AllWhitespace
|| (whitespaceMode == WhitespaceUnknown && isAllWhitespace(characters));
unsigned currentPosition = 0;
unsigned lengthLimit = shouldUseLengthLimit(task.parent.get()) ? Text::defaultLengthLimit : std::numeric_limits<unsigned>::max();
Node* previousChild = task.nextChild ? task.nextChild->previousSibling() : task.parent->lastChild();
if (is<Text>(previousChild)) {
Text& textNode = downcast<Text>(*previousChild);
currentPosition = textNode.parserAppendData(characters, 0, lengthLimit);
}
while (currentPosition < characters.length()) {
Ref<Text> textNode = Text::createWithLengthLimit(task.parent->document(), shouldUseAtomicString ? AtomicString(characters).string() : characters, currentPosition, lengthLimit);
if (!textNode->length()) {
String substring = characters.substring(currentPosition);
textNode = Text::create(task.parent->document(), shouldUseAtomicString ? AtomicString(substring).string() : substring);
}
currentPosition += textNode->length();
ASSERT(currentPosition <= characters.length());
task.child = WTF::move(textNode);
executeTask(task);
}
}
void HTMLConstructionSite::reparent(HTMLElementStack::ElementRecord& newParent, HTMLElementStack::ElementRecord& child)
{
HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Reparent);
task.parent = &newParent.node();
task.child = &child.element();
m_taskQueue.append(task);
}
void HTMLConstructionSite::reparent(HTMLElementStack::ElementRecord& newParent, HTMLStackItem& child)
{
HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Reparent);
task.parent = &newParent.node();
task.child = &child.element();
m_taskQueue.append(task);
}
void HTMLConstructionSite::insertAlreadyParsedChild(HTMLStackItem& newParent, HTMLElementStack::ElementRecord& child)
{
if (causesFosterParenting(newParent)) {
fosterParent(&child.element());
return;
}
HTMLConstructionSiteTask task(HTMLConstructionSiteTask::InsertAlreadyParsedChild);
task.parent = &newParent.node();
task.child = &child.element();
m_taskQueue.append(task);
}
void HTMLConstructionSite::takeAllChildren(HTMLStackItem& newParent, HTMLElementStack::ElementRecord& oldParent)
{
HTMLConstructionSiteTask task(HTMLConstructionSiteTask::TakeAllChildren);
task.parent = &newParent.node();
task.child = &oldParent.node();
m_taskQueue.append(task);
}
PassRefPtr<Element> HTMLConstructionSite::createElement(AtomicHTMLToken* token, const AtomicString& namespaceURI)
{
QualifiedName tagName(nullAtom, token->name(), namespaceURI);
RefPtr<Element> element = ownerDocumentForCurrentNode().createElement(tagName, true);
setAttributes(element.get(), token, m_parserContentPolicy);
return element.release();
}
inline Document& HTMLConstructionSite::ownerDocumentForCurrentNode()
{
#if ENABLE(TEMPLATE_ELEMENT)
if (is<HTMLTemplateElement>(currentNode()))
return downcast<HTMLTemplateElement>(currentNode()).content()->document();
#endif
return currentNode().document();
}
PassRefPtr<Element> HTMLConstructionSite::createHTMLElement(AtomicHTMLToken* token)
{
QualifiedName tagName(nullAtom, token->name(), xhtmlNamespaceURI);
Document& ownerDocument = ownerDocumentForCurrentNode();
bool insideTemplateElement = !ownerDocument.frame();
RefPtr<Element> element = HTMLElementFactory::createElement(tagName, ownerDocument, insideTemplateElement ? nullptr : form(), true);
if (is<HTMLPictureElement>(currentNode()) && is<HTMLImageElement>(*element.get()))
downcast<HTMLImageElement>(*element.get()).setPictureElement(&downcast<HTMLPictureElement>(currentNode()));
setAttributes(element.get(), token, m_parserContentPolicy);
ASSERT(element->isHTMLElement());
return element.release();
}
PassRefPtr<HTMLStackItem> HTMLConstructionSite::createElementFromSavedToken(HTMLStackItem* item)
{
RefPtr<Element> element;
AtomicHTMLToken fakeToken(HTMLToken::StartTag, item->localName(), Vector<Attribute>(item->attributes()));
if (item->namespaceURI() == HTMLNames::xhtmlNamespaceURI)
element = createHTMLElement(&fakeToken);
else
element = createElement(&fakeToken, item->namespaceURI());
return HTMLStackItem::create(element.releaseNonNull(), fakeToken, item->namespaceURI());
}
bool HTMLConstructionSite::indexOfFirstUnopenFormattingElement(unsigned& firstUnopenElementIndex) const
{
if (m_activeFormattingElements.isEmpty())
return false;
unsigned index = m_activeFormattingElements.size();
do {
--index;
const HTMLFormattingElementList::Entry& entry = m_activeFormattingElements.at(index);
if (entry.isMarker() || m_openElements.contains(&entry.element())) {
firstUnopenElementIndex = index + 1;
return firstUnopenElementIndex < m_activeFormattingElements.size();
}
} while (index);
firstUnopenElementIndex = index;
return true;
}
void HTMLConstructionSite::reconstructTheActiveFormattingElements()
{
unsigned firstUnopenElementIndex;
if (!indexOfFirstUnopenFormattingElement(firstUnopenElementIndex))
return;
unsigned unopenEntryIndex = firstUnopenElementIndex;
ASSERT(unopenEntryIndex < m_activeFormattingElements.size());
for (; unopenEntryIndex < m_activeFormattingElements.size(); ++unopenEntryIndex) {
HTMLFormattingElementList::Entry& unopenedEntry = m_activeFormattingElements.at(unopenEntryIndex);
RefPtr<HTMLStackItem> reconstructed = createElementFromSavedToken(unopenedEntry.stackItem());
attachLater(¤tNode(), &reconstructed->node());
m_openElements.push(reconstructed);
unopenedEntry.replaceElement(reconstructed.release());
}
}
void HTMLConstructionSite::generateImpliedEndTagsWithExclusion(const AtomicString& tagName)
{
while (hasImpliedEndTag(currentStackItem()) && !currentStackItem().matchesHTMLTag(tagName))
m_openElements.pop();
}
void HTMLConstructionSite::generateImpliedEndTags()
{
while (hasImpliedEndTag(currentStackItem()))
m_openElements.pop();
}
bool HTMLConstructionSite::inQuirksMode()
{
return m_inQuirksMode;
}
void HTMLConstructionSite::findFosterSite(HTMLConstructionSiteTask& task)
{
#if ENABLE(TEMPLATE_ELEMENT)
HTMLElementStack::ElementRecord* lastTemplateElement = m_openElements.topmost(templateTag.localName());
if (lastTemplateElement && !m_openElements.inTableScope(tableTag)) {
task.parent = &lastTemplateElement->element();
return;
}
#endif
HTMLElementStack::ElementRecord* lastTableElementRecord = m_openElements.topmost(tableTag.localName());
if (lastTableElementRecord) {
Element& lastTableElement = lastTableElementRecord->element();
ContainerNode* parent = lastTableElement.parentNode();
bool parentCanBeFosterParent = parent && (parent->isElementNode() || (m_isParsingFragment && parent == &m_openElements.rootNode()));
#if ENABLE(TEMPLATE_ELEMENT)
parentCanBeFosterParent = parentCanBeFosterParent || (is<DocumentFragment>(parent) && downcast<DocumentFragment>(parent)->isTemplateContent());
#endif
if (parentCanBeFosterParent) {
task.parent = parent;
task.nextChild = &lastTableElement;
return;
}
task.parent = &lastTableElementRecord->next()->element();
return;
}
task.parent = &m_openElements.rootNode(); }
bool HTMLConstructionSite::shouldFosterParent() const
{
return m_redirectAttachToFosterParent
&& causesFosterParenting(currentStackItem());
}
void HTMLConstructionSite::fosterParent(PassRefPtr<Node> node)
{
HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert);
findFosterSite(task);
task.child = node;
ASSERT(task.parent);
m_taskQueue.append(task);
}
}