2010-06-30 Eric Seidel <eric@webkit.org>
authoreric@webkit.org <eric@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Jun 2010 20:02:49 +0000 (20:02 +0000)
committereric@webkit.org <eric@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Jun 2010 20:02:49 +0000 (20:02 +0000)
        Reviewed by Adam Barth.

        Implement HTML5 "in scope" algorithm and attempt to use it
        https://bugs.webkit.org/show_bug.cgi?id=41402

        Adds two new (expected) failures, since we're now
        switching out of InBody to AfterBody when seeing
        </html>.  We don't implement AfterBody yet, so
        the rest of the content after </html> is ignored.

        * html5lib/runner-expected-html5.txt:
2010-06-30  Eric Seidel  <eric@webkit.org>

        Reviewed by Adam Barth.

        Implement HTML5 "in scope" algorithm and attempt to use it
        https://bugs.webkit.org/show_bug.cgi?id=41402

        Implemented the 4 needed "in scope" functions for HTML5.
        3 for the different sets of scope markers, and one for
        doing exact element comparisons instead of tag name searches.

        I deployed inScope("body") for </body> and </html> in InBody.

        Adds two new (expected) failures, since we're now
        switching out of InBody to AfterBody when seeing
        </html>.  We don't implement AfterBody yet, so
        the rest of the content after </html> is ignored.

        * html/HTMLElementStack.cpp:
        (WebCore::inScopeCommon):
        (WebCore::HTMLElementStack::inScope):
        (WebCore::HTMLElementStack::inListItemScope):
        (WebCore::HTMLElementStack::inTableScope):
        * html/HTMLElementStack.h:
        * html/HTMLTreeBuilder.cpp:
        (WebCore::HTMLTreeBuilder::processBodyEndTagForInBody):
        (WebCore::HTMLTreeBuilder::processEndTag):
        * html/HTMLTreeBuilder.h:

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

LayoutTests/ChangeLog
LayoutTests/html5lib/runner-expected-html5.txt
WebCore/ChangeLog
WebCore/html/HTMLElementStack.cpp
WebCore/html/HTMLElementStack.h
WebCore/html/HTMLTreeBuilder.cpp
WebCore/html/HTMLTreeBuilder.h

index 6f89257..5b7f0fc 100644 (file)
@@ -1,3 +1,17 @@
+2010-06-30  Eric Seidel  <eric@webkit.org>
+
+        Reviewed by Adam Barth.
+
+        Implement HTML5 "in scope" algorithm and attempt to use it
+        https://bugs.webkit.org/show_bug.cgi?id=41402
+
+        Adds two new (expected) failures, since we're now
+        switching out of InBody to AfterBody when seeing
+        </html>.  We don't implement AfterBody yet, so
+        the rest of the content after </html> is ignored.
+
+        * html5lib/runner-expected-html5.txt:
+
 2010-06-30  Kenneth Russell  <kbr@google.com>
 
         Reviewed by Oliver Hunt.
index 9fb3b7e..b993328 100644 (file)
@@ -48,6 +48,7 @@ resources/tests1.dat:
 86
 89
 90
+92
 93
 94
 95
@@ -93,6 +94,7 @@ resources/tests2.dat:
 51
 53
 54
+55
 58
 
 resources/tests3.dat:
index 55b6cb3..4247707 100644 (file)
@@ -2,6 +2,35 @@
 
         Reviewed by Adam Barth.
 
+        Implement HTML5 "in scope" algorithm and attempt to use it
+        https://bugs.webkit.org/show_bug.cgi?id=41402
+
+        Implemented the 4 needed "in scope" functions for HTML5.
+        3 for the different sets of scope markers, and one for
+        doing exact element comparisons instead of tag name searches.
+
+        I deployed inScope("body") for </body> and </html> in InBody.
+
+        Adds two new (expected) failures, since we're now
+        switching out of InBody to AfterBody when seeing
+        </html>.  We don't implement AfterBody yet, so
+        the rest of the content after </html> is ignored.
+
+        * html/HTMLElementStack.cpp:
+        (WebCore::inScopeCommon):
+        (WebCore::HTMLElementStack::inScope):
+        (WebCore::HTMLElementStack::inListItemScope):
+        (WebCore::HTMLElementStack::inTableScope):
+        * html/HTMLElementStack.h:
+        * html/HTMLTreeBuilder.cpp:
+        (WebCore::HTMLTreeBuilder::processBodyEndTagForInBody):
+        (WebCore::HTMLTreeBuilder::processEndTag):
+        * html/HTMLTreeBuilder.h:
+
+2010-06-30  Eric Seidel  <eric@webkit.org>
+
+        Reviewed by Adam Barth.
+
         Split HTMLElementStack out into its own file
         https://bugs.webkit.org/show_bug.cgi?id=41399
 
index 0b4b1a3..0842965 100644 (file)
 #include "HTMLElementStack.h"
 
 #include "Element.h"
+#include "HTMLNames.h"
+#include "SVGNames.h"
 #include <wtf/PassOwnPtr.h>
 
 namespace WebCore {
 
+using namespace HTMLNames;
+
 class HTMLElementStack::ElementRecord : public Noncopyable {
 public:
     ElementRecord(PassRefPtr<Element> element, PassOwnPtr<ElementRecord> next)
@@ -141,20 +145,77 @@ bool HTMLElementStack::contains(Element* element) const
     return false;
 }
 
-bool HTMLElementStack::inScope(const AtomicString& name) const
+namespace {
+
+inline bool isScopeMarker(const Element* element)
+{
+    return element->hasTagName(appletTag)
+        || element->hasTagName(captionTag)
+        || element->hasTagName(appletTag)
+        || element->hasTagName(htmlTag)
+        || element->hasTagName(tableTag)
+        || element->hasTagName(tdTag)
+        || element->hasTagName(thTag)
+        || element->hasTagName(buttonTag)
+        || element->hasTagName(marqueeTag)
+        || element->hasTagName(objectTag)
+        || element->hasTagName(SVGNames::foreignObjectTag);
+}
+
+inline bool isListItemScopeMarker(const Element* element)
+{
+    return isScopeMarker(element)
+        || element->hasTagName(olTag)
+        || element->hasTagName(ulTag);
+}
+inline bool isTableScopeMarker(const Element* element)
+{
+    return element->hasTagName(htmlTag)
+        || element->hasTagName(tableTag);
+}
+
+}
+
+template <bool isMarker(const Element*)>
+bool inScopeCommon(HTMLElementStack::ElementRecord* top, const AtomicString& targetTag)
+{
+    for (HTMLElementStack::ElementRecord* pos = top; pos; pos = pos->next()) {
+        Element* element = pos->element();
+        if (element->hasLocalName(targetTag))
+            return true;
+        if (isMarker(element))
+            return false;
+    }
+    ASSERT_NOT_REACHED(); // <html> is always on the stack and is a scope marker.
+    return false;
+}
+
+bool HTMLElementStack::inScope(Element* targetElement) const
 {
-    // FIXME: This algorithm is wrong.
     for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) {
-        if (pos->element()->tagQName() == name)
+        Element* element = pos->element();
+        if (element == targetElement)
             return true;
+        if (isScopeMarker(element))
+            return false;
     }
+    ASSERT_NOT_REACHED(); // <html> is always on the stack and is a scope marker.
     return false;
 }
 
-bool HTMLElementStack::inScope(Element* element) const
+bool HTMLElementStack::inScope(const AtomicString& targetTag) const
+{
+    return inScopeCommon<isScopeMarker>(m_top.get(), targetTag);
+}
+
+bool HTMLElementStack::inListItemScope(const AtomicString& targetTag) const
+{
+    return inScopeCommon<isListItemScopeMarker>(m_top.get(), targetTag);
+}
+
+bool HTMLElementStack::inTableScope(const AtomicString& targetTag) const
 {
-    // FIXME: This algorithm is wrong.
-    return contains(element);
+    return inScopeCommon<isTableScopeMarker>(m_top.get(), targetTag);
 }
 
 Element* HTMLElementStack::htmlElement()
index 801ab6a..7e715ba 100644 (file)
 #ifndef HTMLElementStack_h
 #define HTMLElementStack_h
 
-#include "HTMLNames.h"
+#include <wtf/Forward.h>
 #include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
 
 namespace WebCore {
 
+class AtomicString;
 class Element;
 
 class HTMLElementStack : public Noncopyable {
@@ -53,19 +55,22 @@ public:
 
     bool contains(Element*) const;
 
-    bool inScope(const AtomicString& name) const;
     bool inScope(Element*) const;
+    bool inScope(const AtomicString& tagName) const;
+    bool inListItemScope(const AtomicString& tagName) const;
+    bool inTableScope(const AtomicString& tagName) const;
 
     Element* htmlElement();
     Element* headElement();
     Element* bodyElement();
 
+    // Public so free functions can use it, but defined privately.
+    class ElementRecord;
 private:
     void pushCommon(PassRefPtr<Element>);
     void popCommon();
     void removeNonFirstCommon(Element*);
 
-    class ElementRecord;
     OwnPtr<ElementRecord> m_top;
 
     // We remember <html>, <head> and <body> as they are pushed.  Their
index fe1bd9c..c2220ed 100644 (file)
@@ -587,6 +587,17 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token)
     }
 }
 
+bool HTMLTreeBuilder::processBodyEndTagForInBody(AtomicHTMLToken& token)
+{
+    if (!m_openElements.inScope(bodyTag.localName())) {
+        parseError(token);
+        return false;
+    }
+    notImplemented();
+    m_insertionMode = AfterBodyMode;
+    return true;
+}
+
 void HTMLTreeBuilder::processEndTag(AtomicHTMLToken& token)
 {
     switch (insertionMode()) {
@@ -634,12 +645,12 @@ void HTMLTreeBuilder::processEndTag(AtomicHTMLToken& token)
     case InBodyMode:
         ASSERT(insertionMode() == InBodyMode);
         if (token.name() == bodyTag) {
-            notImplemented();
-            m_insertionMode = AfterBodyMode;
+            processBodyEndTagForInBody(token);
             return;
         }
         if (token.name() == htmlTag) {
-            notImplemented();
+            if (processBodyEndTagForInBody(token))
+                notImplemented(); // Re-process the curent token.
             return;
         }
         if (token.name() == addressTag || token.name() == articleTag || token.name() == asideTag || token.name() == blockquoteTag || token.name() == buttonTag || token.name() == centerTag || token.name() == "details" || token.name() == dirTag || token.name() == divTag || token.name() == dlTag || token.name() == fieldsetTag || token.name() == "figure" || token.name() == footerTag || token.name() == headerTag || token.name() == hgroupTag || token.name() == listingTag || token.name() == menuTag || token.name() == navTag || token.name() == olTag || token.name() == preTag || token.name() == sectionTag || token.name() == ulTag) {
index 7e40df3..17063f2 100644 (file)
@@ -122,6 +122,8 @@ private:
 
     bool processStartTagForInHead(AtomicHTMLToken&);
 
+    bool processBodyEndTagForInBody(AtomicHTMLToken&);
+
     template<typename ChildType>
     PassRefPtr<ChildType> attach(Node* parent, PassRefPtr<ChildType> prpChild)
     {