mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Implement [Unscopable] (fixes #11583)
This commit is contained in:
parent
0f1f99a4bf
commit
3529803975
8 changed files with 96 additions and 35 deletions
|
@ -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
|
||||
|
@ -2530,7 +2531,10 @@ let mut prototype_proto = RootedObject::new(cx, ptr::null_mut());
|
|||
%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():
|
||||
|
@ -2546,6 +2550,7 @@ create_interface_prototype_object(cx,
|
|||
%(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());
|
||||
|
@ -5058,9 +5063,13 @@ class CGDescriptor(CGThing):
|
|||
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))
|
||||
|
@ -5072,7 +5081,9 @@ class CGDescriptor(CGThing):
|
|||
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))
|
||||
|
@ -5106,10 +5117,6 @@ class CGDescriptor(CGThing):
|
|||
if not descriptor.interface.isCallback():
|
||||
cgThings.append(CGPrototypeJSClass(descriptor))
|
||||
|
||||
properties = PropertyArrays(descriptor)
|
||||
cgThings.append(CGGeneric(str(properties)))
|
||||
cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties))
|
||||
|
||||
# If there are no constant members, don't make a module for constants
|
||||
constMembers = [m for m in descriptor.interface.members if m.isConst()]
|
||||
if constMembers:
|
||||
|
@ -5156,13 +5163,25 @@ class CGDescriptor(CGThing):
|
|||
|
||||
cgThings.append(CGWrapMethod(descriptor))
|
||||
|
||||
haveUnscopables = False
|
||||
if not descriptor.interface.isCallback():
|
||||
if unscopableNames:
|
||||
haveUnscopables = True
|
||||
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"))
|
||||
if descriptor.concrete or descriptor.hasDescendants():
|
||||
cgThings.append(CGIDLInterface(descriptor))
|
||||
cgThings.append(CGInterfaceTrait(descriptor))
|
||||
if descriptor.weakReferenceable:
|
||||
cgThings.append(CGWeakReferenceableTrait(descriptor))
|
||||
|
||||
properties = PropertyArrays(descriptor)
|
||||
cgThings.append(CGGeneric(str(properties)))
|
||||
cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties, haveUnscopables))
|
||||
|
||||
cgThings = CGList(cgThings, "\n")
|
||||
# self.cgRoot = CGWrapper(CGNamespace(toBindingNamespace(descriptor.name),
|
||||
# cgThings),
|
||||
|
|
|
@ -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;
|
||||
|
@ -236,8 +238,22 @@ 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.
|
||||
|
@ -375,6 +391,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,
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
2
components/servo/Cargo.lock
generated
2
components/servo/Cargo.lock
generated
|
@ -1077,7 +1077,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "js"
|
||||
version = "0.1.3"
|
||||
source = "git+https://github.com/servo/rust-mozjs#c6f6817a7beb7f310050e1dde88654a95de6df26"
|
||||
source = "git+https://github.com/servo/rust-mozjs#a5ec009853a6bd1c57d9c909a0d2994bc015cee2"
|
||||
dependencies = [
|
||||
"heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
2
ports/cef/Cargo.lock
generated
2
ports/cef/Cargo.lock
generated
|
@ -990,7 +990,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "js"
|
||||
version = "0.1.3"
|
||||
source = "git+https://github.com/servo/rust-mozjs#c6f6817a7beb7f310050e1dde88654a95de6df26"
|
||||
source = "git+https://github.com/servo/rust-mozjs#a5ec009853a6bd1c57d9c909a0d2994bc015cee2"
|
||||
dependencies = [
|
||||
"heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
[remove-unscopable.html]
|
||||
type: testharness
|
||||
[remove() should be unscopable]
|
||||
expected: FAIL
|
||||
|
|
@ -5,14 +5,28 @@
|
|||
<script src=/resources/testharnessreport.js></script>
|
||||
<div id="testDiv" onclick="result1 = remove; result2 = this.remove;"></div>
|
||||
<script>
|
||||
var remove = "Hello there";
|
||||
var result1;
|
||||
var result2;
|
||||
test(function() {
|
||||
assert_true(Element.prototype[Symbol.unscopables].remove);
|
||||
var div = document.querySelector("#testDiv");
|
||||
div.dispatchEvent(new Event("click"));
|
||||
assert_equals(typeof result1, "string");
|
||||
assert_equals(typeof result2, "function");
|
||||
}, "remove() should be unscopable")
|
||||
var unscopables = [
|
||||
"before",
|
||||
"after",
|
||||
"replaceWith",
|
||||
"remove",
|
||||
"prepend",
|
||||
"append"
|
||||
];
|
||||
for (var i in unscopables) {
|
||||
var name = unscopables[i];
|
||||
window[name] = "Hello there";
|
||||
result1 = result2 = undefined;
|
||||
test(function () {
|
||||
assert_true(Element.prototype[Symbol.unscopables][name]);
|
||||
var div = document.querySelector('#testDiv');
|
||||
div.setAttribute(
|
||||
"onclick", "result1 = " + name + "; result2 = this." + name + ";");
|
||||
div.dispatchEvent(new Event("click"));
|
||||
assert_equals(typeof result1, "string");
|
||||
assert_equals(typeof result2, "function");
|
||||
}, name + "() should be unscopable");
|
||||
}
|
||||
</script>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue