Implement the [Exposed] extended attribute on interfaces.

Fixes #2823.
This commit is contained in:
Ms2ger 2016-07-08 15:48:55 +02:00
parent c064c4950d
commit d678b20616
4 changed files with 54 additions and 16 deletions

View file

@ -1825,12 +1825,17 @@ def DOMClass(descriptor):
protoList.extend(['PrototypeList::ID::Last'] * (descriptor.config.maxProtoChainLength - len(protoList))) protoList.extend(['PrototypeList::ID::Last'] * (descriptor.config.maxProtoChainLength - len(protoList)))
prototypeChainString = ', '.join(protoList) prototypeChainString = ', '.join(protoList)
heapSizeOf = 'heap_size_of_raw_self_and_children::<%s>' % descriptor.interface.identifier.name heapSizeOf = 'heap_size_of_raw_self_and_children::<%s>' % descriptor.interface.identifier.name
if descriptor.isGlobal():
globals_ = camel_to_upper_snake(descriptor.name)
else:
globals_ = 'EMPTY'
return """\ return """\
DOMClass { DOMClass {
interface_chain: [ %s ], interface_chain: [ %s ],
type_id: %s, type_id: %s,
heap_size_of: %s as unsafe fn(_) -> _, heap_size_of: %s as unsafe fn(_) -> _,
}""" % (prototypeChainString, DOMClassTypeId(descriptor), heapSizeOf) global: InterfaceObjectMap::%s,
}""" % (prototypeChainString, DOMClassTypeId(descriptor), heapSizeOf, globals_)
class CGDOMJSClass(CGThing): class CGDOMJSClass(CGThing):
@ -2233,9 +2238,9 @@ match result {
class CGConstructorEnabled(CGAbstractMethod): class CGConstructorEnabled(CGAbstractMethod):
""" """
A method for testing whether we should be exposing this interface A method for testing whether we should be exposing this interface object.
object or navigator property. This can perform various tests This can perform various tests depending on what conditions are specified
depending on what conditions are specified on the interface. on the interface.
""" """
def __init__(self, descriptor): def __init__(self, descriptor):
CGAbstractMethod.__init__(self, descriptor, CGAbstractMethod.__init__(self, descriptor,
@ -2248,6 +2253,11 @@ class CGConstructorEnabled(CGAbstractMethod):
conditions = [] conditions = []
iface = self.descriptor.interface iface = self.descriptor.interface
bits = " | ".join(sorted(
"InterfaceObjectMap::" + camel_to_upper_snake(i) for i in iface.exposureSet
))
conditions.append("is_exposed_in(aObj, %s)" % bits)
pref = iface.getExtendedAttribute("Pref") pref = iface.getExtendedAttribute("Pref")
if pref: if pref:
assert isinstance(pref, list) and len(pref) == 1 assert isinstance(pref, list) and len(pref) == 1
@ -2258,8 +2268,6 @@ class CGConstructorEnabled(CGAbstractMethod):
assert isinstance(func, list) and len(func) == 1 assert isinstance(func, list) and len(func) == 1
conditions.append("%s(aCx, aObj)" % func[0]) conditions.append("%s(aCx, aObj)" % func[0])
assert conditions
return CGList((CGGeneric(cond) for cond in conditions), " &&\n") return CGList((CGGeneric(cond) for cond in conditions), " &&\n")
@ -2805,21 +2813,20 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
return CGAbstractMethod.define(self) return CGAbstractMethod.define(self)
def definition_body(self): def definition_body(self):
def getCheck(desc):
if not desc.isExposedConditionally():
return ""
else:
return "if !ConstructorEnabled(cx, global) { return; }"
if self.descriptor.interface.isCallback(): if self.descriptor.interface.isCallback():
function = "GetConstructorObject" function = "GetConstructorObject"
else: else:
function = "GetProtoObject" function = "GetProtoObject"
return CGGeneric("""\ return CGGeneric("""\
assert!(!global.get().is_null()); assert!(!global.get().is_null());
%s
if !ConstructorEnabled(cx, global) {
return;
}
rooted!(in(cx) let mut proto = ptr::null_mut()); rooted!(in(cx) let mut proto = ptr::null_mut());
%s(cx, global, proto.handle_mut()); %s(cx, global, proto.handle_mut());
assert!(!proto.is_null());""" % (getCheck(self.descriptor), function)) assert!(!proto.is_null());""" % (function,))
def needCx(returnType, arguments, considerTypes): def needCx(returnType, arguments, considerTypes):
@ -5133,7 +5140,6 @@ class CGDescriptor(CGThing):
if descriptor.interface.hasInterfaceObject(): if descriptor.interface.hasInterfaceObject():
cgThings.append(CGDefineDOMInterfaceMethod(descriptor)) cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
if descriptor.isExposedConditionally():
cgThings.append(CGConstructorEnabled(descriptor)) cgThings.append(CGConstructorEnabled(descriptor))
if descriptor.proxy: if descriptor.proxy:
@ -5555,6 +5561,7 @@ class CGBindingRoot(CGThing):
'js::glue::AppendToAutoIdVector', 'js::glue::AppendToAutoIdVector',
'js::rust::{GCMethods, define_methods, define_properties}', 'js::rust::{GCMethods, define_methods, define_properties}',
'dom::bindings', 'dom::bindings',
'dom::bindings::codegen::InterfaceObjectMap',
'dom::bindings::global::{GlobalRef, global_root_from_object, global_root_from_reflector}', 'dom::bindings::global::{GlobalRef, global_root_from_object, global_root_from_reflector}',
'dom::bindings::interface::{InterfaceConstructorBehavior, NonCallbackInterfaceObjectClass}', 'dom::bindings::interface::{InterfaceConstructorBehavior, NonCallbackInterfaceObjectClass}',
'dom::bindings::interface::{create_callback_interface_object, create_interface_prototype_object}', 'dom::bindings::interface::{create_callback_interface_object, create_interface_prototype_object}',
@ -5562,6 +5569,7 @@ class CGBindingRoot(CGThing):
'dom::bindings::interface::{define_guarded_methods, define_guarded_properties}', 'dom::bindings::interface::{define_guarded_methods, define_guarded_properties}',
'dom::bindings::interface::{ConstantSpec, NonNullJSNative}', 'dom::bindings::interface::{ConstantSpec, NonNullJSNative}',
'dom::bindings::interface::ConstantVal::{IntVal, UintVal}', 'dom::bindings::interface::ConstantVal::{IntVal, UintVal}',
'dom::bindings::interface::is_exposed_in',
'dom::bindings::js::{JS, Root, RootedReference}', 'dom::bindings::js::{JS, Root, RootedReference}',
'dom::bindings::js::{OptionalRootedReference}', 'dom::bindings::js::{OptionalRootedReference}',
'dom::bindings::reflector::{Reflectable}', 'dom::bindings::reflector::{Reflectable}',
@ -6215,6 +6223,10 @@ class CallbackSetter(CallbackMember):
return None return None
def camel_to_upper_snake(s):
return "_".join(m.group(0).upper() for m in re.finditer("[A-Z][a-z]*", s))
class GlobalGenRoots(): class GlobalGenRoots():
""" """
Roots for global codegen. Roots for global codegen.
@ -6232,6 +6244,18 @@ class GlobalGenRoots():
] ]
imports = CGList([CGGeneric("use %s;" % mod) for mod in mods], "\n") imports = CGList([CGGeneric("use %s;" % mod) for mod in mods], "\n")
global_descriptors = config.getDescriptors(isGlobal=True)
flags = [("EMPTY", 0)]
flags.extend(
(camel_to_upper_snake(d.name), 2 ** idx)
for (idx, d) in enumerate(global_descriptors)
)
global_flags = CGWrapper(CGIndenter(CGList([
CGGeneric("const %s = %#x," % args)
for args in flags
], "\n")), pre="pub flags Globals: u8 {\n", post="\n}")
globals_ = CGWrapper(CGIndenter(global_flags), pre="bitflags! {\n", post="\n}")
pairs = [] pairs = []
for d in config.getDescriptors(hasInterfaceObject=True): for d in config.getDescriptors(hasInterfaceObject=True):
binding = toBindingNamespace(d.name) binding = toBindingNamespace(d.name)
@ -6251,7 +6275,7 @@ class GlobalGenRoots():
return CGList([ return CGList([
CGGeneric(AUTOGENERATED_WARNING_COMMENT), CGGeneric(AUTOGENERATED_WARNING_COMMENT),
CGList([imports, phf], "\n\n") CGList([imports, globals_, phf], "\n\n")
]) ])
@staticmethod @staticmethod

View file

@ -85,6 +85,8 @@ class Configuration:
getter = lambda x: x.interface.isCallback() getter = lambda x: x.interface.isCallback()
elif key == 'isJSImplemented': elif key == 'isJSImplemented':
getter = lambda x: x.interface.isJSImplemented() getter = lambda x: x.interface.isJSImplemented()
elif key == 'isGlobal':
getter = lambda x: x.isGlobal()
else: else:
getter = lambda x: getattr(x, key) getter = lambda x: getattr(x, key)
curr = filter(lambda x: getter(x) == val, curr) curr = filter(lambda x: getter(x) == val, curr)

View file

@ -4,6 +4,7 @@
//! Machinery to initialise interface prototype objects and interface objects. //! Machinery to initialise interface prototype objects and interface objects.
use dom::bindings::codegen::InterfaceObjectMap::Globals;
use dom::bindings::codegen::PrototypeList; use dom::bindings::codegen::PrototypeList;
use dom::bindings::conversions::get_dom_class; use dom::bindings::conversions::get_dom_class;
use dom::bindings::guard::Guard; use dom::bindings::guard::Guard;
@ -484,3 +485,11 @@ unsafe extern "C" fn non_new_constructor(
throw_type_error(cx, "This constructor needs to be called with `new`."); throw_type_error(cx, "This constructor needs to be called with `new`.");
false false
} }
/// Returns whether an interface with exposure set given by `globals` should
/// be exposed in the global object `obj`.
pub unsafe fn is_exposed_in(object: HandleObject, globals: Globals) -> bool {
let unwrapped = UncheckedUnwrapObject(object.get(), /* stopAtWindowProxy = */ 0);
let dom_class = get_dom_class(unwrapped).unwrap();
globals.contains(dom_class.global)
}

View file

@ -93,6 +93,9 @@ pub struct DOMClass {
/// The HeapSizeOf function wrapper for that interface. /// The HeapSizeOf function wrapper for that interface.
pub heap_size_of: unsafe fn(*const c_void) -> usize, pub heap_size_of: unsafe fn(*const c_void) -> usize,
/// The `Globals` flag for this global interface, if any.
pub global: InterfaceObjectMap::Globals,
} }
unsafe impl Sync for DOMClass {} unsafe impl Sync for DOMClass {}