Use the original token to create an element in "reconstruct the active formatting...
authorkseo@webkit.org <kseo@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 23 Jul 2012 23:15:50 +0000 (23:15 +0000)
committerkseo@webkit.org <kseo@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 23 Jul 2012 23:15:50 +0000 (23:15 +0000)
https://bugs.webkit.org/show_bug.cgi?id=91703

Reviewed by Adam Barth.

Source/WebCore:

The current WebKit HTML5 parser implementation does not hold the original token
in the stack of open elements and the active formatting elements. This is
problematic because the original token is used to create an element in
"reconstruct the active formatting elements" and "call the adoption agency".

As a workaround, WebKit uses the saved element instead of the original token
to create an element. But this causes us to fail examples like this:
<b id="1"><p><script>document.getElementById("1").id = "2"</script></p>TEXT</b>
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".

Created a ref-counted container class, HTMLStackItem to hold the original token
and the namespace URI as well as the element. Changed HTMLElementStack and
HTMLFormattingElementList to use HTMLStackItem.
Changed HTMLConstructionSite::reconstructTheActiveFormattingElements and
HTMLTreeBuilder::callTheAdoptionAgency to create an element from the saved token
instead of the saved element.

Updated test expectation for html5lib/runner-expected.txt
because now resources/scripted/adoption01.dat passes.

* html/parser/HTMLConstructionSite.cpp:
(WebCore::HTMLConstructionSite::insertHTMLHtmlStartTagBeforeHTML):
(WebCore::HTMLConstructionSite::insertHTMLHeadElement):
(WebCore::HTMLConstructionSite::insertHTMLBodyElement):
(WebCore::HTMLConstructionSite::insertHTMLFormElement):
(WebCore::HTMLConstructionSite::insertHTMLElement):
(WebCore::HTMLConstructionSite::insertFormattingElement):
(WebCore::HTMLConstructionSite::insertScriptElement):
(WebCore::HTMLConstructionSite::insertForeignElement):
(WebCore::HTMLConstructionSite::createElementFromSavedToken):
(WebCore::HTMLConstructionSite::reconstructTheActiveFormattingElements):
* html/parser/HTMLConstructionSite.h:
(HTMLConstructionSite):
(WebCore::HTMLConstructionSite::currentElementRecord):
* html/parser/HTMLElementStack.cpp:
(WebCore::HTMLElementStack::ElementRecord::ElementRecord):
(WebCore::HTMLElementStack::ElementRecord::replaceElement):
(WebCore::HTMLElementStack::pushRootNode):
(WebCore::HTMLElementStack::pushHTMLHtmlElement):
(WebCore::HTMLElementStack::pushRootNodeCommon):
(WebCore::HTMLElementStack::pushHTMLHeadElement):
(WebCore::HTMLElementStack::pushHTMLBodyElement):
(WebCore::HTMLElementStack::push):
(WebCore::HTMLElementStack::insertAbove):
(WebCore::HTMLElementStack::pushCommon):
* html/parser/HTMLElementStack.h:
(WebCore::HTMLElementStack::ElementRecord::element):
(WebCore::HTMLElementStack::ElementRecord::node):
(WebCore::HTMLElementStack::ElementRecord::stackItem):
(ElementRecord):
(HTMLElementStack):
* html/parser/HTMLFormattingElementList.cpp:
(WebCore::HTMLFormattingElementList::swapTo):
(WebCore::HTMLFormattingElementList::append):
* html/parser/HTMLFormattingElementList.h:
(WebCore::HTMLFormattingElementList::Entry::Entry):
(WebCore::HTMLFormattingElementList::Entry::isMarker):
(WebCore::HTMLFormattingElementList::Entry::stackItem):
(WebCore::HTMLFormattingElementList::Entry::element):
(WebCore::HTMLFormattingElementList::Entry::replaceElement):
(WebCore::HTMLFormattingElementList::Entry::operator==):
(WebCore::HTMLFormattingElementList::Entry::operator!=):
(Entry):
(HTMLFormattingElementList):
* html/parser/HTMLStackItem.h: Added.
(WebCore):
(HTMLStackItem):
(WebCore::HTMLStackItem::create):
(WebCore::HTMLStackItem::element):
(WebCore::HTMLStackItem::node):
(WebCore::HTMLStackItem::token):
(WebCore::HTMLStackItem::namespaceURI):
(WebCore::HTMLStackItem::HTMLStackItem):
* html/parser/HTMLTreeBuilder.cpp:
(WebCore::HTMLTreeBuilder::HTMLTreeBuilder):
(WebCore::HTMLTreeBuilder::processStartTag):
(WebCore::HTMLTreeBuilder::callTheAdoptionAgency):

LayoutTests:

Updated test expectation for html5lib/runner-expected.txt
because now resources/scripted/adoption01.dat passes.

* html5lib/runner-expected.txt:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@123399 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/html5lib/runner-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/html/parser/HTMLConstructionSite.cpp
Source/WebCore/html/parser/HTMLConstructionSite.h
Source/WebCore/html/parser/HTMLElementStack.cpp
Source/WebCore/html/parser/HTMLElementStack.h
Source/WebCore/html/parser/HTMLFormattingElementList.cpp
Source/WebCore/html/parser/HTMLFormattingElementList.h
Source/WebCore/html/parser/HTMLStackItem.h [new file with mode: 0644]
Source/WebCore/html/parser/HTMLTreeBuilder.cpp

index 5624e0d..3083c80 100644 (file)
@@ -1,3 +1,15 @@
+2012-07-23  Kwang Yul Seo  <skyul@company100.net>
+
+        Use the original token to create an element in "reconstruct the active formatting elements" and "call the adoption agency"
+        https://bugs.webkit.org/show_bug.cgi?id=91703
+
+        Reviewed by Adam Barth.
+
+        Updated test expectation for html5lib/runner-expected.txt
+        because now resources/scripted/adoption01.dat passes.
+
+        * html5lib/runner-expected.txt:
+
 2012-07-23  Rafael Brandao  <rafael.lobo@openbossa.org>
 
         [Qt] svg/{in-html,overflow,repaint,wicd} needs update after new testfonts
index 19c4b1a..cd5a20f 100644 (file)
@@ -43,33 +43,6 @@ resources/tables01.dat: PASS
 
 resources/tricky01.dat: PASS
 
-resources/scripted/adoption01.dat:
-1
-
-Test 1 of 1 in resources/scripted/adoption01.dat failed. Input:
-<p><b id="A"><script>document.getElementById("A").id = "B"</script></p>TEXT</b>
-Got:
-| <html>
-|   <head>
-|   <body>
-|     <p>
-|       <b>
-|         id="B"
-|         <script>
-|           "document.getElementById("A").id = "B""
-|     <b>
-|       id="B"
-|       "TEXT"
-Expected:
-| <html>
-|   <head>
-|   <body>
-|     <p>
-|       <b>
-|         id="B"
-|         <script>
-|           "document.getElementById("A").id = "B""
-|     <b>
-|       id="A"
-|       "TEXT"
+resources/scripted/adoption01.dat: PASS
+
 resources/scripted/webkit01.dat: PASS
index 8ff06db..3ca580d 100644 (file)
@@ -1,3 +1,90 @@
+2012-07-23  Kwang Yul Seo  <skyul@company100.net>
+
+        Use the original token to create an element in "reconstruct the active formatting elements" and "call the adoption agency"
+        https://bugs.webkit.org/show_bug.cgi?id=91703
+
+        Reviewed by Adam Barth.
+
+        The current WebKit HTML5 parser implementation does not hold the original token
+        in the stack of open elements and the active formatting elements. This is
+        problematic because the original token is used to create an element in
+        "reconstruct the active formatting elements" and "call the adoption agency".
+
+        As a workaround, WebKit uses the saved element instead of the original token
+        to create an element. But this causes us to fail examples like this:
+        <b id="1"><p><script>document.getElementById("1").id = "2"</script></p>TEXT</b>
+        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".
+
+        Created a ref-counted container class, HTMLStackItem to hold the original token
+        and the namespace URI as well as the element. Changed HTMLElementStack and
+        HTMLFormattingElementList to use HTMLStackItem.
+        Changed HTMLConstructionSite::reconstructTheActiveFormattingElements and
+        HTMLTreeBuilder::callTheAdoptionAgency to create an element from the saved token
+        instead of the saved element.
+
+        Updated test expectation for html5lib/runner-expected.txt
+        because now resources/scripted/adoption01.dat passes.
+
+        * html/parser/HTMLConstructionSite.cpp:
+        (WebCore::HTMLConstructionSite::insertHTMLHtmlStartTagBeforeHTML):
+        (WebCore::HTMLConstructionSite::insertHTMLHeadElement):
+        (WebCore::HTMLConstructionSite::insertHTMLBodyElement):
+        (WebCore::HTMLConstructionSite::insertHTMLFormElement):
+        (WebCore::HTMLConstructionSite::insertHTMLElement):
+        (WebCore::HTMLConstructionSite::insertFormattingElement):
+        (WebCore::HTMLConstructionSite::insertScriptElement):
+        (WebCore::HTMLConstructionSite::insertForeignElement):
+        (WebCore::HTMLConstructionSite::createElementFromSavedToken):
+        (WebCore::HTMLConstructionSite::reconstructTheActiveFormattingElements):
+        * html/parser/HTMLConstructionSite.h:
+        (HTMLConstructionSite):
+        (WebCore::HTMLConstructionSite::currentElementRecord):
+        * html/parser/HTMLElementStack.cpp:
+        (WebCore::HTMLElementStack::ElementRecord::ElementRecord):
+        (WebCore::HTMLElementStack::ElementRecord::replaceElement):
+        (WebCore::HTMLElementStack::pushRootNode):
+        (WebCore::HTMLElementStack::pushHTMLHtmlElement):
+        (WebCore::HTMLElementStack::pushRootNodeCommon):
+        (WebCore::HTMLElementStack::pushHTMLHeadElement):
+        (WebCore::HTMLElementStack::pushHTMLBodyElement):
+        (WebCore::HTMLElementStack::push):
+        (WebCore::HTMLElementStack::insertAbove):
+        (WebCore::HTMLElementStack::pushCommon):
+        * html/parser/HTMLElementStack.h:
+        (WebCore::HTMLElementStack::ElementRecord::element):
+        (WebCore::HTMLElementStack::ElementRecord::node):
+        (WebCore::HTMLElementStack::ElementRecord::stackItem):
+        (ElementRecord):
+        (HTMLElementStack):
+        * html/parser/HTMLFormattingElementList.cpp:
+        (WebCore::HTMLFormattingElementList::swapTo):
+        (WebCore::HTMLFormattingElementList::append):
+        * html/parser/HTMLFormattingElementList.h:
+        (WebCore::HTMLFormattingElementList::Entry::Entry):
+        (WebCore::HTMLFormattingElementList::Entry::isMarker):
+        (WebCore::HTMLFormattingElementList::Entry::stackItem):
+        (WebCore::HTMLFormattingElementList::Entry::element):
+        (WebCore::HTMLFormattingElementList::Entry::replaceElement):
+        (WebCore::HTMLFormattingElementList::Entry::operator==):
+        (WebCore::HTMLFormattingElementList::Entry::operator!=):
+        (Entry):
+        (HTMLFormattingElementList):
+        * html/parser/HTMLStackItem.h: Added.
+        (WebCore):
+        (HTMLStackItem):
+        (WebCore::HTMLStackItem::create):
+        (WebCore::HTMLStackItem::element):
+        (WebCore::HTMLStackItem::node):
+        (WebCore::HTMLStackItem::token):
+        (WebCore::HTMLStackItem::namespaceURI):
+        (WebCore::HTMLStackItem::HTMLStackItem):
+        * html/parser/HTMLTreeBuilder.cpp:
+        (WebCore::HTMLTreeBuilder::HTMLTreeBuilder):
+        (WebCore::HTMLTreeBuilder::processStartTag):
+        (WebCore::HTMLTreeBuilder::callTheAdoptionAgency):
+
 2012-07-23  Andreas Kling  <kling@webkit.org>
 
         Report the extra memory used by immutable StylePropertySet objects.
index b30a8ae..cc8bc29 100644 (file)
@@ -39,6 +39,7 @@
 #include "HTMLNames.h"
 #include "HTMLParserIdioms.h"
 #include "HTMLScriptElement.h"
+#include "HTMLStackItem.h"
 #include "HTMLToken.h"
 #include "HTMLTokenizer.h"
 #include "LocalizedStrings.h"
@@ -197,7 +198,7 @@ void HTMLConstructionSite::insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken* tok
     RefPtr<HTMLHtmlElement> element = HTMLHtmlElement::create(m_document);
     element->parserSetAttributes(token->attributes(), m_fragmentScriptingPermission);
     attachLater(m_attachmentRoot, element);
-    m_openElements.pushHTMLHtmlElement(element);
+    m_openElements.pushHTMLHtmlElement(HTMLStackItem::create(element, token));
 
     executeQueuedTasks();
     element->insertedByParser();
@@ -282,7 +283,7 @@ void HTMLConstructionSite::insertHTMLHeadElement(AtomicHTMLToken* token)
     ASSERT(!shouldFosterParent());
     m_head = createHTMLElement(token);
     attachLater(currentNode(), m_head);
-    m_openElements.pushHTMLHeadElement(m_head);
+    m_openElements.pushHTMLHeadElement(HTMLStackItem::create(m_head, token));
 }
 
 void HTMLConstructionSite::insertHTMLBodyElement(AtomicHTMLToken* token)
@@ -290,7 +291,7 @@ void HTMLConstructionSite::insertHTMLBodyElement(AtomicHTMLToken* token)
     ASSERT(!shouldFosterParent());
     RefPtr<Element> body = createHTMLElement(token);
     attachLater(currentNode(), body);
-    m_openElements.pushHTMLBodyElement(body.release());
+    m_openElements.pushHTMLBodyElement(HTMLStackItem::create(body.release(), token));
 }
 
 void HTMLConstructionSite::insertHTMLFormElement(AtomicHTMLToken* token, bool isDemoted)
@@ -300,14 +301,14 @@ void HTMLConstructionSite::insertHTMLFormElement(AtomicHTMLToken* token, bool is
     m_form = static_pointer_cast<HTMLFormElement>(element.release());
     m_form->setDemoted(isDemoted);
     attachLater(currentNode(), m_form);
-    m_openElements.push(m_form);
+    m_openElements.push(HTMLStackItem::create(m_form, token));
 }
 
 void HTMLConstructionSite::insertHTMLElement(AtomicHTMLToken* token)
 {
     RefPtr<Element> element = createHTMLElement(token);
     attachLater(currentNode(), element);
-    m_openElements.push(element.release());
+    m_openElements.push(HTMLStackItem::create(element.release(), token));
 }
 
 void HTMLConstructionSite::insertSelfClosingHTMLElement(AtomicHTMLToken* token)
@@ -327,7 +328,7 @@ void HTMLConstructionSite::insertFormattingElement(AtomicHTMLToken* token)
     // Possible active formatting elements include:
     // a, b, big, code, em, font, i, nobr, s, small, strike, strong, tt, and u.
     insertHTMLElement(token);
-    m_activeFormattingElements.append(currentElement());
+    m_activeFormattingElements.append(currentElementRecord()->stackItem());
 }
 
 void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken* token)
@@ -343,7 +344,7 @@ void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken* token)
     if (m_fragmentScriptingPermission != DisallowScriptingContent)
         element->parserSetAttributes(token->attributes(), m_fragmentScriptingPermission);
     attachLater(currentNode(), element);
-    m_openElements.push(element.release());
+    m_openElements.push(HTMLStackItem::create(element.release(), token));
 }
 
 void HTMLConstructionSite::insertForeignElement(AtomicHTMLToken* token, const AtomicString& namespaceURI)
@@ -354,7 +355,7 @@ void HTMLConstructionSite::insertForeignElement(AtomicHTMLToken* token, const At
     RefPtr<Element> element = createElement(token, namespaceURI);
     attachLater(currentNode(), element, token->selfClosing());
     if (!token->selfClosing())
-        m_openElements.push(element.release());
+        m_openElements.push(HTMLStackItem::create(element.release(), token, namespaceURI));
 }
 
 void HTMLConstructionSite::insertTextNode(const String& characters, WhitespaceMode whitespaceMode)
@@ -418,28 +419,14 @@ PassRefPtr<Element> HTMLConstructionSite::createHTMLElement(AtomicHTMLToken* tok
     return element.release();
 }
 
-PassRefPtr<Element> HTMLConstructionSite::createHTMLElementFromElementRecord(HTMLElementStack::ElementRecord* record)
+PassRefPtr<HTMLStackItem> HTMLConstructionSite::createElementFromSavedToken(HTMLStackItem* item)
 {
-    return createHTMLElementFromSavedElement(record->element());
-}
-
-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.
-
-    Vector<Attribute> clonedAttributes;
-    if (ElementAttributeData* attributeData = element->updatedAttributeData())
-        clonedAttributes = attributeData->clonedAttributeVector();
-
-    RefPtr<AtomicHTMLToken> fakeToken = AtomicHTMLToken::create(HTMLTokenTypes::StartTag, element->localName(), clonedAttributes);
-    return createHTMLElement(fakeToken.get());
+    RefPtr<Element> element;
+    if (item->namespaceURI() == HTMLNames::xhtmlNamespaceURI)
+        element = createHTMLElement(item->token());
+    else
+        element = createElement(item->token(), item->namespaceURI());
+    return HTMLStackItem::create(element.release(), item->token(), item->namespaceURI());
 }
 
 bool HTMLConstructionSite::indexOfFirstUnopenFormattingElement(unsigned& firstUnopenElementIndex) const
@@ -469,10 +456,10 @@ void HTMLConstructionSite::reconstructTheActiveFormattingElements()
     ASSERT(unopenEntryIndex < m_activeFormattingElements.size());
     for (; unopenEntryIndex < m_activeFormattingElements.size(); ++unopenEntryIndex) {
         HTMLFormattingElementList::Entry& unopenedEntry = m_activeFormattingElements.at(unopenEntryIndex);
-        RefPtr<Element> reconstructed = createHTMLElementFromSavedElement(unopenedEntry.element());
-        attachLater(currentNode(), reconstructed);
-        m_openElements.push(reconstructed.release());
-        unopenedEntry.replaceElement(currentElement());
+        RefPtr<HTMLStackItem> reconstructed = createElementFromSavedToken(unopenedEntry.stackItem().get());
+        attachLater(currentNode(), reconstructed->node());
+        m_openElements.push(reconstructed);
+        unopenedEntry.replaceElement(reconstructed.release());
     }
 }
 
index ed95849..a43668b 100644 (file)
@@ -106,7 +106,7 @@ public:
     void insertHTMLBodyStartTagInBody(AtomicHTMLToken*);
 
     PassRefPtr<Element> createHTMLElement(AtomicHTMLToken*);
-    PassRefPtr<Element> createHTMLElementFromElementRecord(HTMLElementStack::ElementRecord*);
+    PassRefPtr<HTMLStackItem> createElementFromSavedToken(HTMLStackItem*);
 
     bool shouldFosterParent() const;
     void fosterParent(PassRefPtr<Node>);
@@ -118,6 +118,7 @@ public:
     void generateImpliedEndTagsWithExclusion(const AtomicString& tagName);
 
     bool isEmpty() const { return !m_openElements.stackDepth(); }
+    HTMLElementStack::ElementRecord* currentElementRecord() const { return m_openElements.topRecord(); }
     Element* currentElement() const { return m_openElements.top(); }
     ContainerNode* currentNode() const { return m_openElements.topNode(); }
     Element* oneBelowTop() const { return m_openElements.oneBelowTop(); }
@@ -160,7 +161,6 @@ private:
 
     void findFosterSite(HTMLConstructionSiteTask&);
 
-    PassRefPtr<Element> createHTMLElementFromSavedElement(Element*);
     PassRefPtr<Element> createElement(AtomicHTMLToken*, const AtomicString& namespaceURI);
 
     void mergeAttributesFromTokenIntoElement(AtomicHTMLToken*, Element*);
index cd5d08a..7acab9a 100644 (file)
@@ -125,23 +125,23 @@ inline bool isSelectScopeMarker(ContainerNode* node)
 
 }
 
-HTMLElementStack::ElementRecord::ElementRecord(PassRefPtr<ContainerNode> node, PassOwnPtr<ElementRecord> next)
-    : m_node(node)
+HTMLElementStack::ElementRecord::ElementRecord(PassRefPtr<HTMLStackItem> item, PassOwnPtr<ElementRecord> next)
+    : m_item(item)
     , m_next(next)
 {
-    ASSERT(m_node);
+    ASSERT(m_item);
 }
 
 HTMLElementStack::ElementRecord::~ElementRecord()
 {
 }
 
-void HTMLElementStack::ElementRecord::replaceElement(PassRefPtr<Element> element)
+void HTMLElementStack::ElementRecord::replaceElement(PassRefPtr<HTMLStackItem> item)
 {
-    ASSERT(element);
-    ASSERT(!m_node || m_node->isElementNode());
+    ASSERT(item);
+    ASSERT(!m_item || m_item->node()->isElementNode());
     // FIXME: Should this call finishParsingChildren?
-    m_node = element;
+    m_item = item;
 }
 
 bool HTMLElementStack::ElementRecord::isAbove(ElementRecord* other) const
@@ -307,62 +307,62 @@ void HTMLElementStack::popUntilForeignContentScopeMarker()
         pop();
 }
     
-void HTMLElementStack::pushRootNode(PassRefPtr<ContainerNode> rootNode)
+void HTMLElementStack::pushRootNode(PassRefPtr<HTMLStackItem> rootItem)
 {
-    ASSERT(rootNode->nodeType() == Node::DOCUMENT_FRAGMENT_NODE);
-    pushRootNodeCommon(rootNode);
+    ASSERT(rootItem->node()->nodeType() == Node::DOCUMENT_FRAGMENT_NODE);
+    pushRootNodeCommon(rootItem);
 }
 
-void HTMLElementStack::pushHTMLHtmlElement(PassRefPtr<Element> element)
+void HTMLElementStack::pushHTMLHtmlElement(PassRefPtr<HTMLStackItem> item)
 {
-    ASSERT(element->hasTagName(HTMLNames::htmlTag));
-    pushRootNodeCommon(element);
+    ASSERT(item->element()->hasTagName(HTMLNames::htmlTag));
+    pushRootNodeCommon(item);
 }
     
-void HTMLElementStack::pushRootNodeCommon(PassRefPtr<ContainerNode> rootNode)
+void HTMLElementStack::pushRootNodeCommon(PassRefPtr<HTMLStackItem> rootItem)
 {
     ASSERT(!m_top);
     ASSERT(!m_rootNode);
-    m_rootNode = rootNode.get();
-    pushCommon(rootNode);
+    m_rootNode = rootItem->node();
+    pushCommon(rootItem);
 }
 
-void HTMLElementStack::pushHTMLHeadElement(PassRefPtr<Element> element)
+void HTMLElementStack::pushHTMLHeadElement(PassRefPtr<HTMLStackItem> item)
 {
-    ASSERT(element->hasTagName(HTMLNames::headTag));
+    ASSERT(item->element()->hasTagName(HTMLNames::headTag));
     ASSERT(!m_headElement);
-    m_headElement = element.get();
-    pushCommon(element);
+    m_headElement = item->element();
+    pushCommon(item);
 }
 
-void HTMLElementStack::pushHTMLBodyElement(PassRefPtr<Element> element)
+void HTMLElementStack::pushHTMLBodyElement(PassRefPtr<HTMLStackItem> item)
 {
-    ASSERT(element->hasTagName(HTMLNames::bodyTag));
+    ASSERT(item->element()->hasTagName(HTMLNames::bodyTag));
     ASSERT(!m_bodyElement);
-    m_bodyElement = element.get();
-    pushCommon(element);
+    m_bodyElement = item->element();
+    pushCommon(item);
 }
 
-void HTMLElementStack::push(PassRefPtr<Element> element)
+void HTMLElementStack::push(PassRefPtr<HTMLStackItem> item)
 {
-    ASSERT(!element->hasTagName(HTMLNames::htmlTag));
-    ASSERT(!element->hasTagName(HTMLNames::headTag));
-    ASSERT(!element->hasTagName(HTMLNames::bodyTag));
+    ASSERT(!item->element()->hasTagName(HTMLNames::htmlTag));
+    ASSERT(!item->element()->hasTagName(HTMLNames::headTag));
+    ASSERT(!item->element()->hasTagName(HTMLNames::bodyTag));
     ASSERT(m_rootNode);
-    pushCommon(element);
+    pushCommon(item);
 }
 
-void HTMLElementStack::insertAbove(PassRefPtr<Element> element, ElementRecord* recordBelow)
+void HTMLElementStack::insertAbove(PassRefPtr<HTMLStackItem> item, ElementRecord* recordBelow)
 {
-    ASSERT(element);
+    ASSERT(item);
     ASSERT(recordBelow);
     ASSERT(m_top);
-    ASSERT(!element->hasTagName(HTMLNames::htmlTag));
-    ASSERT(!element->hasTagName(HTMLNames::headTag));
-    ASSERT(!element->hasTagName(HTMLNames::bodyTag));
+    ASSERT(!item->element()->hasTagName(HTMLNames::htmlTag));
+    ASSERT(!item->element()->hasTagName(HTMLNames::headTag));
+    ASSERT(!item->element()->hasTagName(HTMLNames::bodyTag));
     ASSERT(m_rootNode);
     if (recordBelow == m_top) {
-        push(element);
+        push(item);
         return;
     }
 
@@ -371,7 +371,7 @@ void HTMLElementStack::insertAbove(PassRefPtr<Element> element, ElementRecord* r
             continue;
 
         m_stackDepth++;
-        recordAbove->setNext(adoptPtr(new ElementRecord(element, recordAbove->releaseNext())));
+        recordAbove->setNext(adoptPtr(new ElementRecord(item, recordAbove->releaseNext())));
         recordAbove->next()->element()->beginParsingChildren();
         return;
     }
@@ -567,12 +567,12 @@ ContainerNode* HTMLElementStack::rootNode() const
     return m_rootNode;
 }
 
-void HTMLElementStack::pushCommon(PassRefPtr<ContainerNode> node)
+void HTMLElementStack::pushCommon(PassRefPtr<HTMLStackItem> item)
 {
     ASSERT(m_rootNode);
 
     m_stackDepth++;
-    m_top = adoptPtr(new ElementRecord(node, m_top.release()));
+    m_top = adoptPtr(new ElementRecord(item, m_top.release()));
 }
 
 void HTMLElementStack::popCommon()
index f7baa36..6e31251 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "Element.h"
 #include "HTMLNames.h"
+#include "HTMLStackItem.h"
 #include <wtf/Forward.h>
 #include <wtf/Noncopyable.h>
 #include <wtf/OwnPtr.h>
@@ -55,23 +56,23 @@ public:
     public:
         ~ElementRecord(); // Public for ~PassOwnPtr()
     
-        Element* element() const { return toElement(m_node.get()); }
-        ContainerNode* node() const { return m_node.get(); }
-        void replaceElement(PassRefPtr<Element>);
+        Element* element() const { return m_item->element(); }
+        ContainerNode* node() const { return m_item->node(); }
+        PassRefPtr<HTMLStackItem> stackItem() const { return m_item; }
+        void replaceElement(PassRefPtr<HTMLStackItem>);
 
         bool isAbove(ElementRecord*) const;
 
         ElementRecord* next() const { return m_next.get(); }
-
     private:
         friend class HTMLElementStack;
 
-        ElementRecord(PassRefPtr<ContainerNode>, PassOwnPtr<ElementRecord>);
+        ElementRecord(PassRefPtr<HTMLStackItem>, PassOwnPtr<ElementRecord>);
 
         PassOwnPtr<ElementRecord> releaseNext() { return m_next.release(); }
         void setNext(PassOwnPtr<ElementRecord> next) { m_next = next; }
 
-        RefPtr<ContainerNode> m_node;
+        RefPtr<HTMLStackItem> m_item;
         OwnPtr<ElementRecord> m_next;
     };
 
@@ -97,13 +98,13 @@ public:
     ElementRecord* find(Element*) const;
     ElementRecord* topmost(const AtomicString& tagName) const;
 
-    void insertAbove(PassRefPtr<Element>, ElementRecord*);
+    void insertAbove(PassRefPtr<HTMLStackItem>, ElementRecord*);
 
-    void push(PassRefPtr<Element>);
-    void pushRootNode(PassRefPtr<ContainerNode>);
-    void pushHTMLHtmlElement(PassRefPtr<Element>);
-    void pushHTMLHeadElement(PassRefPtr<Element>);
-    void pushHTMLBodyElement(PassRefPtr<Element>);
+    void push(PassRefPtr<HTMLStackItem>);
+    void pushRootNode(PassRefPtr<HTMLStackItem>);
+    void pushHTMLHtmlElement(PassRefPtr<HTMLStackItem>);
+    void pushHTMLHeadElement(PassRefPtr<HTMLStackItem>);
+    void pushHTMLBodyElement(PassRefPtr<HTMLStackItem>);
 
     void pop();
     void popUntil(const AtomicString& tagName);
@@ -156,8 +157,8 @@ public:
 #endif
 
 private:
-    void pushCommon(PassRefPtr<ContainerNode>);
-    void pushRootNodeCommon(PassRefPtr<ContainerNode>);
+    void pushCommon(PassRefPtr<HTMLStackItem>);
+    void pushRootNodeCommon(PassRefPtr<HTMLStackItem>);
     void popCommon();
     void removeNonTopCommon(Element*);
 
index 0145de0..b42cebd 100644 (file)
@@ -87,25 +87,25 @@ HTMLFormattingElementList::Bookmark HTMLFormattingElementList::bookmarkFor(Eleme
     return Bookmark(&at(index));
 }
 
-void HTMLFormattingElementList::swapTo(Element* oldElement, Element* newElement, const Bookmark& bookmark)
+void HTMLFormattingElementList::swapTo(Element* oldElement, PassRefPtr<HTMLStackItem> newItem, const Bookmark& bookmark)
 {
     ASSERT(contains(oldElement));
-    ASSERT(!contains(newElement));
+    ASSERT(!contains(newItem->element()));
     if (!bookmark.hasBeenMoved()) {
         ASSERT(bookmark.mark()->element() == oldElement);
-        bookmark.mark()->replaceElement(newElement);
+        bookmark.mark()->replaceElement(newItem);
         return;
     }
     size_t index = bookmark.mark() - first();
     ASSERT(index < size());
-    m_entries.insert(index + 1, newElement);
+    m_entries.insert(index + 1, newItem);
     remove(oldElement);
 }
 
-void HTMLFormattingElementList::append(Element* element)
+void HTMLFormattingElementList::append(PassRefPtr<HTMLStackItem> item)
 {
-    ensureNoahsArkCondition(element);
-    m_entries.append(element);
+    ensureNoahsArkCondition(item->element());
+    m_entries.append(item);
 }
 
 void HTMLFormattingElementList::remove(Element* element)
index 79fe2ff..9f3545d 100644 (file)
@@ -26,6 +26,7 @@
 #ifndef HTMLFormattingElementList_h
 #define HTMLFormattingElementList_h
 
+#include "HTMLStackItem.h"
 #include <wtf/Forward.h>
 #include <wtf/RefPtr.h>
 #include <wtf/Vector.h>
@@ -47,35 +48,35 @@ public:
     class Entry {
     public:
         // Inline because they're hot and Vector<T> uses them.
-        explicit Entry(Element* element)
-            : m_element(element)
+        explicit Entry(PassRefPtr<HTMLStackItem> item)
+            : m_item(item)
         {
-            ASSERT(element);
         }
         enum MarkerEntryType { MarkerEntry };
         Entry(MarkerEntryType)
-            : m_element(0)
+            : m_item(0)
         {
         }
         ~Entry() {}
 
-        bool isMarker() const { return !m_element; }
+        bool isMarker() const { return !m_item; }
 
+        PassRefPtr<HTMLStackItem> stackItem() const { return m_item; }
         Element* element() const
         {
-            // The fact that !m_element == isMarker() is an implementation detail
+            // The fact that !m_item == isMarker() is an implementation detail
             // callers should check isMarker() before calling element().
-            ASSERT(m_element);
-            return m_element.get();
+            ASSERT(m_item);
+            return m_item->element();
         }
-        void replaceElement(PassRefPtr<Element> element) { m_element = element; }
+        void replaceElement(PassRefPtr<HTMLStackItem> item) { m_item = item; }
 
         // Needed for use with Vector.  These are super-hot and must be inline.
-        bool operator==(Element* element) const { return m_element == element; }
-        bool operator!=(Element* element) const { return m_element != element; }
+        bool operator==(Element* element) const { return !m_item ? !element : m_item->element() == element; }
+        bool operator!=(Element* element) const { return !m_item ? !!element : m_item->element() != element; }
 
     private:
-        RefPtr<Element> m_element;
+        RefPtr<HTMLStackItem> m_item;
     };
 
     class Bookmark {
@@ -107,11 +108,11 @@ public:
 
     Entry* find(Element*);
     bool contains(Element*);
-    void append(Element*);
+    void append(PassRefPtr<HTMLStackItem>);
     void remove(Element*);
 
     Bookmark bookmarkFor(Element*);
-    void swapTo(Element* oldElement, Element* newElement, const Bookmark&);
+    void swapTo(Element* oldElement, PassRefPtr<HTMLStackItem> newItem, const Bookmark&);
 
     void appendMarker();
     // clearToLastMarker also clears the marker (per the HTML5 spec).
diff --git a/Source/WebCore/html/parser/HTMLStackItem.h b/Source/WebCore/html/parser/HTMLStackItem.h
new file mode 100644 (file)
index 0000000..7dc7607
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2012 Company 100, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GOOGLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef HTMLStackItem_h
+#define HTMLStackItem_h
+
+#include "Element.h"
+#include "HTMLNames.h"
+#include "HTMLToken.h"
+
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/AtomicString.h>
+
+namespace WebCore {
+
+class ContainerNode;
+
+class HTMLStackItem : public RefCounted<HTMLStackItem> {
+public:
+    // DocumentFragment case.
+    static PassRefPtr<HTMLStackItem> create(PassRefPtr<ContainerNode> node)
+    {
+        return adoptRef(new HTMLStackItem(node));
+    }
+
+    // Used by HTMLElementStack and HTMLFormattingElementList.
+    static PassRefPtr<HTMLStackItem> create(PassRefPtr<ContainerNode> node, PassRefPtr<AtomicHTMLToken> token, const AtomicString& namespaceURI = HTMLNames::xhtmlNamespaceURI)
+    {
+        return adoptRef(new HTMLStackItem(node, token, namespaceURI));
+    }
+
+    Element* element() const { return toElement(m_node.get()); }
+    ContainerNode* node() const { return m_node.get(); }
+
+    AtomicHTMLToken* token() { return m_token.get(); }
+    const AtomicString& namespaceURI() const { return m_namespaceURI; }
+
+private:
+    HTMLStackItem(PassRefPtr<ContainerNode> node)
+        : m_node(node)
+        , m_isDocumentFragmentNode(true)
+    {
+    }
+
+    HTMLStackItem(PassRefPtr<ContainerNode> node, PassRefPtr<AtomicHTMLToken> token, const AtomicString& namespaceURI = HTMLNames::xhtmlNamespaceURI)
+        : m_node(node)
+        , m_token(token)
+        , m_namespaceURI(namespaceURI)
+        , m_isDocumentFragmentNode(false)
+    {
+    }
+
+    RefPtr<ContainerNode> m_node;
+
+    RefPtr<AtomicHTMLToken> m_token;
+    AtomicString m_namespaceURI;
+    bool m_isDocumentFragmentNode;
+};
+
+} // namespace WebCore
+
+#endif // HTMLStackItem_h
index 7026e68..729388d 100644 (file)
@@ -40,6 +40,7 @@
 #include "HTMLNames.h"
 #include "HTMLParserIdioms.h"
 #include "HTMLScriptElement.h"
+#include "HTMLStackItem.h"
 #include "HTMLToken.h"
 #include "HTMLTokenizer.h"
 #include "LocalizedStrings.h"
@@ -380,7 +381,7 @@ HTMLTreeBuilder::HTMLTreeBuilder(HTMLDocumentParser* parser, DocumentFragment* f
         // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#fragment-case
         // For efficiency, we skip step 4.2 ("Let root be a new html element with no attributes")
         // and instead use the DocumentFragment as a root node.
-        m_tree.openElements()->pushRootNode(fragment);
+        m_tree.openElements()->pushRootNode(HTMLStackItem::create(fragment));
         resetInsertionModeAppropriately();
         m_tree.setForm(closestFormAncestor(contextElement));
     }
@@ -1184,7 +1185,7 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken* token)
             || token->name() == titleTag) {
             parseError(token);
             ASSERT(m_tree.head());
-            m_tree.openElements()->pushHTMLHeadElement(m_tree.head());
+            m_tree.openElements()->pushHTMLHeadElement(HTMLStackItem::create(m_tree.head(), token));
             processStartTagForInHead(token);
             m_tree.openElements()->removeHTMLHeadElement(m_tree.head());
             return;
@@ -1559,10 +1560,11 @@ void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken* token)
             if (node == formattingElementRecord)
                 break;
             // 6.5
-            RefPtr<Element> newElement = m_tree.createHTMLElementFromElementRecord(node);
+            RefPtr<HTMLStackItem> newItem = m_tree.createElementFromSavedToken(node->stackItem().get());
+
             HTMLFormattingElementList::Entry* nodeEntry = m_tree.activeFormattingElements()->find(node->element());
-            nodeEntry->replaceElement(newElement.get());
-            node->replaceElement(newElement.release());
+            nodeEntry->replaceElement(newItem);
+            node->replaceElement(newItem.release());
             // 6.4 -- Intentionally out of order to handle the case where node
             // was replaced in 6.5.
             // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10096
@@ -1595,25 +1597,25 @@ void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken* token)
                 lastNode->element()->lazyAttach();
         }
         // 8
-        RefPtr<Element> newElement = m_tree.createHTMLElementFromElementRecord(formattingElementRecord);
+        RefPtr<HTMLStackItem> newItem = m_tree.createElementFromSavedToken(formattingElementRecord->stackItem().get());
         // 9
-        newElement->takeAllChildrenFrom(furthestBlock->element());
+        newItem->element()->takeAllChildrenFrom(furthestBlock->element());
         // 10
         Element* furthestBlockElement = furthestBlock->element();
         // FIXME: All this creation / parserAddChild / attach business should
         //        be in HTMLConstructionSite.  My guess is that steps 8--12
         //        should all be in some HTMLConstructionSite function.
-        furthestBlockElement->parserAddChild(newElement);
-        if (furthestBlockElement->attached() && !newElement->attached()) {
-            // Notice that newElement might already be attached if, for example, one of the reparented
+        furthestBlockElement->parserAddChild(newItem->element());
+        if (furthestBlockElement->attached() && !newItem->element()->attached()) {
+            // Notice that newItem->element() might already be attached if, for example, one of the reparented
             // children is a style element, which attaches itself automatically.
-            newElement->attach();
+            newItem->element()->attach();
         }
         // 11
-        m_tree.activeFormattingElements()->swapTo(formattingElement, newElement.get(), bookmark);
+        m_tree.activeFormattingElements()->swapTo(formattingElement, newItem, bookmark);
         // 12
         m_tree.openElements()->remove(formattingElement);
-        m_tree.openElements()->insertAbove(newElement, furthestBlock);
+        m_tree.openElements()->insertAbove(newItem, furthestBlock);
     }
 }