Object.getOwnPropertyNames() does not return named properties
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 28 Sep 2015 17:43:49 +0000 (17:43 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 28 Sep 2015 17:43:49 +0000 (17:43 +0000)
https://bugs.webkit.org/show_bug.cgi?id=149562
<rdar://problem/22879779>

Reviewed by Darin Adler.

LayoutTests/imported/w3c:

Rebaseline existing W3C tests now that Object.getOwnPropertyNames()
returns named properties for HTMLCollection. We unfortunately still
don't pass those because 'length' / 'constructor' properties are
currently on the instance and they should be on the prototype.

* web-platform-tests/dom/collections/HTMLCollection-supported-property-names-expected.txt:
* web-platform-tests/dom/nodes/Document-getElementsByTagName-expected.txt:
* web-platform-tests/dom/nodes/Element-getElementsByTagName-expected.txt:
* web-platform-tests/html/dom/documents/dom-tree-accessors/document.forms-expected.txt:

Source/WebCore:

Previously, Object.getOwnPropertyNames() did not return named properties
for interfaces with named property getters. This patch adds support for
this in the JS bindings generator and uses it for HTMLCollection only
for now. Other interfaces will be taken care of independently.

Note that currently, even though the named properties are returned by
Object.getOwnPropertyNames(), these properties are still not enumerated.
This is because these are always unenumerable for existing DOM interfaces:
- https://dom.spec.whatwg.org/#interface-htmlcollection
- https://dom.spec.whatwg.org/#namednodemap

In the future, we may need to extend support if some interfaces require
those to be enumerable.

Test: fast/dom/htmlcollection-getownpropertynames.html

* Modules/mediastream/RTCStatsResponse.cpp:
(WebCore::WebCore::RTCStatsResponse::supportedPropertyNames):
* Modules/mediastream/RTCStatsResponse.h:
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateHeader):
(GenerateImplementation):
* css/StyleSheetList.cpp:
(WebCore::StyleSheetList::supportedPropertyNames):
* css/StyleSheetList.h:
* dom/DOMNamedFlowCollection.cpp:
(WebCore::DOMNamedFlowCollection::supportedPropertyNames):
* dom/DOMNamedFlowCollection.h:
* dom/NamedNodeMap.cpp:
(WebCore::NamedNodeMap::supportedPropertyNames):
* dom/NamedNodeMap.h:
* html/HTMLCollection.cpp:
(WebCore::HTMLCollection::supportedPropertyNames):
* html/HTMLCollection.h:
(WebCore::CollectionNamedElementCache::propertyNames):
(WebCore::CollectionNamedElementCache::appendToIdCache):
(WebCore::CollectionNamedElementCache::appendToNameCache):
(WebCore::CollectionNamedElementCache::memoryCost):
(WebCore::CollectionNamedElementCache::append):
* plugins/DOMMimeTypeArray.cpp:
(WebCore::DOMMimeTypeArray::supportedPropertyNames):
* plugins/DOMMimeTypeArray.h:
* plugins/DOMPlugin.cpp:
(WebCore::DOMPlugin::supportedPropertyNames):
* plugins/DOMPlugin.h:
* plugins/DOMPluginArray.cpp:
(WebCore::DOMPluginArray::supportedPropertyNames):
* plugins/DOMPluginArray.h:

LayoutTests:

Add layout test that verifies that Object.getOwnPropertyNames() returns
an HTMLCollection's named properties, in addition to its indexes. It
also checks that they are not enumerable, as per the DOM specification.

* fast/dom/htmlcollection-getownpropertynames-expected.txt: Added.
* fast/dom/htmlcollection-getownpropertynames.html: Added.

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

29 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/dom/htmlcollection-getownpropertynames-expected.txt [new file with mode: 0644]
LayoutTests/fast/dom/htmlcollection-getownpropertynames.html [new file with mode: 0644]
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/dom/collections/HTMLCollection-supported-property-names-expected.txt
LayoutTests/imported/w3c/web-platform-tests/dom/nodes/Document-getElementsByTagName-expected.txt
LayoutTests/imported/w3c/web-platform-tests/dom/nodes/Element-getElementsByTagName-expected.txt
LayoutTests/imported/w3c/web-platform-tests/html/dom/documents/dom-tree-accessors/document.forms-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/Modules/mediastream/RTCStatsResponse.cpp
Source/WebCore/Modules/mediastream/RTCStatsResponse.h
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/bindings/scripts/test/JS/JSTestEventTarget.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestOverrideBuiltins.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestOverrideBuiltins.h
Source/WebCore/css/StyleSheetList.cpp
Source/WebCore/css/StyleSheetList.h
Source/WebCore/dom/DOMNamedFlowCollection.cpp
Source/WebCore/dom/DOMNamedFlowCollection.h
Source/WebCore/dom/NamedNodeMap.cpp
Source/WebCore/dom/NamedNodeMap.h
Source/WebCore/html/HTMLCollection.cpp
Source/WebCore/html/HTMLCollection.h
Source/WebCore/plugins/DOMMimeTypeArray.cpp
Source/WebCore/plugins/DOMMimeTypeArray.h
Source/WebCore/plugins/DOMPlugin.cpp
Source/WebCore/plugins/DOMPlugin.h
Source/WebCore/plugins/DOMPluginArray.cpp
Source/WebCore/plugins/DOMPluginArray.h

index be6169b..aeb431d 100644 (file)
@@ -1,3 +1,18 @@
+2015-09-28  Chris Dumez  <cdumez@apple.com>
+
+        Object.getOwnPropertyNames() does not return named properties
+        https://bugs.webkit.org/show_bug.cgi?id=149562
+        <rdar://problem/22879779>
+
+        Reviewed by Darin Adler.
+
+        Add layout test that verifies that Object.getOwnPropertyNames() returns
+        an HTMLCollection's named properties, in addition to its indexes. It
+        also checks that they are not enumerable, as per the DOM specification.
+
+        * fast/dom/htmlcollection-getownpropertynames-expected.txt: Added.
+        * fast/dom/htmlcollection-getownpropertynames.html: Added.
+
 2015-09-28  Ryosuke Niwa  <rniwa@webkit.org>
 
         Update bug numbers for failing test expectations in fast/shadow-dom.
diff --git a/LayoutTests/fast/dom/htmlcollection-getownpropertynames-expected.txt b/LayoutTests/fast/dom/htmlcollection-getownpropertynames-expected.txt
new file mode 100644 (file)
index 0000000..3ae3f27
--- /dev/null
@@ -0,0 +1,16 @@
+Tests that HTMLCollection's named properties returned by Object.getOwnPropertyNames() but not enumerable.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+* Own properties
+Actual:   ['0', '1', '2', '3', '4', '5', '6', '7', 'some-id', 'some-name', 'another-id', 'another-name', 'constructor', 'length']
+Expected: ['0', '1', '2', '3', '4', '5', '6', '7', 'some-id', 'some-name', 'another-id', 'another-name']
+
+* Enumerated properties
+Actual:   ['0', '1', '2', '3', '4', '5', '6', '7', 'length', 'item', 'namedItem']
+Expected: ['0', '1', '2', '3', '4', '5', '6', '7', 'length', 'item', 'namedItem']
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/dom/htmlcollection-getownpropertynames.html b/LayoutTests/fast/dom/htmlcollection-getownpropertynames.html
new file mode 100644 (file)
index 0000000..3037fce
--- /dev/null
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../../resources/js-test-pre.js"></script>
+<div id="playground">
+    <!-- with no attribute -->
+    <span></span>
+
+    <!-- with `id` attribute -->
+    <span id=''></span>
+    <span id='some-id'></span>
+    <span id='some-id'></span><!-- to ensure no duplicates -->
+
+    <!-- with `name` attribute -->
+    <span name=''></span>
+    <span name='some-name'></span>
+    <span name='some-name'></span><!-- to ensure no duplicates -->
+
+    <!-- with `name` and `id` attribute -->
+    <span id='another-id' name='another-name'></span>
+</div>
+<script>
+description("Tests that HTMLCollection's named properties returned by Object.getOwnPropertyNames() but not enumerable.");
+
+var playground = document.getElementById("playground");
+var elements = playground.getElementsByTagName("span");
+
+debug("* Own properties");
+var ownProperties = Object.getOwnPropertyNames(elements);
+var result = "[";
+var isFirst = true;
+for (var i = 0; i < ownProperties.length; i++) {
+    if (isFirst)
+        isFirst = false;
+    else
+       result += ", ";
+    result += "'" + ownProperties[i] + "'";
+}
+result += "]";
+debug("Actual:   " + result);
+debug("Expected: ['0', '1', '2', '3', '4', '5', '6', '7', 'some-id', 'some-name', 'another-id', 'another-name']");
+
+debug("");
+debug("* Enumerated properties");
+result = "[";
+isFirst = true;
+for (var property in elements) {
+    if (isFirst)
+        isFirst = false;
+    else
+       result += ", ";
+    result += "'" + property + "'";
+}
+result += "]";
+debug("Actual:   " + result);
+debug("Expected: ['0', '1', '2', '3', '4', '5', '6', '7', 'length', 'item', 'namedItem']");
+
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
index 6107668..064b7b8 100644 (file)
@@ -1,3 +1,21 @@
+2015-09-28  Chris Dumez  <cdumez@apple.com>
+
+        Object.getOwnPropertyNames() does not return named properties
+        https://bugs.webkit.org/show_bug.cgi?id=149562
+        <rdar://problem/22879779>
+
+        Reviewed by Darin Adler.
+
+        Rebaseline existing W3C tests now that Object.getOwnPropertyNames()
+        returns named properties for HTMLCollection. We unfortunately still
+        don't pass those because 'length' / 'constructor' properties are
+        currently on the instance and they should be on the prototype.
+
+        * web-platform-tests/dom/collections/HTMLCollection-supported-property-names-expected.txt:
+        * web-platform-tests/dom/nodes/Document-getElementsByTagName-expected.txt:
+        * web-platform-tests/dom/nodes/Element-getElementsByTagName-expected.txt:
+        * web-platform-tests/html/dom/documents/dom-tree-accessors/document.forms-expected.txt:
+
 2015-09-24  Chris Dumez  <cdumez@apple.com>
 
         Node.replaceChild() does not behave according to the specification
index 68b451f..2cbf871 100644 (file)
@@ -1,5 +1,5 @@
 
-FAIL Object.getOwnPropertyNames on HTMLCollection assert_array_equals: lengths differ, expected 12 got 10
+FAIL Object.getOwnPropertyNames on HTMLCollection assert_array_equals: lengths differ, expected 12 got 14
 FAIL Object.getOwnPropertyNames on HTMLCollection with non-HTML namespace assert_array_equals: lengths differ, expected 1 got 3
 FAIL Object.getOwnPropertyNames on HTMLCollection with expando object assert_array_equals: lengths differ, expected 2 got 4
 
index dfcd8ff..902d92d 100644 (file)
@@ -8,7 +8,7 @@ FAIL Shouldn't be able to set unsigned properties on a HTMLCollection (strict mo
     }" did not throw
 PASS Should be able to set expando shadowing a proto prop (item) 
 PASS Should be able to set expando shadowing a proto prop (namedItem) 
-FAIL hasOwnProperty, getOwnPropertyDescriptor, getOwnPropertyNames assert_array_equals: lengths differ, expected 2 got 3
+FAIL hasOwnProperty, getOwnPropertyDescriptor, getOwnPropertyNames assert_array_equals: lengths differ, expected 2 got 4
 PASS HTML element with uppercase tagName never matches in HTML Documents 
 PASS Element in non-HTML namespace, no prefix, lowercase name 
 PASS Element in non-HTML namespace, no prefix, uppercase name 
index bedfc86..ba561ad 100644 (file)
@@ -8,7 +8,7 @@ FAIL Shouldn't be able to set unsigned properties on a HTMLCollection (strict mo
     }" did not throw
 PASS Should be able to set expando shadowing a proto prop (item) 
 PASS Should be able to set expando shadowing a proto prop (namedItem) 
-FAIL hasOwnProperty, getOwnPropertyDescriptor, getOwnPropertyNames assert_array_equals: lengths differ, expected 2 got 3
+FAIL hasOwnProperty, getOwnPropertyDescriptor, getOwnPropertyNames assert_array_equals: lengths differ, expected 2 got 4
 PASS HTML element with uppercase tagName never matches in HTML Documents 
 PASS Element in non-HTML namespace, no prefix, lowercase name 
 PASS Element in non-HTML namespace, no prefix, uppercase name 
index 82bf472..0dac11a 100644 (file)
@@ -5,5 +5,5 @@ PASS document.forms
 PASS document.forms.item with string arg 
 PASS document.forms with empty string 
 FAIL document.forms iteration assert_array_equals: property 3, expected "item" but got "length"
-FAIL document.forms getOwnPropertyNames assert_array_equals: property 3, expected "form1" but got "constructor"
+FAIL document.forms getOwnPropertyNames assert_array_equals: lengths differ, expected 5 got 7
 
index 6de3de7..2e6be5e 100644 (file)
@@ -1,3 +1,60 @@
+2015-09-28  Chris Dumez  <cdumez@apple.com>
+
+        Object.getOwnPropertyNames() does not return named properties
+        https://bugs.webkit.org/show_bug.cgi?id=149562
+        <rdar://problem/22879779>
+
+        Reviewed by Darin Adler.
+
+        Previously, Object.getOwnPropertyNames() did not return named properties
+        for interfaces with named property getters. This patch adds support for
+        this in the JS bindings generator and uses it for HTMLCollection only
+        for now. Other interfaces will be taken care of independently.
+
+        Note that currently, even though the named properties are returned by
+        Object.getOwnPropertyNames(), these properties are still not enumerated.
+        This is because these are always unenumerable for existing DOM interfaces:
+        - https://dom.spec.whatwg.org/#interface-htmlcollection
+        - https://dom.spec.whatwg.org/#namednodemap
+
+        In the future, we may need to extend support if some interfaces require
+        those to be enumerable.
+
+        Test: fast/dom/htmlcollection-getownpropertynames.html
+
+        * Modules/mediastream/RTCStatsResponse.cpp:
+        (WebCore::WebCore::RTCStatsResponse::supportedPropertyNames):
+        * Modules/mediastream/RTCStatsResponse.h:
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateHeader):
+        (GenerateImplementation):
+        * css/StyleSheetList.cpp:
+        (WebCore::StyleSheetList::supportedPropertyNames):
+        * css/StyleSheetList.h:
+        * dom/DOMNamedFlowCollection.cpp:
+        (WebCore::DOMNamedFlowCollection::supportedPropertyNames):
+        * dom/DOMNamedFlowCollection.h:
+        * dom/NamedNodeMap.cpp:
+        (WebCore::NamedNodeMap::supportedPropertyNames):
+        * dom/NamedNodeMap.h:
+        * html/HTMLCollection.cpp:
+        (WebCore::HTMLCollection::supportedPropertyNames):
+        * html/HTMLCollection.h:
+        (WebCore::CollectionNamedElementCache::propertyNames):
+        (WebCore::CollectionNamedElementCache::appendToIdCache):
+        (WebCore::CollectionNamedElementCache::appendToNameCache):
+        (WebCore::CollectionNamedElementCache::memoryCost):
+        (WebCore::CollectionNamedElementCache::append):
+        * plugins/DOMMimeTypeArray.cpp:
+        (WebCore::DOMMimeTypeArray::supportedPropertyNames):
+        * plugins/DOMMimeTypeArray.h:
+        * plugins/DOMPlugin.cpp:
+        (WebCore::DOMPlugin::supportedPropertyNames):
+        * plugins/DOMPlugin.h:
+        * plugins/DOMPluginArray.cpp:
+        (WebCore::DOMPluginArray::supportedPropertyNames):
+        * plugins/DOMPluginArray.h:
+
 2015-09-28  Per Arne Vollan  <peavo@outlook.com>
 
         [Curl] Deadlock when downloading.
index c385bef..a26d2b0 100644 (file)
@@ -46,6 +46,12 @@ RefPtr<RTCStatsReport> RTCStatsResponse::namedItem(const AtomicString& name)
     return nullptr;
 }
 
+Vector<AtomicString> WebCore::RTCStatsResponse::supportedPropertyNames()
+{
+    // FIXME: Should be implemented.
+    return Vector<AtomicString>();
+}
+
 size_t RTCStatsResponse::addReport(String id, String type, double timestamp)
 {
     m_result.append(RTCStatsReport::create(id, type, timestamp));
index d704ac2..1235783 100644 (file)
@@ -46,6 +46,7 @@ public:
     const Vector<RefPtr<RTCStatsReport>>& result() const { return m_result; };
 
     RefPtr<RTCStatsReport> namedItem(const AtomicString&);
+    Vector<AtomicString> supportedPropertyNames();
 
     virtual size_t addReport(String id, String type, double timestamp) override;
     virtual void addStatistic(size_t report, String name, String value) override;
index 9bc0ee5..5981657 100644 (file)
@@ -1033,7 +1033,7 @@ sub GenerateHeader
     }
 
     # Custom getOwnPropertyNames function
-    if ($interface->extendedAttributes->{"CustomEnumerateProperty"} || $indexedGetterFunction) {
+    if ($interface->extendedAttributes->{"CustomEnumerateProperty"} || $indexedGetterFunction || $namedGetterFunction) {
         push(@headerContent, "    static void getOwnPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());\n");
         $structureFlags{"JSC::OverridesGetPropertyNames"} = 1;       
     }
@@ -2771,13 +2771,22 @@ sub GenerateImplementation
         }
     }
 
-    if ($indexedGetterFunction && !$interface->extendedAttributes->{"CustomEnumerateProperty"}) {
+    if (($indexedGetterFunction || $namedGetterFunction) && !$interface->extendedAttributes->{"CustomEnumerateProperty"}) {
         push(@implContent, "void ${className}::getOwnPropertyNames(JSObject* object, ExecState* state, PropertyNameArray& propertyNames, EnumerationMode mode)\n");
         push(@implContent, "{\n");
         push(@implContent, "    auto* thisObject = jsCast<${className}*>(object);\n");
         push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
-        push(@implContent, "    for (unsigned i = 0, count = thisObject->impl().length(); i < count; ++i)\n");
-        push(@implContent, "        propertyNames.add(Identifier::from(state, i));\n");
+        if ($indexedGetterFunction) {
+            push(@implContent, "    for (unsigned i = 0, count = thisObject->impl().length(); i < count; ++i)\n");
+            push(@implContent, "        propertyNames.add(Identifier::from(state, i));\n");
+        }
+        if ($namedGetterFunction) {
+            # FIXME: We may need to add an IDL extended attribute at some point if an interface needs enumerable named properties.
+            push(@implContent, "    if (mode.includeDontEnumProperties()) {\n");
+            push(@implContent, "        for (auto& propertyName : thisObject->impl().supportedPropertyNames())\n");
+            push(@implContent, "            propertyNames.add(Identifier::fromString(state, propertyName));\n");
+            push(@implContent, "    }\n");
+        }
         push(@implContent, "    Base::getOwnPropertyNames(thisObject, state, propertyNames, mode);\n");
         push(@implContent, "}\n\n");
     }
index 84c5151..2c359d2 100644 (file)
@@ -233,6 +233,10 @@ void JSTestEventTarget::getOwnPropertyNames(JSObject* object, ExecState* state,
     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
     for (unsigned i = 0, count = thisObject->impl().length(); i < count; ++i)
         propertyNames.add(Identifier::from(state, i));
+    if (mode.includeDontEnumProperties()) {
+        for (auto& propertyName : thisObject->impl().supportedPropertyNames())
+            propertyNames.add(Identifier::fromString(state, propertyName));
+    }
     Base::getOwnPropertyNames(thisObject, state, propertyNames, mode);
 }
 
index b2e4317..2748e62 100644 (file)
@@ -201,6 +201,17 @@ EncodedJSValue jsTestOverrideBuiltinsConstructor(ExecState* state, JSObject*, En
     return JSValue::encode(JSTestOverrideBuiltins::getConstructor(state->vm(), domObject->globalObject()));
 }
 
+void JSTestOverrideBuiltins::getOwnPropertyNames(JSObject* object, ExecState* state, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+    auto* thisObject = jsCast<JSTestOverrideBuiltins*>(object);
+    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+    if (mode.includeDontEnumProperties()) {
+        for (auto& propertyName : thisObject->impl().supportedPropertyNames())
+            propertyNames.add(Identifier::fromString(state, propertyName));
+    }
+    Base::getOwnPropertyNames(thisObject, state, propertyNames, mode);
+}
+
 JSValue JSTestOverrideBuiltins::getConstructor(VM& vm, JSGlobalObject* globalObject)
 {
     return getDOMConstructor<JSTestOverrideBuiltinsConstructor>(vm, jsCast<JSDOMGlobalObject*>(globalObject));
index bba3753..0c9a7f1 100644 (file)
@@ -52,6 +52,7 @@ public:
         return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
     }
 
+    static void getOwnPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode = JSC::EnumerationMode());
     static JSC::JSValue getConstructor(JSC::VM&, JSC::JSGlobalObject*);
     TestOverrideBuiltins& impl() const { return *m_impl; }
     void releaseImpl() { std::exchange(m_impl, nullptr)->deref(); }
@@ -59,7 +60,7 @@ public:
 private:
     TestOverrideBuiltins* m_impl;
 public:
-    static const unsigned StructureFlags = JSC::HasImpureGetOwnPropertySlot | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | Base::StructureFlags;
+    static const unsigned StructureFlags = JSC::HasImpureGetOwnPropertySlot | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
     JSTestOverrideBuiltins(JSC::Structure*, JSDOMGlobalObject*, Ref<TestOverrideBuiltins>&&);
 
index c80ca12..9f706fc 100644 (file)
@@ -81,4 +81,10 @@ HTMLStyleElement* StyleSheetList::getNamedItem(const String& name) const
     return nullptr;
 }
 
+Vector<AtomicString> StyleSheetList::supportedPropertyNames()
+{
+    // FIXME: Should be implemented.
+    return Vector<AtomicString>();
+}
+
 } // namespace WebCore
index 12a7c45..4d109d3 100644 (file)
@@ -41,6 +41,7 @@ public:
     StyleSheet* item(unsigned index);
 
     HTMLStyleElement* getNamedItem(const String&) const;
+    Vector<AtomicString> supportedPropertyNames();
 
     Document* document() { return m_document; }
 
index ddd32e6..e0b42cd 100644 (file)
@@ -61,6 +61,12 @@ RefPtr<WebKitNamedFlow> DOMNamedFlowCollection::namedItem(const AtomicString& na
     return nullptr;
 }
 
+Vector<AtomicString> DOMNamedFlowCollection::supportedPropertyNames()
+{
+    // FIXME: Should be implemented.
+    return Vector<AtomicString>();
+}
+
 // The HashFunctions object used by the HashSet to compare between RefPtr<NamedFlows>.
 // It is safe to set safeToCompareToEmptyOrDeleted because the HashSet will never contain null pointers or deleted values.
 struct DOMNamedFlowCollection::DOMNamedFlowHashFunctions {
index 09f97d0..379eea3 100644 (file)
@@ -50,6 +50,7 @@ public:
     unsigned long length() const;
     PassRefPtr<WebKitNamedFlow> item(unsigned long index) const;
     RefPtr<WebKitNamedFlow> namedItem(const AtomicString& name) const;
+    Vector<AtomicString> supportedPropertyNames();
 
 private:
     struct DOMNamedFlowHashFunctions;
index d9ab661..2e0adf0 100644 (file)
@@ -63,6 +63,12 @@ RefPtr<Node> NamedNodeMap::removeNamedItem(const AtomicString& name, ExceptionCo
     return m_element.detachAttribute(index);
 }
 
+Vector<AtomicString> NamedNodeMap::supportedPropertyNames()
+{
+    // FIXME: Should be implemented.
+    return Vector<AtomicString>();
+}
+
 RefPtr<Node> NamedNodeMap::removeNamedItemNS(const AtomicString& namespaceURI, const AtomicString& localName, ExceptionCode& ec)
 {
     unsigned index = m_element.hasAttributes() ? m_element.findAttributeIndexByName(QualifiedName(nullAtom, localName, namespaceURI)) : ElementData::attributeNotFound;
index d325639..49bd29f 100644 (file)
@@ -53,6 +53,7 @@ public:
 
     RefPtr<Node> getNamedItem(const AtomicString&) const;
     RefPtr<Node> removeNamedItem(const AtomicString& name, ExceptionCode&);
+    Vector<AtomicString> supportedPropertyNames();
 
     RefPtr<Node> getNamedItemNS(const AtomicString& namespaceURI, const AtomicString& localName) const;
     RefPtr<Node> removeNamedItemNS(const AtomicString& namespaceURI, const AtomicString& localName, ExceptionCode&);
index 611d043..e7801bf 100644 (file)
@@ -166,6 +166,15 @@ Element* HTMLCollection::namedItemSlow(const AtomicString& name) const
     return nullptr;
 }
 
+// Documented in https://dom.spec.whatwg.org/#interface-htmlcollection.
+const Vector<AtomicString>& HTMLCollection::supportedPropertyNames()
+{
+    updateNamedElementCache();
+    ASSERT(m_namedElementCache);
+
+    return m_namedElementCache->propertyNames();
+}
+
 void HTMLCollection::updateNamedElementCache() const
 {
     if (hasNamedElementCache())
index 3b4c14a..811a418 100644 (file)
@@ -37,6 +37,7 @@ class CollectionNamedElementCache {
 public:
     const Vector<Element*>* findElementsWithId(const AtomicString& id) const;
     const Vector<Element*>* findElementsWithName(const AtomicString& name) const;
+    const Vector<AtomicString>& propertyNames() const { return m_propertyNames; }
 
     void appendToIdCache(const AtomicString& id, Element&);
     void appendToNameCache(const AtomicString& name, Element&);
@@ -48,10 +49,11 @@ private:
     typedef HashMap<AtomicStringImpl*, Vector<Element*>> StringToElementsMap;
 
     const Vector<Element*>* find(const StringToElementsMap&, const AtomicString& key) const;
-    static void append(StringToElementsMap&, const AtomicString& key, Element&);
+    void append(StringToElementsMap&, const AtomicString& key, Element&);
 
     StringToElementsMap m_idMap;
     StringToElementsMap m_nameMap;
+    Vector<AtomicString> m_propertyNames;
 
 #if !ASSERT_DISABLED
     bool m_didPopulate { false };
@@ -66,6 +68,7 @@ public:
     // DOM API
     virtual Element* item(unsigned index) const override = 0; // Tighten return type from NodeList::item().
     virtual Element* namedItem(const AtomicString& name) const = 0;
+    const Vector<AtomicString>& supportedPropertyNames();
     RefPtr<NodeList> tags(const String&);
 
     // Non-DOM API
@@ -127,17 +130,17 @@ inline const Vector<Element*>* CollectionNamedElementCache::findElementsWithName
 
 inline void CollectionNamedElementCache::appendToIdCache(const AtomicString& id, Element& element)
 {
-    return append(m_idMap, id, element);
+    append(m_idMap, id, element);
 }
 
 inline void CollectionNamedElementCache::appendToNameCache(const AtomicString& name, Element& element)
 {
-    return append(m_nameMap, name, element);
+    append(m_nameMap, name, element);
 }
 
 inline size_t CollectionNamedElementCache::memoryCost() const
 {
-    return (m_idMap.size() + m_nameMap.size()) * sizeof(Element*);
+    return (m_idMap.size() + m_nameMap.size()) * sizeof(Element*) + m_propertyNames.size() * sizeof(AtomicString);
 }
 
 inline void CollectionNamedElementCache::didPopulate()
@@ -158,6 +161,8 @@ inline const Vector<Element*>* CollectionNamedElementCache::find(const StringToE
 
 inline void CollectionNamedElementCache::append(StringToElementsMap& map, const AtomicString& key, Element& element)
 {
+    if (!m_idMap.contains(key.impl()) && !m_nameMap.contains(key.impl()))
+        m_propertyNames.append(key);
     map.add(key.impl(), Vector<Element*>()).iterator->value.append(&element);
 }
 
index 8d8ace5..1e316af 100644 (file)
@@ -86,6 +86,12 @@ RefPtr<DOMMimeType> DOMMimeTypeArray::namedItem(const AtomicString& propertyName
     return nullptr;
 }
 
+Vector<AtomicString> DOMMimeTypeArray::supportedPropertyNames()
+{
+    // FIXME: Should be implemented.
+    return Vector<AtomicString>();
+}
+
 PluginData* DOMMimeTypeArray::getPluginData() const
 {
     if (!m_frame)
index 0fcd312..a2485fb 100644 (file)
@@ -39,6 +39,7 @@ public:
     unsigned length() const;
     RefPtr<DOMMimeType> item(unsigned index);
     RefPtr<DOMMimeType> namedItem(const AtomicString& propertyName);
+    Vector<AtomicString> supportedPropertyNames();
 
 private:
     explicit DOMMimeTypeArray(Frame*);
index 272cbf5..daa00ca 100644 (file)
@@ -85,4 +85,10 @@ RefPtr<DOMMimeType> DOMPlugin::namedItem(const AtomicString& propertyName)
     return nullptr;
 }
 
+Vector<AtomicString> DOMPlugin::supportedPropertyNames()
+{
+    // FIXME: Should be implemented.
+    return Vector<AtomicString>();
+}
+
 } // namespace WebCore
index e70c997..863fad3 100644 (file)
@@ -44,6 +44,7 @@ public:
 
     RefPtr<DOMMimeType> item(unsigned index);
     RefPtr<DOMMimeType> namedItem(const AtomicString& propertyName);
+    Vector<AtomicString> supportedPropertyNames();
 
 private:
     DOMPlugin(PluginData*, Frame*, PluginInfo);
index 7192aac..8f44dd5 100644 (file)
@@ -77,6 +77,12 @@ RefPtr<DOMPlugin> DOMPluginArray::namedItem(const AtomicString& propertyName)
     return nullptr;
 }
 
+Vector<AtomicString> DOMPluginArray::supportedPropertyNames()
+{
+    // FIXME: Should be implemented.
+    return Vector<AtomicString>();
+}
+
 void DOMPluginArray::refresh(bool reload)
 {
     Page::refreshPlugins(reload);
index a922d43..c6f7524 100644 (file)
@@ -39,6 +39,7 @@ public:
     unsigned length() const;
     RefPtr<DOMPlugin> item(unsigned index);
     RefPtr<DOMPlugin> namedItem(const AtomicString& propertyName);
+    Vector<AtomicString> supportedPropertyNames();
 
     void refresh(bool reload);