Skip to content

Commit

Permalink
Implement [Unscopable] (fixes servo#11583)
Browse files Browse the repository at this point in the history
  • Loading branch information
nox committed Jun 5, 2016
1 parent 57cd0aa commit b5a81d5
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 22 deletions.
28 changes: 24 additions & 4 deletions components/script/dom/bindings/codegen/CodegenRust.py
Original file line number Diff line number Diff line change
Expand Up @@ -2494,12 +2494,13 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
properties should be a PropertyArrays instance.
"""
def __init__(self, descriptor, properties):
def __init__(self, descriptor, properties, haveUnscopables):
args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'global'),
Argument('*mut ProtoOrIfaceArray', 'cache')]
CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args,
unsafe=True)
self.properties = properties
self.haveUnscopables = haveUnscopables

def definition_body(self):
name = self.descriptor.interface.identifier.name
Expand Down Expand Up @@ -2530,7 +2531,10 @@ def definition_body(self):
%s;
assert!(!prototype_proto.ptr.is_null());""" % getPrototypeProto)]

properties = {"id": name}
properties = {
"id": name,
"unscopables": "unscopable_names" if self.haveUnscopables else "&[]"
}
for arrayName in self.properties.arrayNames():
array = getattr(self.properties, arrayName)
if array.length():
Expand All @@ -2546,6 +2550,7 @@ def definition_body(self):
%(methods)s,
%(attrs)s,
%(consts)s,
%(unscopables)s,
prototype.handle_mut());
assert!(!prototype.ptr.is_null());
assert!((*cache)[PrototypeList::ID::%(id)s as usize].is_null());
Expand Down Expand Up @@ -5058,9 +5063,13 @@ def __init__(self, descriptor):
descriptor.shouldHaveGetConstructorObjectMethod()):
cgThings.append(CGGetConstructorObjectMethod(descriptor))

unscopableNames = []
for m in descriptor.interface.members:
if (m.isMethod() and
(not m.isIdentifierLess() or m == descriptor.operations["Stringifier"])):
if m.getExtendedAttribute("Unscopable"):
assert not m.isStatic()
unscopableNames.append(m.identifier.name)
if m.isStatic():
assert descriptor.interface.hasInterfaceObject()
cgThings.append(CGStaticMethod(descriptor, m))
Expand All @@ -5072,7 +5081,9 @@ def __init__(self, descriptor):
raise TypeError("Stringifier attributes not supported yet. "
"See https://github.com/servo/servo/issues/7590\n"
"%s" % m.location)

if m.getExtendedAttribute("Unscopable"):
assert not m.isStatic()
unscopableNames.append(m.identifier.name)
if m.isStatic():
assert descriptor.interface.hasInterfaceObject()
cgThings.append(CGStaticGetter(descriptor, m))
Expand Down Expand Up @@ -5106,9 +5117,18 @@ def __init__(self, descriptor):
if not descriptor.interface.isCallback():
cgThings.append(CGPrototypeJSClass(descriptor))

haveUnscopables = (len(unscopableNames) != 0 and
descriptor.interface.hasInterfacePrototypeObject())
if haveUnscopables:
cgThings.append(
CGList([CGGeneric("const unscopable_names: &'static [&'static [u8]] = &["),
CGIndenter(CGList([CGGeneric(str_to_const_array(name)) for
name in unscopableNames], ",\n")),
CGGeneric("];\n")], "\n"))

properties = PropertyArrays(descriptor)
cgThings.append(CGGeneric(str(properties)))
cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties))
cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties, haveUnscopables))

# If there are no constant members, don't make a module for constants
constMembers = [m for m in descriptor.interface.members if m.isConst()]
Expand Down
45 changes: 37 additions & 8 deletions components/script/dom/bindings/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,18 @@ use dom::bindings::conversions::get_dom_class;
use dom::bindings::guard::Guard;
use dom::bindings::utils::get_proto_or_iface_array;
use js::error::throw_type_error;
use js::glue::UncheckedUnwrapObject;
use js::glue::{RUST_SYMBOL_TO_JSID, UncheckedUnwrapObject};
use js::jsapi::{Class, ClassExtension, ClassSpec, GetGlobalForObjectCrossCompartment};
use js::jsapi::{HandleObject, HandleValue, JSClass, JSContext, JSFunctionSpec};
use js::jsapi::{JSNative, JSFUN_CONSTRUCTOR, JSPROP_ENUMERATE, JSPROP_PERMANENT, JSPROP_READONLY};
use js::jsapi::{JSPROP_RESOLVING, JSPropertySpec, JSString, JS_AtomizeAndPinString};
use js::jsapi::{JS_DefineProperty, JS_DefineProperty1, JS_DefineProperty2, JS_DefineProperty4};
use js::jsapi::{GetWellKnownSymbol, HandleObject, HandleValue, JSClass, JSContext};
use js::jsapi::{JSFunctionSpec, JSNative, JSFUN_CONSTRUCTOR, JSPROP_ENUMERATE};
use js::jsapi::{JSPROP_PERMANENT, JSPROP_READONLY, JSPROP_RESOLVING, JSPropertySpec};
use js::jsapi::{JSString, JS_AtomizeAndPinString, JS_DefineProperty, JS_DefineProperty1};
use js::jsapi::{JS_DefineProperty2, JS_DefineProperty4, JS_DefinePropertyById3};
use js::jsapi::{JS_GetClass, JS_GetFunctionObject, JS_GetPrototype, JS_LinkConstructorAndPrototype};
use js::jsapi::{JS_NewFunction, JS_NewObject, JS_NewObjectWithUniqueType, JS_NewStringCopyN};
use js::jsapi::{MutableHandleObject, MutableHandleValue, ObjectOps, RootedObject, RootedString};
use js::jsapi::{RootedValue, Value};
use js::jsapi::{JS_NewFunction, JS_NewObject, JS_NewObjectWithUniqueType};
use js::jsapi::{JS_NewPlainObject, JS_NewStringCopyN, MutableHandleObject};
use js::jsapi::{MutableHandleValue, ObjectOps, RootedId, RootedObject};
use js::jsapi::{RootedString, RootedValue, SymbolCode, TrueHandleValue, Value};
use js::jsval::{BooleanValue, DoubleValue, Int32Value, JSVal, NullValue, UInt32Value};
use js::rust::{define_methods, define_properties};
use libc;
Expand Down Expand Up @@ -236,8 +238,19 @@ pub unsafe fn create_interface_prototype_object(
regular_methods: &[Guard<&'static [JSFunctionSpec]>],
regular_properties: &[Guard<&'static [JSPropertySpec]>],
constants: &[Guard<&[ConstantSpec]>],
unscopable_names: &[&[u8]],
rval: MutableHandleObject) {
create_object(cx, proto, class, regular_methods, regular_properties, constants, rval);
if !unscopable_names.is_empty() {
let mut unscopable_obj = RootedObject::new(cx, ptr::null_mut());
create_unscopable_object(cx, unscopable_names, unscopable_obj.handle_mut());
let unscopable_symbol = GetWellKnownSymbol(cx, SymbolCode::unscopables);
assert!(!unscopable_symbol.is_null());
let unscopable_id = RootedId::new(cx, RUST_SYMBOL_TO_JSID(unscopable_symbol));
assert!(JS_DefinePropertyById3(
cx, rval.handle(), unscopable_id.handle(), unscopable_obj.handle(),
JSPROP_READONLY, None, None))
}
}

/// Create and define the interface object of a non-callback interface.
Expand Down Expand Up @@ -375,6 +388,22 @@ unsafe fn create_object(
}
}

unsafe fn create_unscopable_object(
cx: *mut JSContext,
names: &[&[u8]],
rval: MutableHandleObject) {
assert!(!names.is_empty());
assert!(rval.is_null());
rval.set(JS_NewPlainObject(cx));
assert!(!rval.ptr.is_null());
for &name in names {
assert!(*name.last().unwrap() == b'\0');
assert!(JS_DefineProperty(
cx, rval.handle(), name.as_ptr() as *const libc::c_char, TrueHandleValue,
JSPROP_READONLY, None, None));
}
}

/// Conditionally define methods on an object.
pub unsafe fn define_guarded_methods(
cx: *mut JSContext,
Expand Down
7 changes: 4 additions & 3 deletions components/script/dom/webidls/ChildNode.webidl
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@

[NoInterfaceObject]
interface ChildNode {
[Throws]
[Throws, Unscopable]
void before((Node or DOMString)... nodes);
[Throws]
[Throws, Unscopable]
void after((Node or DOMString)... nodes);
[Throws]
[Throws, Unscopable]
void replaceWith((Node or DOMString)... nodes);
[Unscopable]
void remove();
};

Expand Down
4 changes: 2 additions & 2 deletions components/script/dom/webidls/ParentNode.webidl
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ interface ParentNode {
[Pure]
readonly attribute unsigned long childElementCount;

[Throws]
[Throws, Unscopable]
void prepend((Node or DOMString)... nodes);
[Throws]
[Throws, Unscopable]
void append((Node or DOMString)... nodes);

[Pure, Throws]
Expand Down
5 changes: 0 additions & 5 deletions tests/wpt/metadata/dom/nodes/remove-unscopable.html.ini

This file was deleted.

0 comments on commit b5a81d5

Please sign in to comment.