aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py71
-rw-r--r--components/script/dom/bindings/proxyhandler.rs10
-rw-r--r--components/script/dom/document.rs6
-rw-r--r--components/script/dom/domstringmap.rs7
-rw-r--r--components/script/dom/htmlcollection.rs27
-rw-r--r--components/script/dom/namednodemap.rs6
-rw-r--r--components/script/dom/storage.rs5
-rw-r--r--components/script/dom/testbindingproxy.rs3
-rw-r--r--components/script/dom/webidls/TestBindingProxy.webidl1
-rw-r--r--tests/wpt/metadata/MANIFEST.json8
-rw-r--r--tests/wpt/metadata/html/dom/documents/dom-tree-accessors/document.forms.html.ini4
-rw-r--r--tests/wpt/web-platform-tests/dom/collections/HTMLCollection-supported-property-names.html54
-rw-r--r--tests/wpt/web-platform-tests/js/builtins/Object.prototype.getOwnPropertyNames.html56
13 files changed, 237 insertions, 21 deletions
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py
index 4e8b3d40101..cd3ee9baacb 100644
--- a/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/components/script/dom/bindings/codegen/CodegenRust.py
@@ -2473,7 +2473,7 @@ let traps = ProxyTraps {
enter: None,
getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor),
defineProperty: Some(%s),
- ownPropertyKeys: Some(proxyhandler::own_property_keys),
+ ownPropertyKeys: Some(own_property_keys),
delete_: Some(%s),
enumerate: None,
preventExtensions: Some(proxyhandler::prevent_extensions),
@@ -4178,6 +4178,59 @@ class CGDOMJSProxyHandler_delete(CGAbstractExternMethod):
return CGGeneric(self.getBody())
+class CGDOMJSProxyHandler_ownPropertyKeys(CGAbstractExternMethod):
+ def __init__(self, descriptor):
+ args = [Argument('*mut JSContext', 'cx'),
+ Argument('HandleObject', 'proxy'),
+ Argument('*mut AutoIdVector', 'props')]
+ CGAbstractExternMethod.__init__(self, descriptor, "own_property_keys", "u8", args)
+ self.descriptor = descriptor
+
+ def getBody(self):
+ body = dedent(
+ """
+ let unwrapped_proxy = UnwrapProxy(proxy);
+ """)
+
+ if self.descriptor.operations['IndexedGetter']:
+ body += dedent(
+ """
+ for i in 0..(*unwrapped_proxy).Length() {
+ let rooted_jsid = RootedId::new(cx, int_to_jsid(i as i32));
+ AppendToAutoIdVector(props, rooted_jsid.handle().get());
+ }
+ """)
+
+ if self.descriptor.operations['NamedGetter']:
+ body += dedent(
+ """
+ for name in (*unwrapped_proxy).SupportedPropertyNames() {
+ let cstring = CString::new(name).unwrap();
+ let jsstring = JS_InternString(cx, cstring.as_ptr());
+ let mut rooted = RootedString::new(cx, jsstring);
+ let jsid = INTERNED_STRING_TO_JSID(cx, rooted.handle().get());
+ let rooted_jsid = RootedId::new(cx, jsid);
+ AppendToAutoIdVector(props, rooted_jsid.handle().get());
+ }
+ """)
+
+ body += dedent(
+ """
+ let expando = get_expando_object(proxy);
+ if !expando.is_null() {
+ let rooted_expando = RootedObject::new(cx, expando);
+ GetPropertyKeys(cx, rooted_expando.handle(), JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
+ }
+
+ return JSTrue;
+ """)
+
+ return body
+
+ def definition_body(self):
+ return CGGeneric(self.getBody())
+
+
class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod):
def __init__(self, descriptor):
args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
@@ -4496,6 +4549,14 @@ class CGInterfaceTrait(CGThing):
infallible = 'infallible' in descriptor.getExtendedAttributes(operation)
if operation.isGetter():
arguments = method_arguments(descriptor, rettype, arguments, trailing=("found", "&mut bool"))
+
+ # If this interface 'supports named properties', then we
+ # should be able to access 'supported property names'
+ #
+ # WebIDL, Second Draft, section 3.2.4.5
+ # https://heycam.github.io/webidl/#idl-named-properties
+ if operation.isNamed():
+ yield "SupportedPropertyNames", [], "Vec<DOMString>"
else:
arguments = method_arguments(descriptor, rettype, arguments)
rettype = return_type(descriptor, rettype, infallible)
@@ -4600,6 +4661,7 @@ class CGDescriptor(CGThing):
# cgThings.append(CGProxyIsProxy(descriptor))
cgThings.append(CGProxyUnwrap(descriptor))
cgThings.append(CGDOMJSProxyHandlerDOMClass(descriptor))
+ cgThings.append(CGDOMJSProxyHandler_ownPropertyKeys(descriptor))
cgThings.append(CGDOMJSProxyHandler_getOwnPropertyDescriptor(descriptor))
cgThings.append(CGDOMJSProxyHandler_className(descriptor))
cgThings.append(CGDOMJSProxyHandler_get(descriptor))
@@ -4958,6 +5020,7 @@ class CGBindingRoot(CGThing):
'js::{JSCLASS_IS_GLOBAL, JSCLASS_RESERVED_SLOTS_SHIFT}',
'js::{JSCLASS_RESERVED_SLOTS_MASK}',
'js::{JSPROP_ENUMERATE, JSPROP_SHARED}',
+ 'js::{JSITER_OWNONLY, JSITER_HIDDEN, JSITER_SYMBOLS}',
'js::jsapi::{JS_CallFunctionValue, JS_GetClass, JS_GetGlobalForObject}',
'js::jsapi::{JS_GetObjectPrototype, JS_GetProperty, JS_GetPropertyById}',
'js::jsapi::{JS_GetPropertyDescriptorById, JS_GetReservedSlot}',
@@ -4967,20 +5030,22 @@ class CGBindingRoot(CGThing):
'js::jsapi::{JSClass, FreeOp, JSFreeOp, JSFunctionSpec, jsid}',
'js::jsapi::{MutableHandleValue, MutableHandleObject, HandleObject, HandleValue, RootedObject}',
'js::jsapi::{RootedValue, JSNativeWrapper, JSNative, JSObject, JSPropertyDescriptor}',
+ 'js::jsapi::{RootedId, JS_InternString, RootedString, INTERNED_STRING_TO_JSID}',
'js::jsapi::{JSPropertySpec}',
'js::jsapi::{JSString, JSTracer, JSJitInfo, JSJitInfo_OpType, JSJitInfo_AliasSet}',
'js::jsapi::{MutableHandle, Handle, HandleId, JSType, JSValueType}',
'js::jsapi::{SymbolCode, ObjectOpResult, HandleValueArray}',
'js::jsapi::{JSJitGetterCallArgs, JSJitSetterCallArgs, JSJitMethodCallArgs, CallArgs}',
'js::jsapi::{JSAutoCompartment, JSAutoRequest, JS_ComputeThis}',
- 'js::jsapi::GetGlobalForObjectCrossCompartment',
+ 'js::jsapi::{GetGlobalForObjectCrossCompartment, AutoIdVector, GetPropertyKeys}',
'js::jsval::JSVal',
'js::jsval::{ObjectValue, ObjectOrNullValue, PrivateValue}',
'js::jsval::{NullValue, UndefinedValue}',
'js::glue::{CallJitMethodOp, CallJitGetterOp, CallJitSetterOp, CreateProxyHandler}',
'js::glue::{GetProxyPrivate, NewProxyObject, ProxyTraps}',
'js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO}',
- 'js::glue::{RUST_JS_NumberValue, RUST_JSID_IS_STRING}',
+ 'js::glue::{RUST_JS_NumberValue, RUST_JSID_IS_STRING, int_to_jsid}',
+ 'js::glue::AppendToAutoIdVector',
'js::rust::GCMethods',
'js::{JSTrue, JSFalse}',
'dom::bindings',
diff --git a/components/script/dom/bindings/proxyhandler.rs b/components/script/dom/bindings/proxyhandler.rs
index 69671a71145..2dde7370442 100644
--- a/components/script/dom/bindings/proxyhandler.rs
+++ b/components/script/dom/bindings/proxyhandler.rs
@@ -11,7 +11,6 @@ use dom::bindings::utils::delete_property_by_id;
use js::glue::GetProxyExtra;
use js::glue::InvokeGetOwnPropertyDescriptor;
use js::glue::{SetProxyExtra, GetProxyHandler};
-use js::jsapi::AutoIdVector;
use js::jsapi::GetObjectProto;
use js::jsapi::{Handle, HandleObject, HandleId, MutableHandle, RootedObject, ObjectOpResult};
use js::jsapi::{JSContext, JSPropertyDescriptor, JSObject};
@@ -83,15 +82,6 @@ pub unsafe extern fn delete(cx: *mut JSContext, proxy: HandleObject, id: HandleI
delete_property_by_id(cx, expando.handle(), id, bp)
}
-/// Stub for ownPropertyKeys
-pub unsafe extern fn own_property_keys(_cx: *mut JSContext,
- _proxy: HandleObject,
- _props: *mut AutoIdVector) -> u8 {
- // FIXME: implement this
- // https://github.com/servo/servo/issues/6390
- JSTrue
-}
-
/// Controls whether the Extensible bit can be changed
pub unsafe extern fn prevent_extensions(_cx: *mut JSContext,
_proxy: HandleObject,
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 78399ac1c2b..7e5adec0353 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -1912,6 +1912,12 @@ impl<'a> DocumentMethods for &'a Document {
collection.r().reflector().get_jsobject().get()
}
+ // https://html.spec.whatwg.org/#document
+ fn SupportedPropertyNames(self) -> Vec<DOMString> {
+ // FIXME: unimplemented (https://github.com/servo/servo/issues/7273)
+ vec![]
+ }
+
global_event_handlers!();
event_handler!(readystatechange, GetOnreadystatechange, SetOnreadystatechange);
}
diff --git a/components/script/dom/domstringmap.rs b/components/script/dom/domstringmap.rs
index fdaf9d7f65c..7d3683f74db 100644
--- a/components/script/dom/domstringmap.rs
+++ b/components/script/dom/domstringmap.rs
@@ -67,5 +67,10 @@ impl<'a> DOMStringMapMethods for &'a DOMStringMap {
}
}
}
-}
+ // https://html.spec.whatwg.org/multipage/#domstringmap
+ fn SupportedPropertyNames(self) -> Vec<DOMString> {
+ // FIXME: unimplemented (https://github.com/servo/servo/issues/7273)
+ vec![]
+ }
+}
diff --git a/components/script/dom/htmlcollection.rs b/components/script/dom/htmlcollection.rs
index bbac05d5b97..71da0d9c04c 100644
--- a/components/script/dom/htmlcollection.rs
+++ b/components/script/dom/htmlcollection.rs
@@ -227,5 +227,30 @@ impl<'a> HTMLCollectionMethods for &'a HTMLCollection {
*found = maybe_elem.is_some();
maybe_elem
}
-}
+ // https://dom.spec.whatwg.org/#interface-htmlcollection
+ fn SupportedPropertyNames(self) -> Vec<DOMString> {
+ // Step 1
+ let mut result = vec![];
+
+ // Step 2
+ let ref filter = self.collection.1;
+ let root = self.collection.0.root();
+ let elems = HTMLCollection::traverse(root.r()).filter(|element| filter.filter(element.r(), root.r()));
+ for elem in elems {
+ // Step 2.1
+ let id_attr = elem.get_string_attribute(&atom!("id"));
+ if !id_attr.is_empty() && !result.contains(&id_attr) {
+ result.push(id_attr)
+ }
+ // Step 2.2
+ let name_attr = elem.get_string_attribute(&atom!("name"));
+ if !name_attr.is_empty() && !result.contains(&name_attr) && *elem.namespace() == ns!(HTML) {
+ result.push(name_attr)
+ }
+ }
+
+ // Step 3
+ result
+ }
+}
diff --git a/components/script/dom/namednodemap.rs b/components/script/dom/namednodemap.rs
index 8894764e073..829e97519a2 100644
--- a/components/script/dom/namednodemap.rs
+++ b/components/script/dom/namednodemap.rs
@@ -105,5 +105,9 @@ impl<'a> NamedNodeMapMethods for &'a NamedNodeMap {
*found = item.is_some();
item
}
-}
+ fn SupportedPropertyNames(self) -> Vec<DOMString> {
+ // FIXME: unimplemented (https://github.com/servo/servo/issues/7273)
+ vec![]
+ }
+}
diff --git a/components/script/dom/storage.rs b/components/script/dom/storage.rs
index ca47bb76c03..6ee0d3c9ccd 100644
--- a/components/script/dom/storage.rs
+++ b/components/script/dom/storage.rs
@@ -134,6 +134,11 @@ impl<'a> StorageMethods for &'a Storage {
fn NamedDeleter(self, name: DOMString) {
self.RemoveItem(name);
}
+
+ fn SupportedPropertyNames(self) -> Vec<DOMString> {
+ // FIXME: unimplemented (https://github.com/servo/servo/issues/7273)
+ vec![]
+ }
}
trait PrivateStorageHelpers {
diff --git a/components/script/dom/testbindingproxy.rs b/components/script/dom/testbindingproxy.rs
index 2d2434e5e38..57b925e8d55 100644
--- a/components/script/dom/testbindingproxy.rs
+++ b/components/script/dom/testbindingproxy.rs
@@ -16,7 +16,8 @@ pub struct TestBindingProxy {
}
impl<'a> TestBindingProxyMethods for &'a TestBindingProxy {
-
+ fn Length(self) -> u32 {0}
+ fn SupportedPropertyNames(self) -> Vec<DOMString> {vec![]}
fn GetNamedItem(self, _: DOMString) -> DOMString {"".to_owned()}
fn SetNamedItem(self, _: DOMString, _: DOMString) -> () {}
fn GetItem(self, _: u32) -> DOMString {"".to_owned()}
diff --git a/components/script/dom/webidls/TestBindingProxy.webidl b/components/script/dom/webidls/TestBindingProxy.webidl
index 3a478eb8acf..64a15b35658 100644
--- a/components/script/dom/webidls/TestBindingProxy.webidl
+++ b/components/script/dom/webidls/TestBindingProxy.webidl
@@ -13,6 +13,7 @@
// web pages.
interface TestBindingProxy : TestBinding {
+ readonly attribute unsigned long length;
getter DOMString getNamedItem(DOMString name);
diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json
index 3e618095b54..10050f88235 100644
--- a/tests/wpt/metadata/MANIFEST.json
+++ b/tests/wpt/metadata/MANIFEST.json
@@ -13072,6 +13072,10 @@
"url": "/dom/collections/HTMLCollection-empty-name.html"
},
{
+ "path": "dom/collections/HTMLCollection-supported-property-names.html",
+ "url": "/dom/collections/HTMLCollection-supported-property-names.html"
+ },
+ {
"path": "dom/events/Event-constants.html",
"url": "/dom/events/Event-constants.html"
},
@@ -18072,6 +18076,10 @@
"url": "/js/builtins/Object.prototype.freeze.html"
},
{
+ "path": "js/builtins/Object.prototype.getOwnPropertyNames.html",
+ "url": "/js/builtins/Object.prototype.getOwnPropertyNames.html"
+ },
+ {
"path": "js/builtins/Object.prototype.hasOwnProperty-order.html",
"url": "/js/builtins/Object.prototype.hasOwnProperty-order.html"
},
diff --git a/tests/wpt/metadata/html/dom/documents/dom-tree-accessors/document.forms.html.ini b/tests/wpt/metadata/html/dom/documents/dom-tree-accessors/document.forms.html.ini
index e91f95fe3df..3d14180ee0f 100644
--- a/tests/wpt/metadata/html/dom/documents/dom-tree-accessors/document.forms.html.ini
+++ b/tests/wpt/metadata/html/dom/documents/dom-tree-accessors/document.forms.html.ini
@@ -5,7 +5,3 @@
[document.forms iteration]
expected: FAIL
-
- [document.forms getOwnPropertyNames]
- expected: FAIL
-
diff --git a/tests/wpt/web-platform-tests/dom/collections/HTMLCollection-supported-property-names.html b/tests/wpt/web-platform-tests/dom/collections/HTMLCollection-supported-property-names.html
new file mode 100644
index 00000000000..a37163b7d18
--- /dev/null
+++ b/tests/wpt/web-platform-tests/dom/collections/HTMLCollection-supported-property-names.html
@@ -0,0 +1,54 @@
+<!doctype html>
+<meta charset=utf-8>
+<link rel=help href=https://dom.spec.whatwg.org/#interface-htmlcollection>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+
+<div id=log></div>
+
+<!-- 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>
+
+<script>
+test(function () {
+ var elements = document.getElementsByTagName("span");
+ assert_array_equals(
+ Object.getOwnPropertyNames(elements),
+ ['0', '1', '2', '3', '4', '5', '6', '7', 'some-id', 'some-name', 'another-id', 'another-name']
+ );
+}, 'Object.getOwnPropertyNames on HTMLCollection');
+
+test(function () {
+ var elem = document.createElementNS('some-random-namespace', 'foo');
+ this.add_cleanup(function () {elem.remove();});
+ elem.setAttribute("name", "some-name");
+ document.body.appendChild(elem);
+
+ var elements = document.getElementsByTagName("foo");
+ assert_array_equals(Object.getOwnPropertyNames(elements), ['0']);
+}, 'Object.getOwnPropertyNames on HTMLCollection with non-HTML namespace');
+
+test(function () {
+ var elem = document.createElement('foo');
+ this.add_cleanup(function () {elem.remove();});
+ document.body.appendChild(elem);
+
+ var elements = document.getElementsByTagName("foo");
+ elements.someProperty = "some value";
+
+ assert_array_equals(Object.getOwnPropertyNames(elements), ['0', 'someProperty']);
+}, 'Object.getOwnPropertyNames on HTMLCollection with expando object');
+</script>
diff --git a/tests/wpt/web-platform-tests/js/builtins/Object.prototype.getOwnPropertyNames.html b/tests/wpt/web-platform-tests/js/builtins/Object.prototype.getOwnPropertyNames.html
new file mode 100644
index 00000000000..582f41ba105
--- /dev/null
+++ b/tests/wpt/web-platform-tests/js/builtins/Object.prototype.getOwnPropertyNames.html
@@ -0,0 +1,56 @@
+<!doctype html>
+<title>Object.prototype.getOwnPropertyNames</title>
+<link rel=help href=http://es5.github.io/#x15.2.3.4>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+
+<div id=log></div>
+<script>
+test(function () {
+ var obj = {0: 'a', 1: 'b', 2: 'c'};
+ assert_array_equals(
+ Object.getOwnPropertyNames(obj).sort(),
+ ['0', '1', '2']
+ );
+}, "object");
+
+test(function () {
+ var arr = ['a', 'b', 'c'];
+ assert_array_equals(
+ Object.getOwnPropertyNames(arr).sort(),
+ ['0', '1', '2', 'length']
+ );
+}, "array-like");
+
+test(function () {
+ var obj = Object.create({}, {
+ getFoo: {
+ value: function() { return this.foo; },
+ enumerable: false
+ }
+ });
+ obj.foo = 1;
+ assert_array_equals(
+ Object.getOwnPropertyNames(obj).sort(),
+ ['foo', 'getFoo']
+ );
+}, "non-enumerable property");
+
+test(function() {
+ function ParentClass() {}
+ ParentClass.prototype.inheritedMethod = function() {};
+
+ function ChildClass() {
+ this.prop = 5;
+ this.method = function() {};
+ }
+ ChildClass.prototype = new ParentClass;
+ ChildClass.prototype.prototypeMethod = function() {};
+
+ var obj = new ChildClass;
+ assert_array_equals(
+ Object.getOwnPropertyNames(obj).sort(),
+ ['method', 'prop']
+ );
+}, 'items on the prototype chain are not listed');
+</script>