Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial implementation of ownPropertyKeys proxy handler #7254

Merged
merged 1 commit into from Aug 20, 2015
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -2473,7 +2473,7 @@ def definition_body(self):
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 @@ def definition_body(self):
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 @@ def members():
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 @@ def __init__(self, descriptor):
# 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 @@ def __init__(self, config, prefix, webIDLFile):
'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 @@ def __init__(self, config, prefix, webIDLFile):
'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',
@@ -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,
@@ -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);
}
@@ -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![]
}
}
@@ -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
}
}
@@ -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![]
}
}
@@ -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 {
@@ -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()}
@@ -13,6 +13,7 @@
// web pages.

interface TestBindingProxy : TestBinding {
readonly attribute unsigned long length;

getter DOMString getNamedItem(DOMString name);

"path": "dom/collections/HTMLCollection-empty-name.html",
"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"
"path": "js/builtins/Object.prototype.freeze.html",
"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"
@@ -5,7 +5,3 @@

[document.forms iteration]
expected: FAIL

[document.forms getOwnPropertyNames]
expected: FAIL

@@ -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>
@@ -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>
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.