summaryrefslogtreecommitdiffstats
path: root/WebCore/html/HTMLConstructionSite.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/html/HTMLConstructionSite.cpp')
-rw-r--r--WebCore/html/HTMLConstructionSite.cpp137
1 files changed, 110 insertions, 27 deletions
diff --git a/WebCore/html/HTMLConstructionSite.cpp b/WebCore/html/HTMLConstructionSite.cpp
index 5745625..e9bb762 100644
--- a/WebCore/html/HTMLConstructionSite.cpp
+++ b/WebCore/html/HTMLConstructionSite.cpp
@@ -32,6 +32,8 @@
#include "Element.h"
#include "Frame.h"
#include "HTMLDocument.h"
+#include "HTMLElementFactory.h"
+#include "HTMLFormElement.h"
#include "HTMLHtmlElement.h"
#include "HTMLNames.h"
#include "HTMLScriptElement.h"
@@ -70,6 +72,15 @@ bool hasImpliedEndTag(Element* element)
|| element->hasTagName(rtTag);
}
+bool causesFosterParenting(const QualifiedName& tagName)
+{
+ return tagName == tableTag
+ || tagName == tbodyTag
+ || tagName == tfootTag
+ || tagName == theadTag
+ || tagName == trTag;
+}
+
} // namespace
template<typename ChildType>
@@ -80,7 +91,7 @@ PassRefPtr<ChildType> HTMLConstructionSite::attach(Node* parent, PassRefPtr<Chil
// FIXME: It's confusing that HTMLConstructionSite::attach does the magic
// redirection to the foster parent but HTMLConstructionSite::attachAtSite
// doesn't. It feels like we're missing a concept somehow.
- if (m_redirectAttachToFosterParent) {
+ if (shouldFosterParent()) {
fosterParent(child.get());
ASSERT(child->attached());
return child.release();
@@ -92,9 +103,10 @@ PassRefPtr<ChildType> HTMLConstructionSite::attach(Node* parent, PassRefPtr<Chil
// |parent| to hold a ref at this point. In the common case (at least
// for elements), however, we'll get to use this ref in the stack of
// open elements.
- ASSERT(parent->attached());
- ASSERT(!child->attached());
- child->attach();
+ if (parent->attached()) {
+ ASSERT(!child->attached());
+ child->attach();
+ }
return child.release();
}
@@ -107,8 +119,7 @@ void HTMLConstructionSite::attachAtSite(const AttachmentSite& site, PassRefPtr<N
ExceptionCode ec = 0;
site.parent->insertBefore(child, site.nextChild, ec);
ASSERT(!ec);
- ASSERT(site.parent->attached());
- if (!child->attached())
+ if (site.parent->attached() && !child->attached())
child->attach();
return;
}
@@ -116,14 +127,14 @@ void HTMLConstructionSite::attachAtSite(const AttachmentSite& site, PassRefPtr<N
// It's slightly unfortunate that we need to hold a reference to child
// here to call attach(). We should investigate whether we can rely on
// |site.parent| to hold a ref at this point.
- ASSERT(site.parent->attached());
- if (!child->attached())
+ if (site.parent->attached() && !child->attached())
child->attach();
}
-HTMLConstructionSite::HTMLConstructionSite(Document* document, FragmentScriptingPermission scriptingPermission)
+HTMLConstructionSite::HTMLConstructionSite(Document* document, FragmentScriptingPermission scriptingPermission, bool isParsingFragment)
: m_document(document)
, m_fragmentScriptingPermission(scriptingPermission)
+ , m_isParsingFragment(isParsingFragment)
, m_redirectAttachToFosterParent(false)
{
}
@@ -132,11 +143,23 @@ HTMLConstructionSite::~HTMLConstructionSite()
{
}
+PassRefPtr<HTMLFormElement> HTMLConstructionSite::takeForm()
+{
+ return m_form.release();
+}
+
+void HTMLConstructionSite::dispatchDocumentElementAvailableIfNeeded()
+{
+ if (m_document->frame() && !m_isParsingFragment)
+ m_document->frame()->loader()->dispatchDocumentElementAvailable();
+}
+
void HTMLConstructionSite::insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken& token)
{
RefPtr<Element> element = HTMLHtmlElement::create(m_document);
element->setAttributeMap(token.takeAtributes(), m_fragmentScriptingPermission);
m_openElements.pushHTMLHtmlElement(attach(m_document, element.release()));
+ dispatchDocumentElementAvailableIfNeeded();
}
void HTMLConstructionSite::mergeAttributesFromTokenIntoElement(AtomicHTMLToken& token, Element* element)
@@ -193,40 +216,52 @@ void HTMLConstructionSite::insertCommentOnHTMLHtmlElement(AtomicHTMLToken& token
attach(m_openElements.htmlElement(), Comment::create(m_document, token.comment()));
}
-PassRefPtr<Element> HTMLConstructionSite::createHTMLElementAndAttachToCurrent(AtomicHTMLToken& token)
+PassRefPtr<Element> HTMLConstructionSite::attachToCurrent(PassRefPtr<Element> child)
{
- ASSERT(token.type() == HTMLToken::StartTag);
- return attach(currentElement(), createHTMLElement(token));
+ return attach(currentElement(), child);
}
void HTMLConstructionSite::insertHTMLHtmlElement(AtomicHTMLToken& token)
{
- ASSERT(!m_redirectAttachToFosterParent);
- m_openElements.pushHTMLHtmlElement(createHTMLElementAndAttachToCurrent(token));
+ ASSERT(!shouldFosterParent());
+ m_openElements.pushHTMLHtmlElement(attachToCurrent(createHTMLElement(token)));
+ dispatchDocumentElementAvailableIfNeeded();
}
void HTMLConstructionSite::insertHTMLHeadElement(AtomicHTMLToken& token)
{
- ASSERT(!m_redirectAttachToFosterParent);
- m_head = createHTMLElementAndAttachToCurrent(token);
+ ASSERT(!shouldFosterParent());
+ m_head = attachToCurrent(createHTMLElement(token));
m_openElements.pushHTMLHeadElement(m_head);
}
void HTMLConstructionSite::insertHTMLBodyElement(AtomicHTMLToken& token)
{
- ASSERT(!m_redirectAttachToFosterParent);
- m_openElements.pushHTMLBodyElement(createHTMLElementAndAttachToCurrent(token));
+ ASSERT(!shouldFosterParent());
+ m_openElements.pushHTMLBodyElement(attachToCurrent(createHTMLElement(token)));
+}
+
+void HTMLConstructionSite::insertHTMLFormElement(AtomicHTMLToken& token)
+{
+ insertHTMLElement(token);
+ ASSERT(currentElement()->isHTMLElement());
+ ASSERT(currentElement()->hasTagName(formTag));
+ m_form = static_cast<HTMLFormElement*>(currentElement());
}
void HTMLConstructionSite::insertHTMLElement(AtomicHTMLToken& token)
{
- m_openElements.push(createHTMLElementAndAttachToCurrent(token));
+ m_openElements.push(attachToCurrent(createHTMLElement(token)));
}
void HTMLConstructionSite::insertSelfClosingHTMLElement(AtomicHTMLToken& token)
{
ASSERT(token.type() == HTMLToken::StartTag);
- createHTMLElementAndAttachToCurrent(token);
+ RefPtr<Element> element = attachToCurrent(createHTMLElement(token));
+ // Normally HTMLElementStack is responsible for calling finishParsingChildren,
+ // but self-closing elements are never in the element stack so the stack
+ // doesn't get a chance to tell them that we're done parsing their children.
+ element->finishParsingChildren();
// FIXME: Do we want to acknowledge the token's self-closing flag?
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#acknowledge-self-closing-flag
}
@@ -244,7 +279,7 @@ void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken& token)
{
RefPtr<HTMLScriptElement> element = HTMLScriptElement::create(scriptTag, m_document, true);
element->setAttributeMap(token.takeAtributes(), m_fragmentScriptingPermission);
- m_openElements.push(attach(currentElement(), element.release()));
+ m_openElements.push(attachToCurrent(element.release()));
}
void HTMLConstructionSite::insertForeignElement(AtomicHTMLToken& token, const AtomicString& namespaceURI)
@@ -252,7 +287,7 @@ void HTMLConstructionSite::insertForeignElement(AtomicHTMLToken& token, const At
ASSERT(token.type() == HTMLToken::StartTag);
notImplemented(); // parseError when xmlns or xmlns:xlink are wrong.
- RefPtr<Element> element = attach(currentElement(), createElement(token, namespaceURI));
+ RefPtr<Element> element = attachToCurrent(createElement(token, namespaceURI));
if (!token.selfClosing())
m_openElements.push(element);
}
@@ -262,7 +297,7 @@ void HTMLConstructionSite::insertTextNode(const String& characters)
AttachmentSite site;
site.parent = currentElement();
site.nextChild = 0;
- if (m_redirectAttachToFosterParent)
+ if (shouldFosterParent())
findFosterSite(site);
Node* previousChild = site.nextChild ? site.nextChild->previousSibling() : site.parent->lastChild();
@@ -287,11 +322,54 @@ PassRefPtr<Element> HTMLConstructionSite::createElement(AtomicHTMLToken& token,
PassRefPtr<Element> HTMLConstructionSite::createHTMLElement(AtomicHTMLToken& token)
{
- RefPtr<Element> element = createElement(token, xhtmlNamespaceURI);
+ QualifiedName tagName(nullAtom, token.name(), xhtmlNamespaceURI);
+ // FIXME: This can't use HTMLConstructionSite::createElement because we
+ // have to pass the current form element. We should rework form association
+ // to occur after construction to allow better code sharing here.
+ RefPtr<Element> element = HTMLElementFactory::createHTMLElement(tagName, m_document, form(), true);
+ element->setAttributeMap(token.takeAtributes(), m_fragmentScriptingPermission);
ASSERT(element->isHTMLElement());
return element.release();
}
+PassRefPtr<Element> HTMLConstructionSite::createHTMLElementFromElementRecord(HTMLElementStack::ElementRecord* record)
+{
+ return createHTMLElementFromSavedElement(record->element());
+}
+
+namespace {
+
+PassRefPtr<NamedNodeMap> cloneAttributes(Element* element)
+{
+ NamedNodeMap* attributes = element->attributes(true);
+ if (!attributes)
+ return 0;
+
+ RefPtr<NamedNodeMap> newAttributes = NamedNodeMap::create();
+ for (size_t i = 0; i < attributes->length(); ++i) {
+ Attribute* attribute = attributes->attributeItem(i);
+ RefPtr<Attribute> clone = Attribute::createMapped(attribute->name(), attribute->value());
+ newAttributes->addAttribute(clone);
+ }
+ return newAttributes.release();
+}
+
+}
+
+PassRefPtr<Element> HTMLConstructionSite::createHTMLElementFromSavedElement(Element* element)
+{
+ // FIXME: This method is wrong. We should be using the original token.
+ // Using an Element* causes us to fail examples like this:
+ // <b id="1"><p><script>document.getElementById("1").id = "2"</script></p>TEXT</b>
+ // When reconstructTheActiveFormattingElements calls this method to open
+ // a second <b> tag to wrap TEXT, it will have id "2", even though the HTML5
+ // spec implies it should be "1". Minefield matches the HTML5 spec here.
+
+ ASSERT(element->isHTMLElement()); // otherwise localName() might be wrong.
+ AtomicHTMLToken fakeToken(HTMLToken::StartTag, element->localName(), cloneAttributes(element));
+ return createHTMLElement(fakeToken);
+}
+
bool HTMLConstructionSite::indexOfFirstUnopenFormattingElement(unsigned& firstUnopenElementIndex) const
{
if (m_activeFormattingElements.isEmpty())
@@ -319,9 +397,8 @@ void HTMLConstructionSite::reconstructTheActiveFormattingElements()
ASSERT(unopenEntryIndex < m_activeFormattingElements.size());
for (; unopenEntryIndex < m_activeFormattingElements.size(); ++unopenEntryIndex) {
HTMLFormattingElementList::Entry& unopenedEntry = m_activeFormattingElements.at(unopenEntryIndex);
- // FIXME: We're supposed to save the original token in the entry.
- AtomicHTMLToken fakeToken(HTMLToken::StartTag, unopenedEntry.element()->localName());
- insertHTMLElement(fakeToken);
+ RefPtr<Element> reconstructed = createHTMLElementFromSavedElement(unopenedEntry.element());
+ m_openElements.push(attachToCurrent(reconstructed.release()));
unopenedEntry.replaceElement(currentElement());
}
}
@@ -357,6 +434,12 @@ void HTMLConstructionSite::findFosterSite(AttachmentSite& site)
site.nextChild = 0;
}
+bool HTMLConstructionSite::shouldFosterParent() const
+{
+ return m_redirectAttachToFosterParent
+ && causesFosterParenting(currentElement()->tagQName());
+}
+
void HTMLConstructionSite::fosterParent(Node* node)
{
AttachmentSite site;