2010-07-05 Eric Seidel <eric@webkit.org>
authoreric@webkit.org <eric@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 6 Jul 2010 06:01:37 +0000 (06:01 +0000)
committereric@webkit.org <eric@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 6 Jul 2010 06:01:37 +0000 (06:01 +0000)
        Reviewed by Adam Barth.

        Add <isindex> support, per HTML5
        https://bugs.webkit.org/show_bug.cgi?id=41650

        * html5lib/resources/tests2.dat:
         - Make the expected wording match the HTML5 spec.
           Not sure why the wording in this test diverged.
        * html5lib/resources/isindex.dat:
         - Cover more isindex cases.
        * html5lib/runner.html:
2010-07-05  Eric Seidel  <eric@webkit.org>

        Reviewed by Adam Barth.

        Add <isindex> support, per HTML5
        https://bugs.webkit.org/show_bug.cgi?id=41650

        Covered by html5lib/runner.html including a new
        isindex.dat test suite.

        * html/HTMLToken.h:
        (WebCore::AtomicHTMLToken::AtomicHTMLToken):
         - Support passing attributes to the constructor.
        (WebCore::AtomicHTMLToken::name):
        (WebCore::AtomicHTMLToken::setName):
        (WebCore::AtomicHTMLToken::getAttributeItem):
        (WebCore::AtomicHTMLToken::attributes):
        (WebCore::AtomicHTMLToken::takeAtributes):
         - Reduces ref-churn, and makes it possible for callers
           to modify attributes w/o affecting future uses of the attributes.
        (WebCore::AtomicHTMLToken::usesName):
         - Used by ASSERTS.
        (WebCore::AtomicHTMLToken::usesAttributes):
         - Used by ASSERTS.
        * html/HTMLTreeBuilder.cpp:
        (WebCore::convertToOldStyle):
         - Can't be const, now that we use takeAttributes()
        (WebCore::HTMLTreeBuilder::insertHTMLStartTagBeforeHTML):
        (WebCore::HTMLTreeBuilder::proesssFakeStartTag):
         - New function.  I'm not sure this is the perfect design
          (I'd kinda like AtomicHTMLToken to be copyable so we can
           have create functions for it), but this makes the callsites
           using fake tokens much more readable.
        (WebCore::HTMLTreeBuilder::proesssFakeEndTag):
        (WebCore::HTMLTreeBuilder::processFakeCharacters):
        (WebCore::HTMLTreeBuilder::attributesForIsindexInput):
        (WebCore::HTMLTreeBuilder::processIsindexStartTagForBody):
        (WebCore::HTMLTreeBuilder::processStartTag):
        (WebCore::HTMLTreeBuilder::insertScriptElement):
         - Use takeAttributes() for less ref-churn.
        (WebCore::HTMLTreeBuilder::createElement): ditto
        (WebCore::HTMLTreeBuilder::finished):
         - Remove bogus use of AtomicHTMLToken constructor which
           wasn't even being used now that we support emitting EOF tokens
           from the Tokenizer directly.
        * html/HTMLTreeBuilder.h:

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

LayoutTests/ChangeLog
LayoutTests/html5lib/resources/isindex.dat [new file with mode: 0644]
LayoutTests/html5lib/resources/tests2.dat
LayoutTests/html5lib/runner-expected-html5.txt
LayoutTests/html5lib/runner-expected.txt
LayoutTests/html5lib/runner.html
WebCore/ChangeLog
WebCore/html/HTMLToken.h
WebCore/html/HTMLTreeBuilder.cpp
WebCore/html/HTMLTreeBuilder.h

index a893e8d..799e9b9 100644 (file)
@@ -1,3 +1,17 @@
+2010-07-05  Eric Seidel  <eric@webkit.org>
+
+        Reviewed by Adam Barth.
+
+        Add <isindex> support, per HTML5
+        https://bugs.webkit.org/show_bug.cgi?id=41650
+
+        * html5lib/resources/tests2.dat:
+         - Make the expected wording match the HTML5 spec.
+           Not sure why the wording in this test diverged.
+        * html5lib/resources/isindex.dat:
+         - Cover more isindex cases.
+        * html5lib/runner.html:
+
 2010-07-05  Adam Barth  <abarth@webkit.org>
 
         Reviewed by Eric Seidel.
diff --git a/LayoutTests/html5lib/resources/isindex.dat b/LayoutTests/html5lib/resources/isindex.dat
new file mode 100644 (file)
index 0000000..88325ff
--- /dev/null
@@ -0,0 +1,40 @@
+#data
+<isindex>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       <hr>
+|       <label>
+|         "This is a searchable index. Enter search keywords: "
+|         <input>
+|           name="isindex"
+|       <hr>
+
+#data
+<isindex name="A" action="B" prompt="C" foo="D">
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       action="B"
+|       <hr>
+|       <label>
+|         "C"
+|         <input>
+|           foo="D"
+|           name="isindex"
+|       <hr>
+
+#data
+<form><isindex>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <form>
index d33996e..54944c6 100644 (file)
@@ -515,7 +515,7 @@ Line: 1 Col: 23 Unexpected start tag isindex. Don't use it!
 |     <form>
 |       <hr>
 |       <label>
-|         "This is a searchable index. Insert your search keywords here: "
+|         "This is a searchable index. Enter search keywords: "
 |         <input>
 |           name="isindex"
 |           test="x"
index 5b236be..0211d75 100644 (file)
@@ -1393,7 +1393,6 @@ resources/tests2.dat:
 34
 36
 38
-42
 47
 48
 49
@@ -1565,25 +1564,6 @@ Expected:
 |       <input>
 |       <input>
 
-Test 42 of 59 in resources/tests2.dat failed. Input:
-<isindex test=x name=x>
-Got:
-| <html>
-|   <head>
-|   <body>
-Expected:
-| <html>
-|   <head>
-|   <body>
-|     <form>
-|       <hr>
-|       <label>
-|         "This is a searchable index. Insert your search keywords here: "
-|         <input>
-|           name="isindex"
-|           test="x"
-|       <hr>
-
 Test 47 of 59 in resources/tests2.dat failed. Input:
  
  
@@ -5292,6 +5272,8 @@ Expected:
 |     <table>
 resources/inbody01.dat: PASS
 
+resources/isindex.dat: PASS
+
 resources/tables01.dat:
 4
 7
index b3da42b..cacbf6c 100644 (file)
@@ -928,7 +928,7 @@ Expected:
 |     <form>
 |       <hr>
 |       <label>
-|         "This is a searchable index. Insert your search keywords here: "
+|         "This is a searchable index. Enter search keywords: "
 |         <input>
 |           name="isindex"
 |           test="x"
@@ -4999,6 +4999,67 @@ Expected:
 |     <table>
 resources/inbody01.dat: PASS
 
+resources/isindex.dat:
+1
+2
+3
+
+Test 1 of 3 in resources/isindex.dat failed. Input:
+<isindex>
+Got:
+| <html>
+|   <head>
+|   <body>
+Expected:
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       <hr>
+|       <label>
+|         "This is a searchable index. Enter search keywords: "
+|         <input>
+|           name="isindex"
+|       <hr>
+
+Test 2 of 3 in resources/isindex.dat failed. Input:
+<isindex name="A" action="B" prompt="C" foo="D">
+Got:
+| <html>
+|   <head>
+|   <body>
+Expected:
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       action="B"
+|       <hr>
+|       <label>
+|         "C"
+|         <input>
+|           foo="D"
+|           name="isindex"
+|       <hr>
+
+Test 3 of 3 in resources/isindex.dat failed. Input:
+<form><isindex>
+Got:
+| <html>
+|   <head>
+|   <body>
+|     <form>
+|       <div>
+|         <hr>
+|         "This is a searchable index. Enter search keywords: "
+|         <isindex>
+|           type="khtml_isindex"
+|         <hr>
+Expected:
+| <html>
+|   <head>
+|   <body>
+|     <form>
 resources/tables01.dat:
 3
 7
index cd17ea1..ce301c1 100644 (file)
@@ -61,6 +61,7 @@ var test_files = [
         'resources/comments01.dat',
         'resources/adoption01.dat',
         'resources/inbody01.dat',
+        'resources/isindex.dat',
         'resources/tables01.dat'
     ],
     tests = [],
index 85d8d02..5402afc 100644 (file)
@@ -1,3 +1,50 @@
+2010-07-05  Eric Seidel  <eric@webkit.org>
+
+        Reviewed by Adam Barth.
+
+        Add <isindex> support, per HTML5
+        https://bugs.webkit.org/show_bug.cgi?id=41650
+
+        Covered by html5lib/runner.html including a new
+        isindex.dat test suite.
+
+        * html/HTMLToken.h:
+        (WebCore::AtomicHTMLToken::AtomicHTMLToken):
+         - Support passing attributes to the constructor.
+        (WebCore::AtomicHTMLToken::name):
+        (WebCore::AtomicHTMLToken::setName):
+        (WebCore::AtomicHTMLToken::getAttributeItem):
+        (WebCore::AtomicHTMLToken::attributes):
+        (WebCore::AtomicHTMLToken::takeAtributes):
+         - Reduces ref-churn, and makes it possible for callers
+           to modify attributes w/o affecting future uses of the attributes.
+        (WebCore::AtomicHTMLToken::usesName):
+         - Used by ASSERTS.
+        (WebCore::AtomicHTMLToken::usesAttributes):
+         - Used by ASSERTS.
+        * html/HTMLTreeBuilder.cpp:
+        (WebCore::convertToOldStyle):
+         - Can't be const, now that we use takeAttributes()
+        (WebCore::HTMLTreeBuilder::insertHTMLStartTagBeforeHTML):
+        (WebCore::HTMLTreeBuilder::proesssFakeStartTag):
+         - New function.  I'm not sure this is the perfect design
+          (I'd kinda like AtomicHTMLToken to be copyable so we can
+           have create functions for it), but this makes the callsites
+           using fake tokens much more readable.
+        (WebCore::HTMLTreeBuilder::proesssFakeEndTag):
+        (WebCore::HTMLTreeBuilder::processFakeCharacters):
+        (WebCore::HTMLTreeBuilder::attributesForIsindexInput):
+        (WebCore::HTMLTreeBuilder::processIsindexStartTagForBody):
+        (WebCore::HTMLTreeBuilder::processStartTag):
+        (WebCore::HTMLTreeBuilder::insertScriptElement):
+         - Use takeAttributes() for less ref-churn.
+        (WebCore::HTMLTreeBuilder::createElement): ditto
+        (WebCore::HTMLTreeBuilder::finished):
+         - Remove bogus use of AtomicHTMLToken constructor which
+           wasn't even being used now that we support emitting EOF tokens
+           from the Tokenizer directly.
+        * html/HTMLTreeBuilder.h:
+
 2010-07-05  Adam Barth  <abarth@webkit.org>
 
         Reviewed by Eric Seidel.
index 741f5cd..c873a5c 100644 (file)
@@ -337,9 +337,17 @@ public:
         }
     }
 
-    AtomicHTMLToken(HTMLToken::Type type, AtomicString name)
+    AtomicHTMLToken(HTMLToken::Type type, AtomicString name, PassRefPtr<NamedNodeMap> attributes = 0)
         : m_type(type)
         , m_name(name)
+        , m_attributes(attributes)
+    {
+        ASSERT(usesName());
+    }
+
+    explicit AtomicHTMLToken(const String& characters)
+        : m_type(HTMLToken::Character)
+        , m_data(characters)
     {
     }
 
@@ -347,13 +355,13 @@ public:
 
     const AtomicString& name() const
     {
-        ASSERT(m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag || m_type == HTMLToken::DOCTYPE);
+        ASSERT(usesName());
         return m_name;
     }
 
     void setName(const AtomicString& name)
     {
-        ASSERT(m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag || m_type == HTMLToken::DOCTYPE);
+        ASSERT(usesName());
         m_name = name;
     }
 
@@ -363,12 +371,26 @@ public:
         return m_selfClosing;
     }
 
+    Attribute* getAttributeItem(const QualifiedName& attributeName)
+    {
+        ASSERT(usesAttributes());
+        if (!m_attributes)
+            return 0;
+        return m_attributes->getAttributeItem(attributeName);
+    }
+
     NamedNodeMap* attributes() const
     {
-        ASSERT(m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag);
+        ASSERT(usesAttributes());
         return m_attributes.get();
     }
 
+    PassRefPtr<NamedNodeMap> takeAtributes()
+    {
+        ASSERT(usesAttributes());
+        return m_attributes.release();
+    }
+
     const String& characters() const
     {
         ASSERT(m_type == HTMLToken::Character);
@@ -404,6 +426,16 @@ public:
 private:
     HTMLToken::Type m_type;
 
+    bool usesName() const
+    {
+        return m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag || m_type == HTMLToken::DOCTYPE;
+    }
+
+    bool usesAttributes() const
+    {
+        return m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag;
+    }
+
     // "name" for DOCTYPE, StartTag, and EndTag
     AtomicString m_name;
 
index c0b8fe7..0419986 100644 (file)
@@ -40,6 +40,7 @@
 #include "HTMLTokenizer.h"
 #include "LegacyHTMLDocumentParser.h"
 #include "LegacyHTMLTreeBuilder.h"
+#include "LocalizedStrings.h"
 #if ENABLE(MATHML)
 #include "MathMLNames.h"
 #endif
@@ -243,7 +244,7 @@ HTMLTreeBuilder::~HTMLTreeBuilder()
 {
 }
 
-static void convertToOldStyle(const AtomicHTMLToken& token, Token& oldStyleToken)
+static void convertToOldStyle(AtomicHTMLToken& token, Token& oldStyleToken)
 {
     switch (token.type()) {
     case HTMLToken::Uninitialized:
@@ -259,7 +260,7 @@ static void convertToOldStyle(const AtomicHTMLToken& token, Token& oldStyleToken
         oldStyleToken.beginTag = (token.type() == HTMLToken::StartTag);
         oldStyleToken.selfClosingTag = token.selfClosing();
         oldStyleToken.tagName = token.name();
-        oldStyleToken.attrs = token.attributes();
+        oldStyleToken.attrs = token.takeAtributes();
         break;
     }
     case HTMLToken::Comment:
@@ -425,7 +426,7 @@ void HTMLTreeBuilder::processDoctypeToken(AtomicHTMLToken& token)
 void HTMLTreeBuilder::insertHTMLStartTagBeforeHTML(AtomicHTMLToken& token)
 {
     RefPtr<Element> element = HTMLHtmlElement::create(m_document);
-    element->setAttributeMap(token.attributes(), m_fragmentScriptingPermission);
+    element->setAttributeMap(token.takeAtributes(), m_fragmentScriptingPermission);
     m_openElements.pushHTMLHtmlElement(attach(m_document, element.release()));
 }
 
@@ -448,6 +449,26 @@ void HTMLTreeBuilder::insertHTMLStartTagInBody(AtomicHTMLToken& token)
     mergeAttributesFromTokenIntoElement(token, m_openElements.htmlElement());
 }
 
+void HTMLTreeBuilder::proesssFakeStartTag(const QualifiedName& tagName, PassRefPtr<NamedNodeMap> attributes)
+{
+    // FIXME: We'll need a fancier conversion than just "localName" for SVG/MathML tags.
+    AtomicHTMLToken fakeToken(HTMLToken::StartTag, tagName.localName(), attributes);
+    processStartTag(fakeToken);
+}
+
+void HTMLTreeBuilder::proesssFakeEndTag(const QualifiedName& tagName)
+{
+    // FIXME: We'll need a fancier conversion than just "localName" for SVG/MathML tags.
+    AtomicHTMLToken fakeToken(HTMLToken::EndTag, tagName.localName());
+    processEndTag(fakeToken);
+}
+
+void HTMLTreeBuilder::processFakeCharacters(const String& characters)
+{
+    AtomicHTMLToken fakeToken(characters);
+    processCharacter(fakeToken);
+}
+
 void HTMLTreeBuilder::processFakePEndTagIfPInScope()
 {
     if (!m_openElements.inScope(pTag.localName()))
@@ -456,6 +477,48 @@ void HTMLTreeBuilder::processFakePEndTagIfPInScope()
     processEndTag(endP);
 }
 
+PassRefPtr<NamedNodeMap> HTMLTreeBuilder::attributesForIsindexInput(AtomicHTMLToken& token)
+{
+    RefPtr<NamedNodeMap> attributes = token.takeAtributes();
+    if (!attributes)
+        attributes = NamedNodeMap::create();
+    else {
+        attributes->removeAttribute(nameAttr);
+        attributes->removeAttribute(actionAttr);
+        attributes->removeAttribute(promptAttr);
+    }
+
+    RefPtr<Attribute> mappedAttribute = Attribute::createMapped(nameAttr, isindexTag.localName());
+    attributes->insertAttribute(mappedAttribute.release(), false);
+    return attributes.release();
+}
+
+void HTMLTreeBuilder::processIsindexStartTagForBody(AtomicHTMLToken& token)
+{
+    parseError(token);
+    if (m_formElement)
+        return;
+    notImplemented(); // Acknowledge self-closing flag
+    proesssFakeStartTag(formTag);
+    Attribute* actionAttribute = token.getAttributeItem(actionAttr);
+    if (actionAttribute) {
+        ASSERT(currentElement()->hasTagName(formTag));
+        currentElement()->setAttribute(actionAttr, actionAttribute->value());
+    }
+    proesssFakeStartTag(hrTag);
+    proesssFakeStartTag(labelTag);
+    Attribute* promptAttribute = token.getAttributeItem(promptAttr);
+    if (promptAttribute)
+        processFakeCharacters(promptAttribute->value());
+    else
+        processFakeCharacters(searchableIndexIntroduction());
+    proesssFakeStartTag(inputTag, attributesForIsindexInput(token));
+    notImplemented(); // This second set of characters may be needed by non-english locales.
+    proesssFakeEndTag(labelTag);
+    proesssFakeStartTag(hrTag);
+    proesssFakeEndTag(formTag);
+}
+
 void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token)
 {
     ASSERT(token.type() == HTMLToken::StartTag);
@@ -659,8 +722,7 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token)
             return;
         }
         if (token.name() == isindexTag) {
-            parseError(token);
-            notImplemented();
+            processIsindexStartTagForBody(token);
             return;
         }
         if (token.name() == textareaTag) {
@@ -753,8 +815,7 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token)
             return;
         }
         if (token.name() == colTag) {
-            AtomicHTMLToken fakeToken(HTMLToken::StartTag, colgroupTag.localName());
-            processStartTag(fakeToken);
+            proesssFakeStartTag(colgroupTag);
             ASSERT(InColumnGroupMode);
             processStartTag(token);
             return;
@@ -766,8 +827,7 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token)
             return;
         }
         if (token.name() == tdTag || token.name() == thTag || token.name() == trTag) {
-            AtomicHTMLToken fakeToken(HTMLToken::StartTag, tbodyTag.localName());
-            processStartTag(fakeToken);
+            proesssFakeStartTag(tbodyTag);
             ASSERT(insertionMode() == InTableBodyMode);
             processStartTag(token);
             return;
@@ -815,8 +875,7 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token)
         }
         if (token.name() == thTag || token.name() == tdTag) {
             parseError(token);
-            AtomicHTMLToken fakeToken(HTMLToken::StartTag, trTag.localName());
-            processStartTag(fakeToken);
+            proesssFakeStartTag(trTag);
             ASSERT(insertionMode() == InRowMode);
             processStartTag(token);
             return;
@@ -1835,7 +1894,7 @@ void HTMLTreeBuilder::insertScriptElement(AtomicHTMLToken& token)
 {
     ASSERT_UNUSED(token, token.type() == HTMLToken::StartTag);
     RefPtr<HTMLScriptElement> element = HTMLScriptElement::create(scriptTag, m_document, true);
-    element->setAttributeMap(token.attributes(), m_fragmentScriptingPermission);
+    element->setAttributeMap(token.takeAtributes(), m_fragmentScriptingPermission);
     m_openElements.push(attach(currentElement(), element.release()));
     m_tokenizer->setState(HTMLTokenizer::ScriptDataState);
     m_originalInsertionMode = m_insertionMode;
@@ -1859,7 +1918,7 @@ void HTMLTreeBuilder::insertTextNode(AtomicHTMLToken& token)
 PassRefPtr<Element> HTMLTreeBuilder::createElement(AtomicHTMLToken& token)
 {
     RefPtr<Element> element = HTMLElementFactory::createHTMLElement(QualifiedName(nullAtom, token.name(), xhtmlNamespaceURI), m_document, 0);
-    element->setAttributeMap(token.attributes(), m_fragmentScriptingPermission);
+    element->setAttributeMap(token.takeAtributes(), m_fragmentScriptingPermission);
     return element.release();
 }
 
@@ -1933,9 +1992,6 @@ void HTMLTreeBuilder::finished()
         return;
     }
 
-    AtomicHTMLToken eofToken(HTMLToken::EndOfFile, nullAtom);
-    processToken(eofToken);
-
     // Warning, this may delete the parser, so don't try to do anything else after this.
     if (!m_isParsingFragment)
         m_document->finishedParsing();
index f241d28..1efb954 100644 (file)
@@ -122,8 +122,16 @@ private:
     void processDefaultForAfterHeadMode(AtomicHTMLToken&);
 
     bool processStartTagForInHead(AtomicHTMLToken&);
+
+    PassRefPtr<NamedNodeMap> attributesForIsindexInput(AtomicHTMLToken&);
+    void processIsindexStartTagForBody(AtomicHTMLToken&);
+
     bool processBodyEndTagForInBody(AtomicHTMLToken&);
     void processAnyOtherEndTagForInBody(AtomicHTMLToken&);
+
+    void proesssFakeStartTag(const QualifiedName&, PassRefPtr<NamedNodeMap> attributes = 0);
+    void proesssFakeEndTag(const QualifiedName&);
+    void processFakeCharacters(const String&);
     void processFakePEndTagIfPInScope();
 
     HTMLElementStack::ElementRecord* furthestBlockForFormattingElement(Element*);