Title: [147113] trunk
Revision
147113
Author
morr...@google.com
Date
2013-03-28 07:34:21 -0700 (Thu, 28 Mar 2013)

Log Message

Custom Elements: should support non-HTML namespaces.
https://bugs.webkit.org/show_bug.cgi?id=111693

Reviewed by Dimitri Glazkov.

Source/WebCore:

Some existing code assumes that the element extends HTMLElements.
This change allow it to extend from Element. Note that the
namespace URI of a custom element is determined by given element
prototype: An element will have XHTML namespace if its prototype
chain includes HTMLElements, SVGElement leads SVG namespace and
null otherwise, respectively.

Test: fast/dom/custom/document-register-namespace.html

* bindings/v8/CustomElementHelpers.cpp:
(WebCore::hasValidPrototypeChainFor): Factored out from isValidPrototypeParameter()
(WebCore::CustomElementHelpers::isValidPrototypeParameter): Extend to support non HTMLElement prototype
(WebCore::CustomElementHelpers::findLocalName): Support non-HTML element names.
* bindings/v8/CustomElementHelpers.h:
(CustomElementHelpers):
* dom/CustomElementConstructor.cpp:
(WebCore::CustomElementConstructor::createElementInternal):
* dom/CustomElementRegistry.cpp:
(WebCore::CustomElementRegistry::registerElement): No longer hard-codes namespace and picks one based on the prototype value.
* dom/CustomElementRegistry.h:
(CustomElementRegistry):

LayoutTests:

* fast/dom/custom/document-register-namespace-expected.txt: Added.
* fast/dom/custom/document-register-namespace.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (147112 => 147113)


--- trunk/LayoutTests/ChangeLog	2013-03-28 14:28:32 UTC (rev 147112)
+++ trunk/LayoutTests/ChangeLog	2013-03-28 14:34:21 UTC (rev 147113)
@@ -1,3 +1,13 @@
+2013-03-28  Hajime Morrita  <morr...@google.com>
+
+        Custom Elements: should support non-HTML namespaces.
+        https://bugs.webkit.org/show_bug.cgi?id=111693
+
+        Reviewed by Dimitri Glazkov.
+
+        * fast/dom/custom/document-register-namespace-expected.txt: Added.
+        * fast/dom/custom/document-register-namespace.html: Added.
+
 2013-03-28  Christophe Dumez  <ch.du...@sisa.samsung.com>
 
         Unreviewed EFL gardening.

Added: trunk/LayoutTests/fast/dom/custom/document-register-namespace-expected.txt (0 => 147113)


--- trunk/LayoutTests/fast/dom/custom/document-register-namespace-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/dom/custom/document-register-namespace-expected.txt	2013-03-28 14:34:21 UTC (rev 147113)
@@ -0,0 +1,38 @@
+Using document.register() for extending HTML and non-HTML elements.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS html1.namespaceURI is 'http://www.w3.org/1999/xhtml'
+PASS html2.namespaceURI is 'http://www.w3.org/1999/xhtml'
+PASS html3.namespaceURI is 'http://www.w3.org/1999/xhtml'
+PASS html4.namespaceURI is 'http://www.w3.org/1999/xhtml'
+PASS notHTML.namespaceURI is 'http://www.example.com/'
+PASS notHTML instanceof CustomHTMLElement is false
+PASS notHTML instanceof HTMLElement is false
+PASS svg1.tagName is 'svg-foo'
+PASS svg1.namespaceURI is 'http://www.w3.org/2000/svg'
+PASS svg2.tagName is 'svg-foo'
+PASS svg2.namespaceURI is 'http://www.w3.org/2000/svg'
+PASS svg3.tagName is 'svg-foo'
+PASS svg3.namespaceURI is 'http://www.w3.org/2000/svg'
+PASS notSVG1.namespaceURI is 'http://www.w3.org/1999/xhtml'
+PASS notSVG1 instanceof CustomSVGElement is false
+PASS notSVG1 instanceof HTMLUnknownElement is true
+PASS notSVG2.namespaceURI is 'http://www.w3.org/1999/xhtml'
+PASS notSVG2 instanceof CustomSVGElement is false
+PASS notSVG2 instanceof HTMLUnknownElement is true
+PASS xml1.tagName is 'xml-foo'
+PASS xml1.namespaceURI is null
+PASS xml2.tagName is 'xml-foo'
+PASS xml2.namespaceURI is null
+PASS notXML1.namespaceURI is 'http://www.w3.org/1999/xhtml'
+PASS notXML1 instanceof CustomXMLElement is false
+PASS notXML1 instanceof HTMLUnknownElement is true
+PASS notXML2.namespaceURI is 'http://www.w3.org/1999/xhtml'
+PASS notXML2 instanceof CustomXMLElement is false
+PASS notXML2 instanceof HTMLUnknownElement is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/dom/custom/document-register-namespace.html (0 => 147113)


--- trunk/LayoutTests/fast/dom/custom/document-register-namespace.html	                        (rev 0)
+++ trunk/LayoutTests/fast/dom/custom/document-register-namespace.html	2013-03-28 14:34:21 UTC (rev 147113)
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script>
+description("Using document.register() for extending HTML and non-HTML elements.");
+
+document.register = document.register || document.webkitRegister;
+
+function createElementFromHTML(html)
+{
+    var container = document.createElement("div");
+    container.innerHTML = html;
+    return container.firstChild;
+}
+
+function createElementFromSVG(svg)
+{
+    var container = document.createElement("div");
+    container.innerHTML = "<svg xmlns='http://www.w3.org/2000/svg'>" + svg + "</svg>";
+    return container.firstChild.firstChild;
+}
+
+CustomHTMLElement = document.register('html-foo', { prototype: Object.create(HTMLElement.prototype) });
+CustomSVGElement = document.register('svg-foo', { prototype: Object.create(SVGElement.prototype) });
+CustomXMLElement = document.register('xml-foo', { prototype: Object.create(Element.prototype) });
+
+var html1 = new CustomHTMLElement();
+shouldBe("html1.namespaceURI", "'http://www.w3.org/1999/xhtml'");
+var html2 = document.createElement("html-foo");
+shouldBe("html2.namespaceURI", "'http://www.w3.org/1999/xhtml'");
+var html3 = document.createElementNS("http://www.w3.org/1999/xhtml", "html-foo");
+shouldBe("html3.namespaceURI", "'http://www.w3.org/1999/xhtml'");
+var html4 = createElementFromHTML("<html-foo></html-foo>");
+shouldBe("html4.namespaceURI", "'http://www.w3.org/1999/xhtml'");
+
+var notHTML = document.createElementNS("http://www.example.com/", "html-foo");
+shouldBe("notHTML.namespaceURI", "'http://www.example.com/'");
+shouldBeFalse("notHTML instanceof CustomHTMLElement");
+shouldBeFalse("notHTML instanceof HTMLElement");
+
+var svg1 = new CustomSVGElement();
+shouldBe("svg1.tagName", "'svg-foo'");
+shouldBe("svg1.namespaceURI", "'http://www.w3.org/2000/svg'");
+var svg2 = document.createElementNS("http://www.w3.org/2000/svg", "svg-foo");
+shouldBe("svg2.tagName", "'svg-foo'");
+shouldBe("svg2.namespaceURI", "'http://www.w3.org/2000/svg'");
+var svg3 = createElementFromSVG("<svg-foo></svg-foo>");
+shouldBe("svg3.tagName", "'svg-foo'");
+shouldBe("svg3.namespaceURI", "'http://www.w3.org/2000/svg'");
+
+var notSVG1 = document.createElement("svg-foo");
+shouldBe("notSVG1.namespaceURI", "'http://www.w3.org/1999/xhtml'");
+shouldBeFalse("notSVG1 instanceof CustomSVGElement");
+shouldBeTrue("notSVG1 instanceof HTMLUnknownElement");
+var notSVG2 = createElementFromHTML("<svg-foo></svg-foo>");
+shouldBe("notSVG2.namespaceURI", "'http://www.w3.org/1999/xhtml'");
+shouldBeFalse("notSVG2 instanceof CustomSVGElement");
+shouldBeTrue("notSVG2 instanceof HTMLUnknownElement");
+
+var xml1 = new CustomXMLElement();
+shouldBe("xml1.tagName", "'xml-foo'");
+shouldBe("xml1.namespaceURI", "null");
+var xml2 = document.createElementNS(null, "xml-foo");
+shouldBe("xml2.tagName", "'xml-foo'");
+shouldBe("xml2.namespaceURI", "null");
+
+var notXML1 = document.createElement("xml-foo");
+shouldBe("notXML1.namespaceURI", "'http://www.w3.org/1999/xhtml'");
+shouldBeFalse("notXML1 instanceof CustomXMLElement");
+shouldBeTrue("notXML1 instanceof HTMLUnknownElement");
+var notXML2 = createElementFromHTML("<xml-foo></xml-foo>");
+shouldBe("notXML2.namespaceURI", "'http://www.w3.org/1999/xhtml'");
+shouldBeFalse("notXML2 instanceof CustomXMLElement");
+shouldBeTrue("notXML2 instanceof HTMLUnknownElement");
+
+</script>
+<script src=""
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (147112 => 147113)


--- trunk/Source/WebCore/ChangeLog	2013-03-28 14:28:32 UTC (rev 147112)
+++ trunk/Source/WebCore/ChangeLog	2013-03-28 14:34:21 UTC (rev 147113)
@@ -1,3 +1,32 @@
+2013-03-28  Hajime Morrita  <morr...@google.com>
+
+        Custom Elements: should support non-HTML namespaces.
+        https://bugs.webkit.org/show_bug.cgi?id=111693
+
+        Reviewed by Dimitri Glazkov.
+
+        Some existing code assumes that the element extends HTMLElements.
+        This change allow it to extend from Element. Note that the
+        namespace URI of a custom element is determined by given element
+        prototype: An element will have XHTML namespace if its prototype
+        chain includes HTMLElements, SVGElement leads SVG namespace and
+        null otherwise, respectively.
+
+        Test: fast/dom/custom/document-register-namespace.html
+
+        * bindings/v8/CustomElementHelpers.cpp:
+        (WebCore::hasValidPrototypeChainFor): Factored out from isValidPrototypeParameter()
+        (WebCore::CustomElementHelpers::isValidPrototypeParameter): Extend to support non HTMLElement prototype
+        (WebCore::CustomElementHelpers::findLocalName): Support non-HTML element names.
+        * bindings/v8/CustomElementHelpers.h:
+        (CustomElementHelpers):
+        * dom/CustomElementConstructor.cpp:
+        (WebCore::CustomElementConstructor::createElementInternal):
+        * dom/CustomElementRegistry.cpp:
+        (WebCore::CustomElementRegistry::registerElement): No longer hard-codes namespace and picks one based on the prototype value.
+        * dom/CustomElementRegistry.h:
+        (CustomElementRegistry):
+
 2013-03-28  Hans Muller  <hmul...@adobe.com>
 
         [CSS Exclusions] Add support for the simple case of padding a polygonal shape-inside

Modified: trunk/Source/WebCore/bindings/v8/CustomElementHelpers.cpp (147112 => 147113)


--- trunk/Source/WebCore/bindings/v8/CustomElementHelpers.cpp	2013-03-28 14:28:32 UTC (rev 147112)
+++ trunk/Source/WebCore/bindings/v8/CustomElementHelpers.cpp	2013-03-28 14:34:21 UTC (rev 147113)
@@ -33,12 +33,13 @@
 
 #include "CustomElementRegistry.h"
 #include "DOMWrapperWorld.h"
+#include "SVGNames.h"
 #include "ScriptController.h"
 #include "V8CustomElementConstructor.h"
 #include "V8HTMLElementWrapperFactory.h"
-#include "V8HTMLParagraphElement.h"
-#include "V8HTMLSpanElement.h"
+#include "V8SVGElementWrapperFactory.h"
 
+
 namespace WebCore {
 
 #if ENABLE(CUSTOM_ELEMENTS)
@@ -98,10 +99,22 @@
     return true;
 }
 
-static bool hasValidPrototypeChain(v8::Handle<v8::Object> requiredAncestor, v8::Handle<v8::Value> chain)
+static bool hasValidPrototypeChainFor(v8::Handle<v8::Object> prototypeObject, WrapperTypeInfo* typeInfo, v8::Handle<v8::Context> context)
 {
+    // document.register() sets the constructor property, so the prototype shouldn't have one.
+    if (prototypeObject->HasOwnProperty(v8String("constructor", context->GetIsolate())))
+        return false;
+
+    v8::Handle<v8::Object> elementConstructor = v8::Handle<v8::Object>::Cast(V8PerContextData::from(context)->constructorForType(typeInfo));
+    if (elementConstructor.IsEmpty())
+        return false;
+    v8::Handle<v8::Object> elementPrototype = v8::Handle<v8::Object>::Cast(elementConstructor->Get(v8String("prototype", context->GetIsolate())));
+    if (elementPrototype.IsEmpty())
+        return false;
+
+    v8::Handle<v8::Value> chain = prototypeObject;
     while (!chain.IsEmpty() && chain->IsObject()) {
-        if (chain == requiredAncestor)
+        if (chain == elementPrototype)
             return true;
         chain = v8::Handle<v8::Object>::Cast(chain)->GetPrototype();
     }
@@ -109,26 +122,30 @@
     return false;
 }
 
-bool CustomElementHelpers::isValidPrototypeParameter(const ScriptValue& prototype, ScriptState* state)
+bool CustomElementHelpers::isValidPrototypeParameter(const ScriptValue& prototype, ScriptState* state, AtomicString& namespaceURI)
 {
     if (prototype.v8Value().IsEmpty() || !prototype.v8Value()->IsObject())
         return false;
 
-    // document.register() sets the constructor property, so the prototype shouldn't have one.
     v8::Handle<v8::Object> prototypeObject = v8::Handle<v8::Object>::Cast(prototype.v8Value());
-    if (prototypeObject->HasOwnProperty(v8String("constructor", state->context()->GetIsolate())))
-        return false;
-    V8PerContextData* perContextData = V8PerContextData::from(state->context());
-    // FIXME: non-HTML subclasses should be also supported: https://bugs.webkit.org/show_bug.cgi?id=111693
-    v8::Handle<v8::Object> htmlConstructor = v8::Handle<v8::Object>::Cast(perContextData->constructorForType(&V8HTMLElement::info));
-    if (htmlConstructor.IsEmpty())
-        return false;
-    v8::Handle<v8::Object> htmlPrototype = v8::Handle<v8::Object>::Cast(htmlConstructor->Get(v8String("prototype", state->context()->GetIsolate())));
-    if (htmlPrototype.IsEmpty())
-        return false;
-    if (!hasValidPrototypeChain(htmlPrototype, prototypeObject))
-        return false;
-    return true;
+    if (hasValidPrototypeChainFor(prototypeObject, &V8HTMLElement::info, state->context())) {
+        namespaceURI = HTMLNames::xhtmlNamespaceURI;
+        return true;
+    }
+
+#if ENABLE(SVG)
+    if (hasValidPrototypeChainFor(prototypeObject, &V8SVGElement::info, state->context())) {
+        namespaceURI = SVGNames::svgNamespaceURI;
+        return true;
+    }
+#endif
+
+    if (hasValidPrototypeChainFor(prototypeObject, &V8Element::info, state->context())) {
+        namespaceURI = nullAtom;
+        return true;
+    }
+
+    return false;
 }
 
 bool CustomElementHelpers::isFeatureAllowed(ScriptState* state)
@@ -169,7 +186,13 @@
     WrapperTypeInfo* type = CustomElementHelpers::findWrapperType(chain);
     if (!type)
         return 0;
-    return findHTMLTagNameOfV8Type(type);
+    if (const QualifiedName* htmlName = findHTMLTagNameOfV8Type(type))
+        return htmlName;
+#if ENABLE(SVG)
+    if (const QualifiedName* svgName = findSVGTagNameOfV8Type(type))
+        return svgName;
+#endif
+    return 0;
 }
 
 void CustomElementHelpers::invokeReadyCallbackIfNeeded(Element* element, v8::Handle<v8::Context> context)

Modified: trunk/Source/WebCore/bindings/v8/CustomElementHelpers.h (147112 => 147113)


--- trunk/Source/WebCore/bindings/v8/CustomElementHelpers.h	2013-03-28 14:28:32 UTC (rev 147112)
+++ trunk/Source/WebCore/bindings/v8/CustomElementHelpers.h	2013-03-28 14:34:21 UTC (rev 147113)
@@ -56,6 +56,7 @@
 class CustomElementHelpers {
 public:
     static bool initializeConstructorWrapper(CustomElementConstructor*, const ScriptValue& prototype, ScriptState*);
+    static bool isValidPrototypeParameter(const ScriptValue&, ScriptState*, AtomicString& namespaceURI);
     static bool isValidPrototypeParameter(const ScriptValue&, ScriptState*);
     static bool isFeatureAllowed(ScriptState*);
     static const QualifiedName* findLocalName(const ScriptValue& prototype);
@@ -93,6 +94,12 @@
     return 0;
 }
 
+inline bool CustomElementHelpers::isValidPrototypeParameter(const ScriptValue& value, ScriptState* state)
+{
+    AtomicString namespaceURI;
+    return isValidPrototypeParameter(value, state, namespaceURI);
+}
+
 #endif // ENABLE(CUSTOM_ELEMENTS)
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/dom/CustomElementConstructor.cpp (147112 => 147113)


--- trunk/Source/WebCore/dom/CustomElementConstructor.cpp	2013-03-28 14:28:32 UTC (rev 147112)
+++ trunk/Source/WebCore/dom/CustomElementConstructor.cpp	2013-03-28 14:34:21 UTC (rev 147113)
@@ -38,6 +38,8 @@
 #include "Document.h"
 #include "HTMLElement.h"
 #include "HTMLNames.h"
+#include "SVGElement.h"
+#include "SVGNames.h"
 #include <wtf/Assertions.h>
 
 namespace WebCore {
@@ -77,7 +79,13 @@
         return 0;
     if (m_localName != m_typeName)
         return setTypeExtension(document()->createElement(m_localName, document()), m_typeName.localName());
-    return HTMLElement::create(m_typeName, document());
+    if (HTMLNames::xhtmlNamespaceURI == m_typeName.namespaceURI())
+        return HTMLElement::create(m_typeName, document());
+#if ENABLE(SVG)
+    if (SVGNames::svgNamespaceURI == m_typeName.namespaceURI())
+        return SVGElement::create(m_typeName, document());
+#endif
+    return Element::create(m_typeName, document());
 }
 
 PassRefPtr<Element> setTypeExtension(PassRefPtr<Element> element, const AtomicString& typeExtension)

Modified: trunk/Source/WebCore/dom/CustomElementRegistry.cpp (147112 => 147113)


--- trunk/Source/WebCore/dom/CustomElementRegistry.cpp	2013-03-28 14:28:32 UTC (rev 147112)
+++ trunk/Source/WebCore/dom/CustomElementRegistry.cpp	2013-03-28 14:34:21 UTC (rev 147113)
@@ -115,8 +115,8 @@
     if (!CustomElementHelpers::isFeatureAllowed(state))
         return 0;
 
-    QualifiedName newName(nullAtom, name.lower(), HTMLNames::xhtmlNamespaceURI);
-    if (!isValidName(newName.localName())) {
+    AtomicString lowerName = name.lower();
+    if (!isValidName(lowerName)) {
         ec = INVALID_CHARACTER_ERR;
         return 0;
     }
@@ -132,19 +132,21 @@
         return 0;
     }
 
-    if (!CustomElementHelpers::isValidPrototypeParameter(prototypeValue, state)) {
+    AtomicString namespaceURI;
+    if (!CustomElementHelpers::isValidPrototypeParameter(prototypeValue, state, namespaceURI)) {
         ec = INVALID_STATE_ERR;
         return 0;
     }
 
-    if (m_names.contains(newName)) {
+    if (m_names.contains(lowerName)) {
         ec = INVALID_STATE_ERR;
         return 0;
     }
 
     const QualifiedName* localNameFound = CustomElementHelpers::findLocalName(prototypeValue);
-    QualifiedName localNameToUse = localNameFound ? *localNameFound : newName;
-    if (find(newName, localNameToUse)) {
+    QualifiedName typeName(nullAtom, lowerName, namespaceURI);
+    QualifiedName localNameToUse = localNameFound ? *localNameFound : typeName;
+    if (find(typeName, localNameToUse)) {
         ec = INVALID_STATE_ERR;
         return 0;
     }
@@ -155,14 +157,14 @@
         return 0;
     }
 
-    RefPtr<CustomElementConstructor> constructor = CustomElementConstructor::create(state, document(), newName, localNameToUse, prototypeValue);
+    RefPtr<CustomElementConstructor> constructor = CustomElementConstructor::create(state, document(), typeName, localNameToUse, prototypeValue);
     if (!constructor) {
         ec = INVALID_STATE_ERR;
         return 0;
     }
         
     m_constructors.add(std::make_pair(constructor->typeName(), constructor->localName()), constructor);
-    m_names.add(constructor->typeName());
+    m_names.add(lowerName);
 
     return constructor;
 }

Modified: trunk/Source/WebCore/dom/CustomElementRegistry.h (147112 => 147113)


--- trunk/Source/WebCore/dom/CustomElementRegistry.h	2013-03-28 14:28:32 UTC (rev 147112)
+++ trunk/Source/WebCore/dom/CustomElementRegistry.h	2013-03-28 14:34:21 UTC (rev 147113)
@@ -38,13 +38,13 @@
 #include "QualifiedName.h"
 #include "ScriptValue.h"
 #include "Supplementable.h"
-#include <wtf/Forward.h>
 #include <wtf/HashSet.h>
 #include <wtf/ListHashSet.h>
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
 #include <wtf/Vector.h>
+#include <wtf/text/AtomicStringHash.h>
 
 namespace WebCore {
 
@@ -93,7 +93,7 @@
 
 private:
     typedef HashMap<std::pair<QualifiedName, QualifiedName>, RefPtr<CustomElementConstructor> > ConstructorMap;
-    typedef HashSet<QualifiedName> NameSet;
+    typedef HashSet<AtomicString> NameSet;
     typedef ListHashSet<CustomElementRegistry*> InstanceSet;
 
     static bool isValidName(const AtomicString&);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to