From b094932d57c7c9cdf555eb201141320c4b390258 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 20 May 2016 21:48:52 +0200 Subject: [PATCH 01/12] Make MemberCondition a function returning a plain string --- .../dom/bindings/codegen/CodegenRust.py | 33 +++++++------------ 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index b44cf2c1c2b..0db105aa3ef 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1322,31 +1322,20 @@ def getRetvalDeclarationForType(returnType, descriptorProvider): returnType) -class MemberCondition: +def MemberCondition(pref, func): """ - An object representing the condition for a member to actually be - exposed. Any of the arguments can be None. If not - None, they should have the following types: + A string representing the condition for a member to actually be exposed. + Any of the arguments can be None. If not None, they should have the + following types: pref: The name of the preference. func: The name of the function. """ - def __init__(self, pref=None, func=None): - assert pref is None or isinstance(pref, str) - assert func is None or isinstance(func, str) - self.pref = pref - - def toFuncPtr(val): - if val is None: - return "None" - return "Some(%s)" % val - self.func = toFuncPtr(func) - - def __eq__(self, other): - return (self.pref == other.pref and self.func == other.func) - - def __ne__(self, other): - return not self.__eq__(other) + assert pref is None or isinstance(pref, str) + assert func is None or isinstance(func, str) + if pref: + return 'Some("%s")' % pref + return "None" class PropertyDefiner: @@ -1427,7 +1416,7 @@ class PropertyDefiner: def switchToCondition(props, condition): prefableSpecs.append(prefableTemplate % - ('Some("%s")' % condition.pref if condition.pref else 'None', + (condition, name + "_specs", len(specs), 'true' if specTerminator else 'false')) @@ -1500,7 +1489,7 @@ class MethodDefiner(PropertyDefiner): "methodInfo": False, "selfHostedName": "ArrayValues", "length": 0, - "condition": MemberCondition()}) + "condition": "None"}) isUnforgeableInterface = bool(descriptor.interface.getExtendedAttribute("Unforgeable")) if not static and unforgeable == isUnforgeableInterface: From bee6f59b16b478625e4078e265b744d4bd3273c9 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 20 May 2016 22:10:31 +0200 Subject: [PATCH 02/12] Use itertools.groupby in generatePrefableArray --- .../dom/bindings/codegen/CodegenRust.py | 34 +++++-------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 0db105aa3ef..a6f03f5c430 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -5,6 +5,7 @@ # Common codegen classes. from collections import defaultdict +from itertools import groupby import operator import re @@ -1406,37 +1407,18 @@ class PropertyDefiner: # members while still allowing us to define all the members in the smallest # number of JSAPI calls. assert len(array) != 0 - # So we won't put a specTerminator at the very front of the list: - lastCondition = getCondition(array[0], self.descriptor) specs = [] - currentSpecs = [] prefableSpecs = [] - prefableTemplate = ' Prefable { pref: %s, specs: %s[%d], terminator: %s }' + hasTerminator = 'true' if specTerminator else 'false' - def switchToCondition(props, condition): - prefableSpecs.append(prefableTemplate % - (condition, - name + "_specs", - len(specs), - 'true' if specTerminator else 'false')) + for cond, members in groupby(array, lambda m: getCondition(m, self.descriptor)): + currentSpecs = [specTemplate % getDataTuple(m) for m in members] + if specTerminator: + currentSpecs.append(specTerminator) specs.append("&[\n" + ",\n".join(currentSpecs) + "]\n") - del currentSpecs[:] - - for member in array: - curCondition = getCondition(member, self.descriptor) - if lastCondition != curCondition: - # Terminate previous list - if specTerminator: - currentSpecs.append(specTerminator) - # And switch to our new pref - switchToCondition(self, lastCondition) - lastCondition = curCondition - # And the actual spec - currentSpecs.append(specTemplate % getDataTuple(member)) - if specTerminator: - currentSpecs.append(specTerminator) - switchToCondition(self, lastCondition) + prefableSpecs.append( + prefableTemplate % (cond, name + "_specs", len(specs) - 1, hasTerminator)) specsArray = ("const %s_specs: &'static [&'static[%s]] = &[\n" + ",\n".join(specs) + "\n" + From adcecda04736623eb4325f7a29c009ddc6b71cd8 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 20 May 2016 22:21:46 +0200 Subject: [PATCH 03/12] Simplify how Prefable arrays are passed in bindings::interface --- .../dom/bindings/codegen/CodegenRust.py | 11 ++---- components/script/dom/bindings/interface.rs | 34 +++++++++---------- 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index a6f03f5c430..b833d431f7f 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -2531,15 +2531,10 @@ assert!(!prototype_proto.ptr.is_null());""" % getPrototypeProto)] properties = {"id": name} for arrayName in self.properties.arrayNames(): array = getattr(self.properties, arrayName) - if arrayName == "consts": - if array.length(): - properties[arrayName] = array.variableName() - else: - properties[arrayName] = "&[]" - elif array.length(): - properties[arrayName] = "Some(%s)" % array.variableName() + if array.length(): + properties[arrayName] = array.variableName() else: - properties[arrayName] = "None" + properties[arrayName] = "&[]" code.append(CGGeneric(""" let mut prototype = RootedObject::new(cx, ptr::null_mut()); diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs index 9ce31b8bd36..f1e6a886eb7 100644 --- a/components/script/dom/bindings/interface.rs +++ b/components/script/dom/bindings/interface.rs @@ -227,8 +227,8 @@ pub unsafe fn create_interface_prototype_object( cx: *mut JSContext, proto: HandleObject, class: &'static JSClass, - regular_methods: Option<&'static [Prefable]>, - regular_properties: Option<&'static [Prefable]>, + regular_methods: &'static [Prefable], + regular_properties: &'static [Prefable], constants: &'static [Prefable], rval: MutableHandleObject) { create_object(cx, proto, class, regular_methods, regular_properties, constants, rval); @@ -240,8 +240,8 @@ pub unsafe fn create_noncallback_interface_object( receiver: HandleObject, proto: HandleObject, class: &'static NonCallbackInterfaceObjectClass, - static_methods: Option<&'static [Prefable]>, - static_properties: Option<&'static [Prefable]>, + static_methods: &'static [Prefable], + static_properties: &'static [Prefable], constants: &'static [Prefable], interface_prototype_object: HandleObject, name: &'static [u8], @@ -354,36 +354,34 @@ unsafe fn create_object( cx: *mut JSContext, proto: HandleObject, class: &'static JSClass, - methods: Option<&'static [Prefable]>, - properties: Option<&'static [Prefable]>, + methods: &'static [Prefable], + properties: &'static [Prefable], constants: &'static [Prefable], rval: MutableHandleObject) { rval.set(JS_NewObjectWithUniqueType(cx, class, proto)); assert!(!rval.ptr.is_null()); - if let Some(methods) = methods { - define_prefable_methods(cx, rval.handle(), methods); - } - if let Some(properties) = properties { - define_prefable_properties(cx, rval.handle(), properties); - } + define_prefable_methods(cx, rval.handle(), methods); + define_prefable_properties(cx, rval.handle(), properties); for prefable in constants { define_constants(cx, rval.handle(), prefable.specs()); } } /// Conditionally define methods on an object. -pub unsafe fn define_prefable_methods(cx: *mut JSContext, - obj: HandleObject, - methods: &'static [Prefable]) { +pub unsafe fn define_prefable_methods( + cx: *mut JSContext, + obj: HandleObject, + methods: &'static [Prefable]) { for prefable in methods { define_methods(cx, obj, prefable.specs()).unwrap(); } } /// Conditionally define properties on an object. -pub unsafe fn define_prefable_properties(cx: *mut JSContext, - obj: HandleObject, - properties: &'static [Prefable]) { +pub unsafe fn define_prefable_properties( + cx: *mut JSContext, + obj: HandleObject, + properties: &'static [Prefable]) { for prefable in properties { define_properties(cx, obj, prefable.specs()).unwrap(); } From a20db08f06f93a693b9288728fc2a4a522f42344 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 20 May 2016 22:34:42 +0200 Subject: [PATCH 04/12] =?UTF-8?q?Remove=20Prefable::terminator=20?= =?UTF-8?q?=F0=9F=A4=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../script/dom/bindings/codegen/CodegenRust.py | 5 ++--- components/script/dom/bindings/interface.rs | 16 ++++++++++++---- components/script/dom/bindings/utils.rs | 13 +++---------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index b833d431f7f..e7fcb887782 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1409,8 +1409,7 @@ class PropertyDefiner: assert len(array) != 0 specs = [] prefableSpecs = [] - prefableTemplate = ' Prefable { pref: %s, specs: %s[%d], terminator: %s }' - hasTerminator = 'true' if specTerminator else 'false' + prefableTemplate = ' Prefable { pref: %s, specs: %s[%d] }' for cond, members in groupby(array, lambda m: getCondition(m, self.descriptor)): currentSpecs = [specTemplate % getDataTuple(m) for m in members] @@ -1418,7 +1417,7 @@ class PropertyDefiner: currentSpecs.append(specTerminator) specs.append("&[\n" + ",\n".join(currentSpecs) + "]\n") prefableSpecs.append( - prefableTemplate % (cond, name + "_specs", len(specs) - 1, hasTerminator)) + prefableTemplate % (cond, name + "_specs", len(specs) - 1)) specsArray = ("const %s_specs: &'static [&'static[%s]] = &[\n" + ",\n".join(specs) + "\n" + diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs index f1e6a886eb7..8791cd4da08 100644 --- a/components/script/dom/bindings/interface.rs +++ b/components/script/dom/bindings/interface.rs @@ -216,7 +216,9 @@ pub unsafe fn create_callback_interface_object( rval.set(JS_NewObject(cx, ptr::null())); assert!(!rval.ptr.is_null()); for prefable in constants { - define_constants(cx, rval.handle(), prefable.specs()); + if let Some(specs) = prefable.specs() { + define_constants(cx, rval.handle(), specs); + } } define_name(cx, rval.handle(), name); define_on_global_object(cx, receiver, name, rval.handle()); @@ -363,7 +365,9 @@ unsafe fn create_object( define_prefable_methods(cx, rval.handle(), methods); define_prefable_properties(cx, rval.handle(), properties); for prefable in constants { - define_constants(cx, rval.handle(), prefable.specs()); + if let Some(specs) = prefable.specs() { + define_constants(cx, rval.handle(), specs); + } } } @@ -373,7 +377,9 @@ pub unsafe fn define_prefable_methods( obj: HandleObject, methods: &'static [Prefable]) { for prefable in methods { - define_methods(cx, obj, prefable.specs()).unwrap(); + if let Some(specs) = prefable.specs() { + define_methods(cx, obj, specs).unwrap(); + } } } @@ -383,7 +389,9 @@ pub unsafe fn define_prefable_properties( obj: HandleObject, properties: &'static [Prefable]) { for prefable in properties { - define_properties(cx, obj, prefable.specs()).unwrap(); + if let Some(specs) = prefable.specs() { + define_properties(cx, obj, specs).unwrap(); + } } } diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs index 607f74456d2..3ba5838a4fa 100644 --- a/components/script/dom/bindings/utils.rs +++ b/components/script/dom/bindings/utils.rs @@ -557,24 +557,17 @@ pub struct Prefable { pub pref: Option<&'static str>, /// The underlying slice of specifications. pub specs: &'static [T], - /// Whether the specifications contain special terminating entries that should be - /// included or not. - pub terminator: bool, } impl Prefable { /// Retrieve the slice represented by this container, unless the condition /// guarding it is false. - pub fn specs(&self) -> &'static [T] { + pub fn specs(&self) -> Option<&'static [T]> { if let Some(pref) = self.pref { if !prefs::get_pref(pref).as_boolean().unwrap_or(false) { - return if self.terminator { - &self.specs[self.specs.len() - 1..] - } else { - &[] - }; + return None; } } - self.specs + Some(self.specs) } } From fd7c4f814949c45518d69216aa384d4d82d60107 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 20 May 2016 23:03:14 +0200 Subject: [PATCH 05/12] Remove utils::Prefable in favour of guard::Guard --- .../dom/bindings/codegen/CodegenRust.py | 29 ++++++----- components/script/dom/bindings/guard.rs | 49 ++++++++++++++++++ components/script/dom/bindings/interface.rs | 51 ++++++++++--------- components/script/dom/bindings/mod.rs | 1 + components/script/dom/bindings/utils.rs | 22 -------- 5 files changed, 91 insertions(+), 61 deletions(-) create mode 100644 components/script/dom/bindings/guard.rs diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index e7fcb887782..f418a1ba569 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1335,8 +1335,8 @@ def MemberCondition(pref, func): assert pref is None or isinstance(pref, str) assert func is None or isinstance(func, str) if pref: - return 'Some("%s")' % pref - return "None" + return 'Condition::Pref("%s")' % pref + return "Condition::Satisfied" class PropertyDefiner: @@ -1380,8 +1380,8 @@ class PropertyDefiner: PropertyDefiner.getStringAttr(interfaceMember, "Func")) - def generatePrefableArray(self, array, name, specTemplate, specTerminator, - specType, getCondition, getDataTuple): + def generateGuardedArray(self, array, name, specTemplate, specTerminator, + specType, getCondition, getDataTuple): """ This method generates our various arrays. @@ -1409,7 +1409,7 @@ class PropertyDefiner: assert len(array) != 0 specs = [] prefableSpecs = [] - prefableTemplate = ' Prefable { pref: %s, specs: %s[%d] }' + prefableTemplate = ' Guard::new(%s, %s[%d])' for cond, members in groupby(array, lambda m: getCondition(m, self.descriptor)): currentSpecs = [specTemplate % getDataTuple(m) for m in members] @@ -1423,7 +1423,7 @@ class PropertyDefiner: ",\n".join(specs) + "\n" + "];\n") % (name, specType) - prefArray = ("const %s: &'static [Prefable<%s>] = &[\n" + + prefArray = ("const %s: &'static [Guard<&'static [%s]>] = &[\n" + ",\n".join(prefableSpecs) + "\n" + "];\n") % (name, specType) return specsArray + prefArray @@ -1470,7 +1470,7 @@ class MethodDefiner(PropertyDefiner): "methodInfo": False, "selfHostedName": "ArrayValues", "length": 0, - "condition": "None"}) + "condition": "Condition::Satisfied"}) isUnforgeableInterface = bool(descriptor.interface.getExtendedAttribute("Unforgeable")) if not static and unforgeable == isUnforgeableInterface: @@ -1521,7 +1521,7 @@ class MethodDefiner(PropertyDefiner): % m["name"][2:], accessor, jitinfo, m["length"], flags, selfHostedName) return (str_to_const_array(m["name"]), accessor, jitinfo, m["length"], flags, selfHostedName) - return self.generatePrefableArray( + return self.generateGuardedArray( array, name, ' JSFunctionSpec {\n' ' name: %s as *const u8 as *const libc::c_char,\n' @@ -1601,7 +1601,7 @@ class AttrDefiner(PropertyDefiner): return (str_to_const_array(attr.identifier.name), flags, getter(attr), setter(attr)) - return self.generatePrefableArray( + return self.generateGuardedArray( array, name, ' JSPropertySpec {\n' ' name: %s as *const u8 as *const libc::c_char,\n' @@ -1636,7 +1636,7 @@ class ConstDefiner(PropertyDefiner): return (str_to_const_array(const.identifier.name), convertConstIDLValueToJSVal(const.value)) - return self.generatePrefableArray( + return self.generateGuardedArray( array, name, ' ConstantSpec { name: %s, value: %s }', None, @@ -2297,8 +2297,8 @@ def InitUnforgeablePropertiesOnHolder(descriptor, properties): """ unforgeables = [] - defineUnforgeableAttrs = "define_prefable_properties(cx, unforgeable_holder.handle(), %s);" - defineUnforgeableMethods = "define_prefable_methods(cx, unforgeable_holder.handle(), %s);" + defineUnforgeableAttrs = "define_guarded_properties(cx, unforgeable_holder.handle(), %s);" + defineUnforgeableMethods = "define_guarded_methods(cx, unforgeable_holder.handle(), %s);" unforgeableMembers = [ (defineUnforgeableAttrs, properties.unforgeable_attrs), @@ -5528,13 +5528,13 @@ class CGBindingRoot(CGThing): 'dom::bindings::interface::{InterfaceConstructorBehavior, NonCallbackInterfaceObjectClass}', 'dom::bindings::interface::{create_callback_interface_object, create_interface_prototype_object}', 'dom::bindings::interface::{create_named_constructors, create_noncallback_interface_object}', - 'dom::bindings::interface::{define_prefable_methods, define_prefable_properties}', + 'dom::bindings::interface::{define_guarded_methods, define_guarded_properties}', 'dom::bindings::interface::{ConstantSpec, NonNullJSNative}', 'dom::bindings::interface::ConstantVal::{IntVal, UintVal}', 'dom::bindings::js::{JS, Root, RootedReference}', 'dom::bindings::js::{OptionalRootedReference}', 'dom::bindings::reflector::{Reflectable}', - 'dom::bindings::utils::{DOMClass, DOMJSClass, Prefable}', + 'dom::bindings::utils::{DOMClass, DOMJSClass}', 'dom::bindings::utils::{DOM_PROTO_UNFORGEABLE_HOLDER_SLOT, JSCLASS_DOM_GLOBAL}', 'dom::bindings::utils::{ProtoOrIfaceArray, create_dom_global}', 'dom::bindings::utils::{enumerate_global, finalize_global, find_enum_string_index}', @@ -5558,6 +5558,7 @@ class CGBindingRoot(CGThing): 'dom::bindings::error::{Fallible, Error, ErrorResult}', 'dom::bindings::error::Error::JSFailed', 'dom::bindings::error::throw_dom_exception', + 'dom::bindings::guard::{Condition, Guard}', 'dom::bindings::proxyhandler', 'dom::bindings::proxyhandler::{ensure_expando_object, fill_property_descriptor}', 'dom::bindings::proxyhandler::{get_expando_object, get_property_descriptor}', diff --git a/components/script/dom/bindings/guard.rs b/components/script/dom/bindings/guard.rs new file mode 100644 index 00000000000..15b7c418a31 --- /dev/null +++ b/components/script/dom/bindings/guard.rs @@ -0,0 +1,49 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! Machinery to conditionally expose things. + +use util::prefs::get_pref; + +/// A container with a condition. +pub struct Guard { + condition: Condition, + value: T, +} + +impl Guard { + /// Construct a new guarded value. + pub const fn new(condition: Condition, value: T) -> Self { + Guard { + condition: condition, + value: value, + } + } + + /// Expose the value if the condition is satisfied. + pub fn expose(&self) -> Option { + if self.condition.is_satisfied() { + Some(self.value) + } else { + None + } + } +} + +/// A condition to expose things. +pub enum Condition { + /// The condition is satisfied if the preference is set. + Pref(&'static str), + /// The condition is always satisfied. + Satisfied, +} + +impl Condition { + fn is_satisfied(&self) -> bool { + match *self { + Condition::Pref(name) => get_pref(name).as_boolean().unwrap_or(false), + Condition::Satisfied => true, + } + } +} diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs index 8791cd4da08..65727ebfa8d 100644 --- a/components/script/dom/bindings/interface.rs +++ b/components/script/dom/bindings/interface.rs @@ -6,7 +6,8 @@ use dom::bindings::codegen::PrototypeList; use dom::bindings::conversions::get_dom_class; -use dom::bindings::utils::{get_proto_or_iface_array, Prefable}; +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::jsapi::{Class, ClassExtension, ClassSpec, GetGlobalForObjectCrossCompartment}; @@ -209,14 +210,14 @@ impl InterfaceConstructorBehavior { pub unsafe fn create_callback_interface_object( cx: *mut JSContext, receiver: HandleObject, - constants: &'static [Prefable], + constants: &'static [Guard<&'static [ConstantSpec]>], name: &'static [u8], rval: MutableHandleObject) { assert!(!constants.is_empty()); rval.set(JS_NewObject(cx, ptr::null())); assert!(!rval.ptr.is_null()); - for prefable in constants { - if let Some(specs) = prefable.specs() { + for guard in constants { + if let Some(specs) = guard.expose() { define_constants(cx, rval.handle(), specs); } } @@ -229,9 +230,9 @@ pub unsafe fn create_interface_prototype_object( cx: *mut JSContext, proto: HandleObject, class: &'static JSClass, - regular_methods: &'static [Prefable], - regular_properties: &'static [Prefable], - constants: &'static [Prefable], + regular_methods: &'static [Guard<&'static [JSFunctionSpec]>], + regular_properties: &'static [Guard<&'static [JSPropertySpec]>], + constants: &'static [Guard<&'static [ConstantSpec]>], rval: MutableHandleObject) { create_object(cx, proto, class, regular_methods, regular_properties, constants, rval); } @@ -242,9 +243,9 @@ pub unsafe fn create_noncallback_interface_object( receiver: HandleObject, proto: HandleObject, class: &'static NonCallbackInterfaceObjectClass, - static_methods: &'static [Prefable], - static_properties: &'static [Prefable], - constants: &'static [Prefable], + static_methods: &'static [Guard<&'static [JSFunctionSpec]>], + static_properties: &'static [Guard<&'static [JSPropertySpec]>], + constants: &'static [Guard<&'static [ConstantSpec]>], interface_prototype_object: HandleObject, name: &'static [u8], length: u32, @@ -356,40 +357,40 @@ unsafe fn create_object( cx: *mut JSContext, proto: HandleObject, class: &'static JSClass, - methods: &'static [Prefable], - properties: &'static [Prefable], - constants: &'static [Prefable], + methods: &'static [Guard<&'static [JSFunctionSpec]>], + properties: &'static [Guard<&'static [JSPropertySpec]>], + constants: &'static [Guard<&'static [ConstantSpec]>], rval: MutableHandleObject) { rval.set(JS_NewObjectWithUniqueType(cx, class, proto)); assert!(!rval.ptr.is_null()); - define_prefable_methods(cx, rval.handle(), methods); - define_prefable_properties(cx, rval.handle(), properties); - for prefable in constants { - if let Some(specs) = prefable.specs() { + define_guarded_methods(cx, rval.handle(), methods); + define_guarded_properties(cx, rval.handle(), properties); + for guard in constants { + if let Some(specs) = guard.expose() { define_constants(cx, rval.handle(), specs); } } } /// Conditionally define methods on an object. -pub unsafe fn define_prefable_methods( +pub unsafe fn define_guarded_methods( cx: *mut JSContext, obj: HandleObject, - methods: &'static [Prefable]) { - for prefable in methods { - if let Some(specs) = prefable.specs() { + methods: &'static [Guard<&'static [JSFunctionSpec]>]) { + for guard in methods { + if let Some(specs) = guard.expose() { define_methods(cx, obj, specs).unwrap(); } } } /// Conditionally define properties on an object. -pub unsafe fn define_prefable_properties( +pub unsafe fn define_guarded_properties( cx: *mut JSContext, obj: HandleObject, - properties: &'static [Prefable]) { - for prefable in properties { - if let Some(specs) = prefable.specs() { + properties: &'static [Guard<&'static [JSPropertySpec]>]) { + for guard in properties { + if let Some(specs) = guard.expose() { define_properties(cx, obj, specs).unwrap(); } } diff --git a/components/script/dom/bindings/mod.rs b/components/script/dom/bindings/mod.rs index d69720dc538..19797a473d0 100644 --- a/components/script/dom/bindings/mod.rs +++ b/components/script/dom/bindings/mod.rs @@ -133,6 +133,7 @@ pub mod cell; pub mod conversions; pub mod error; pub mod global; +pub mod guard; pub mod inheritance; pub mod interface; pub mod js; diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs index 3ba5838a4fa..cf1f437b1cf 100644 --- a/components/script/dom/bindings/utils.rs +++ b/components/script/dom/bindings/utils.rs @@ -39,7 +39,6 @@ use std::ffi::CString; use std::os::raw::c_void; use std::ptr; use std::slice; -use util::prefs; /// Proxy handler for a WindowProxy. pub struct WindowProxyHandler(pub *const libc::c_void); @@ -550,24 +549,3 @@ unsafe extern "C" fn instance_class_has_proto_at_depth(clasp: *const js::jsapi:: pub const DOM_CALLBACKS: DOMCallbacks = DOMCallbacks { instanceClassMatchesProto: Some(instance_class_has_proto_at_depth), }; - -/// A container around JS member specifications that are conditionally enabled. -pub struct Prefable { - /// If present, the name of the preference used to conditionally enable these specs. - pub pref: Option<&'static str>, - /// The underlying slice of specifications. - pub specs: &'static [T], -} - -impl Prefable { - /// Retrieve the slice represented by this container, unless the condition - /// guarding it is false. - pub fn specs(&self) -> Option<&'static [T]> { - if let Some(pref) = self.pref { - if !prefs::get_pref(pref).as_boolean().unwrap_or(false) { - return None; - } - } - Some(self.specs) - } -} From 25aaf78e98a77bba6aa9c34d32aa28fa9f5907ce Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 20 May 2016 23:05:21 +0200 Subject: [PATCH 06/12] Make define_constants private --- components/script/dom/bindings/interface.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs index 65727ebfa8d..b39175ac901 100644 --- a/components/script/dom/bindings/interface.rs +++ b/components/script/dom/bindings/interface.rs @@ -67,7 +67,10 @@ pub type NonNullJSNative = /// Defines constants on `obj`. /// Fails on JSAPI failure. -pub fn define_constants(cx: *mut JSContext, obj: HandleObject, constants: &'static [ConstantSpec]) { +fn define_constants( + cx: *mut JSContext, + obj: HandleObject, + constants: &'static [ConstantSpec]) { for spec in constants { let value = RootedValue::new(cx, spec.get_value()); unsafe { From f0b53937d4a3103ea8a199fe413fe2ebca5c3849 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 20 May 2016 23:13:03 +0200 Subject: [PATCH 07/12] Remove some 'static lifetimes from bindings::interface --- components/script/dom/bindings/interface.rs | 36 ++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs index b39175ac901..0191b4ef58d 100644 --- a/components/script/dom/bindings/interface.rs +++ b/components/script/dom/bindings/interface.rs @@ -70,7 +70,7 @@ pub type NonNullJSNative = fn define_constants( cx: *mut JSContext, obj: HandleObject, - constants: &'static [ConstantSpec]) { + constants: &[ConstantSpec]) { for spec in constants { let value = RootedValue::new(cx, spec.get_value()); unsafe { @@ -213,8 +213,8 @@ impl InterfaceConstructorBehavior { pub unsafe fn create_callback_interface_object( cx: *mut JSContext, receiver: HandleObject, - constants: &'static [Guard<&'static [ConstantSpec]>], - name: &'static [u8], + constants: &[Guard<&[ConstantSpec]>], + name: &[u8], rval: MutableHandleObject) { assert!(!constants.is_empty()); rval.set(JS_NewObject(cx, ptr::null())); @@ -233,9 +233,9 @@ pub unsafe fn create_interface_prototype_object( cx: *mut JSContext, proto: HandleObject, class: &'static JSClass, - regular_methods: &'static [Guard<&'static [JSFunctionSpec]>], - regular_properties: &'static [Guard<&'static [JSPropertySpec]>], - constants: &'static [Guard<&'static [ConstantSpec]>], + regular_methods: &[Guard<&'static [JSFunctionSpec]>], + regular_properties: &[Guard<&'static [JSPropertySpec]>], + constants: &[Guard<&[ConstantSpec]>], rval: MutableHandleObject) { create_object(cx, proto, class, regular_methods, regular_properties, constants, rval); } @@ -246,11 +246,11 @@ pub unsafe fn create_noncallback_interface_object( receiver: HandleObject, proto: HandleObject, class: &'static NonCallbackInterfaceObjectClass, - static_methods: &'static [Guard<&'static [JSFunctionSpec]>], - static_properties: &'static [Guard<&'static [JSPropertySpec]>], - constants: &'static [Guard<&'static [ConstantSpec]>], + static_methods: &[Guard<&'static [JSFunctionSpec]>], + static_properties: &[Guard<&'static [JSPropertySpec]>], + constants: &[Guard<&[ConstantSpec]>], interface_prototype_object: HandleObject, - name: &'static [u8], + name: &[u8], length: u32, rval: MutableHandleObject) { create_object(cx, @@ -270,7 +270,7 @@ pub unsafe fn create_noncallback_interface_object( pub unsafe fn create_named_constructors( cx: *mut JSContext, receiver: HandleObject, - named_constructors: &[(NonNullJSNative, &'static [u8], u32)], + named_constructors: &[(NonNullJSNative, &[u8], u32)], interface_prototype_object: HandleObject) { let mut constructor = RootedObject::new(cx, ptr::null_mut()); @@ -360,9 +360,9 @@ unsafe fn create_object( cx: *mut JSContext, proto: HandleObject, class: &'static JSClass, - methods: &'static [Guard<&'static [JSFunctionSpec]>], - properties: &'static [Guard<&'static [JSPropertySpec]>], - constants: &'static [Guard<&'static [ConstantSpec]>], + methods: &[Guard<&'static [JSFunctionSpec]>], + properties: &[Guard<&'static [JSPropertySpec]>], + constants: &[Guard<&[ConstantSpec]>], rval: MutableHandleObject) { rval.set(JS_NewObjectWithUniqueType(cx, class, proto)); assert!(!rval.ptr.is_null()); @@ -379,7 +379,7 @@ unsafe fn create_object( pub unsafe fn define_guarded_methods( cx: *mut JSContext, obj: HandleObject, - methods: &'static [Guard<&'static [JSFunctionSpec]>]) { + methods: &[Guard<&'static [JSFunctionSpec]>]) { for guard in methods { if let Some(specs) = guard.expose() { define_methods(cx, obj, specs).unwrap(); @@ -391,7 +391,7 @@ pub unsafe fn define_guarded_methods( pub unsafe fn define_guarded_properties( cx: *mut JSContext, obj: HandleObject, - properties: &'static [Guard<&'static [JSPropertySpec]>]) { + properties: &[Guard<&'static [JSPropertySpec]>]) { for guard in properties { if let Some(specs) = guard.expose() { define_properties(cx, obj, specs).unwrap(); @@ -399,7 +399,7 @@ pub unsafe fn define_guarded_properties( } } -unsafe fn define_name(cx: *mut JSContext, obj: HandleObject, name: &'static [u8]) { +unsafe fn define_name(cx: *mut JSContext, obj: HandleObject, name: &[u8]) { assert!(*name.last().unwrap() == b'\0'); let name = RootedString::new( cx, JS_AtomizeAndPinString(cx, name.as_ptr() as *const libc::c_char)); @@ -424,7 +424,7 @@ unsafe fn define_length(cx: *mut JSContext, obj: HandleObject, length: u32) { unsafe fn define_on_global_object( cx: *mut JSContext, receiver: HandleObject, - name: &'static [u8], + name: &[u8], obj: HandleObject) { assert!(*name.last().unwrap() == b'\0'); assert!(JS_DefineProperty1(cx, From 0d04acd50f3871d6a16e24516df44ef0cff3b829 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 21 May 2016 00:01:05 +0200 Subject: [PATCH 08/12] Rename receiver to global in bindings::interface --- components/script/dom/bindings/interface.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs index 0191b4ef58d..371e70372ac 100644 --- a/components/script/dom/bindings/interface.rs +++ b/components/script/dom/bindings/interface.rs @@ -212,7 +212,7 @@ impl InterfaceConstructorBehavior { /// Create and define the interface object of a callback interface. pub unsafe fn create_callback_interface_object( cx: *mut JSContext, - receiver: HandleObject, + global: HandleObject, constants: &[Guard<&[ConstantSpec]>], name: &[u8], rval: MutableHandleObject) { @@ -225,7 +225,7 @@ pub unsafe fn create_callback_interface_object( } } define_name(cx, rval.handle(), name); - define_on_global_object(cx, receiver, name, rval.handle()); + define_on_global_object(cx, global, name, rval.handle()); } /// Create the interface prototype object of a non-callback interface. @@ -243,7 +243,7 @@ pub unsafe fn create_interface_prototype_object( /// Create and define the interface object of a non-callback interface. pub unsafe fn create_noncallback_interface_object( cx: *mut JSContext, - receiver: HandleObject, + global: HandleObject, proto: HandleObject, class: &'static NonCallbackInterfaceObjectClass, static_methods: &[Guard<&'static [JSFunctionSpec]>], @@ -263,13 +263,13 @@ pub unsafe fn create_noncallback_interface_object( assert!(JS_LinkConstructorAndPrototype(cx, rval.handle(), interface_prototype_object)); define_name(cx, rval.handle(), name); define_length(cx, rval.handle(), length); - define_on_global_object(cx, receiver, name, rval.handle()); + define_on_global_object(cx, global, name, rval.handle()); } /// Create and define the named constructors of a non-callback interface. pub unsafe fn create_named_constructors( cx: *mut JSContext, - receiver: HandleObject, + global: HandleObject, named_constructors: &[(NonNullJSNative, &[u8], u32)], interface_prototype_object: HandleObject) { let mut constructor = RootedObject::new(cx, ptr::null_mut()); @@ -294,7 +294,7 @@ pub unsafe fn create_named_constructors( None, None)); - define_on_global_object(cx, receiver, name, constructor.handle()); + define_on_global_object(cx, global, name, constructor.handle()); } } @@ -423,12 +423,12 @@ unsafe fn define_length(cx: *mut JSContext, obj: HandleObject, length: u32) { unsafe fn define_on_global_object( cx: *mut JSContext, - receiver: HandleObject, + global: HandleObject, name: &[u8], obj: HandleObject) { assert!(*name.last().unwrap() == b'\0'); assert!(JS_DefineProperty1(cx, - receiver, + global, name.as_ptr() as *const libc::c_char, obj, JSPROP_RESOLVING, From e179cb02fff68d12c1461dd655a991088c647d68 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 21 May 2016 00:09:06 +0200 Subject: [PATCH 09/12] Implement [Func] --- .../dom/bindings/codegen/CodegenRust.py | 3 +++ components/script/dom/bindings/guard.rs | 12 +++++++--- components/script/dom/bindings/interface.rs | 8 +++---- components/script/dom/testbinding.rs | 16 +++++++++++++- .../script/dom/webidls/TestBinding.webidl | 22 +++++++++++++++++++ .../mozilla/interface_member_exposed.html | 5 +++++ 6 files changed, 58 insertions(+), 8 deletions(-) diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index f418a1ba569..73d9f7f3ed0 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1334,8 +1334,11 @@ def MemberCondition(pref, func): """ assert pref is None or isinstance(pref, str) assert func is None or isinstance(func, str) + assert func is None or pref is None if pref: return 'Condition::Pref("%s")' % pref + if func: + return 'Condition::Func(%s)' % func return "Condition::Satisfied" diff --git a/components/script/dom/bindings/guard.rs b/components/script/dom/bindings/guard.rs index 15b7c418a31..40faebbd4f2 100644 --- a/components/script/dom/bindings/guard.rs +++ b/components/script/dom/bindings/guard.rs @@ -4,6 +4,7 @@ //! Machinery to conditionally expose things. +use js::jsapi::{HandleObject, JSContext}; use util::prefs::get_pref; /// A container with a condition. @@ -22,8 +23,10 @@ impl Guard { } /// Expose the value if the condition is satisfied. - pub fn expose(&self) -> Option { - if self.condition.is_satisfied() { + /// + /// The passed handle is the object on which the value may be exposed. + pub unsafe fn expose(&self, cx: *mut JSContext, obj: HandleObject) -> Option { + if self.condition.is_satisfied(cx, obj) { Some(self.value) } else { None @@ -33,6 +36,8 @@ impl Guard { /// A condition to expose things. pub enum Condition { + /// The condition is satisfied if the function returns true. + Func(unsafe fn(*mut JSContext, HandleObject) -> bool), /// The condition is satisfied if the preference is set. Pref(&'static str), /// The condition is always satisfied. @@ -40,9 +45,10 @@ pub enum Condition { } impl Condition { - fn is_satisfied(&self) -> bool { + unsafe fn is_satisfied(&self, cx: *mut JSContext, obj: HandleObject) -> bool { match *self { Condition::Pref(name) => get_pref(name).as_boolean().unwrap_or(false), + Condition::Func(f) => f(cx, obj), Condition::Satisfied => true, } } diff --git a/components/script/dom/bindings/interface.rs b/components/script/dom/bindings/interface.rs index 371e70372ac..590e57ba8e0 100644 --- a/components/script/dom/bindings/interface.rs +++ b/components/script/dom/bindings/interface.rs @@ -220,7 +220,7 @@ pub unsafe fn create_callback_interface_object( rval.set(JS_NewObject(cx, ptr::null())); assert!(!rval.ptr.is_null()); for guard in constants { - if let Some(specs) = guard.expose() { + if let Some(specs) = guard.expose(cx, rval.handle()) { define_constants(cx, rval.handle(), specs); } } @@ -369,7 +369,7 @@ unsafe fn create_object( define_guarded_methods(cx, rval.handle(), methods); define_guarded_properties(cx, rval.handle(), properties); for guard in constants { - if let Some(specs) = guard.expose() { + if let Some(specs) = guard.expose(cx, rval.handle()) { define_constants(cx, rval.handle(), specs); } } @@ -381,7 +381,7 @@ pub unsafe fn define_guarded_methods( obj: HandleObject, methods: &[Guard<&'static [JSFunctionSpec]>]) { for guard in methods { - if let Some(specs) = guard.expose() { + if let Some(specs) = guard.expose(cx, obj) { define_methods(cx, obj, specs).unwrap(); } } @@ -393,7 +393,7 @@ pub unsafe fn define_guarded_properties( obj: HandleObject, properties: &[Guard<&'static [JSPropertySpec]>]) { for guard in properties { - if let Some(specs) = guard.expose() { + if let Some(specs) = guard.expose(cx, obj) { define_properties(cx, obj, specs).unwrap(); } } diff --git a/components/script/dom/testbinding.rs b/components/script/dom/testbinding.rs index faf53596ecc..5ff0e0bd272 100644 --- a/components/script/dom/testbinding.rs +++ b/components/script/dom/testbinding.rs @@ -24,7 +24,7 @@ use dom::bindings::str::{ByteString, DOMString, USVString}; use dom::bindings::weakref::MutableWeakRef; use dom::blob::{Blob, DataSlice}; use dom::url::URL; -use js::jsapi::{HandleValue, JSContext, JSObject}; +use js::jsapi::{HandleObject, HandleValue, JSContext, JSObject}; use js::jsval::{JSVal, NullValue}; use std::borrow::ToOwned; use std::ptr; @@ -567,6 +567,10 @@ impl TestBindingMethods for TestBinding { fn PrefControlledAttributeEnabled(&self) -> bool { false } fn PrefControlledMethodDisabled(&self) {} fn PrefControlledMethodEnabled(&self) {} + fn FuncControlledAttributeDisabled(&self) -> bool { false } + fn FuncControlledAttributeEnabled(&self) -> bool { false } + fn FuncControlledMethodDisabled(&self) {} + fn FuncControlledMethodEnabled(&self) {} } impl TestBinding { @@ -577,4 +581,14 @@ impl TestBinding { pub fn PrefControlledStaticAttributeEnabled(_: GlobalRef) -> bool { false } pub fn PrefControlledStaticMethodDisabled(_: GlobalRef) {} pub fn PrefControlledStaticMethodEnabled(_: GlobalRef) {} + pub fn FuncControlledStaticAttributeDisabled(_: GlobalRef) -> bool { false } + pub fn FuncControlledStaticAttributeEnabled(_: GlobalRef) -> bool { false } + pub fn FuncControlledStaticMethodDisabled(_: GlobalRef) {} + pub fn FuncControlledStaticMethodEnabled(_: GlobalRef) {} +} + +#[allow(unsafe_code)] +impl TestBinding { + pub unsafe fn condition_satisfied(_: *mut JSContext, _: HandleObject) -> bool { true } + pub unsafe fn condition_unsatisfied(_: *mut JSContext, _: HandleObject) -> bool { false } } diff --git a/components/script/dom/webidls/TestBinding.webidl b/components/script/dom/webidls/TestBinding.webidl index 6706ccfdaa9..cdfb9fd18ae 100644 --- a/components/script/dom/webidls/TestBinding.webidl +++ b/components/script/dom/webidls/TestBinding.webidl @@ -433,4 +433,26 @@ interface TestBinding { static void prefControlledStaticMethodEnabled(); [Pref="dom.testbinding.prefcontrolled2.enabled"] const unsigned short prefControlledConstEnabled = 0; + + [Func="TestBinding::condition_unsatisfied"] + readonly attribute boolean funcControlledAttributeDisabled; + [Func="TestBinding::condition_unsatisfied"] + static readonly attribute boolean funcControlledStaticAttributeDisabled; + [Func="TestBinding::condition_unsatisfied"] + void funcControlledMethodDisabled(); + [Func="TestBinding::condition_unsatisfied"] + static void funcControlledStaticMethodDisabled(); + [Func="TestBinding::condition_unsatisfied"] + const unsigned short funcControlledConstDisabled = 0; + + [Func="TestBinding::condition_satisfied"] + readonly attribute boolean funcControlledAttributeEnabled; + [Func="TestBinding::condition_satisfied"] + static readonly attribute boolean funcControlledStaticAttributeEnabled; + [Func="TestBinding::condition_satisfied"] + void funcControlledMethodEnabled(); + [Func="TestBinding::condition_satisfied"] + static void funcControlledStaticMethodEnabled(); + [Func="TestBinding::condition_satisfied"] + const unsigned short funcControlledConstEnabled = 0; }; diff --git a/tests/wpt/mozilla/tests/mozilla/interface_member_exposed.html b/tests/wpt/mozilla/tests/mozilla/interface_member_exposed.html index d455e8e5586..dd637cf92a8 100644 --- a/tests/wpt/mozilla/tests/mozilla/interface_member_exposed.html +++ b/tests/wpt/mozilla/tests/mozilla/interface_member_exposed.html @@ -19,10 +19,15 @@ function test_member(name, enabled, target) { } var members = [ + 'funcControlledAttribute', + 'funcControlledMethod', 'prefControlledAttribute', 'prefControlledMethod' ]; var staticMembers = [ + 'funcControlledStaticAttribute', + 'funcControlledStaticMethod', + 'funcControlledConst', 'prefControlledStaticAttribute', 'prefControlledStaticMethod', 'prefControlledConst' From 34858fd0c94d470f69f4ed206f7b79dca2dbfb2a Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 21 May 2016 16:30:12 +0200 Subject: [PATCH 10/12] Clean up the functions to retrieve a global root from JS objects --- components/script/dom/bindings/callback.rs | 2 +- components/script/dom/bindings/global.rs | 49 ++++++++++------------ 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/components/script/dom/bindings/callback.rs b/components/script/dom/bindings/callback.rs index e5168e57768..c9424adf5b2 100644 --- a/components/script/dom/bindings/callback.rs +++ b/components/script/dom/bindings/callback.rs @@ -164,7 +164,7 @@ impl CallSetup { /// Performs the setup needed to make a call. #[allow(unrooted_must_root)] pub fn new(callback: &T, handling: ExceptionHandling) -> CallSetup { - let global = global_root_from_object(callback.callback()); + let global = unsafe { global_root_from_object(callback.callback()) }; let cx = global.r().get_cx(); let exception_compartment = unsafe { diff --git a/components/script/dom/bindings/global.rs b/components/script/dom/bindings/global.rs index ff36817b660..036c53e67b4 100644 --- a/components/script/dom/bindings/global.rs +++ b/components/script/dom/bindings/global.rs @@ -302,44 +302,39 @@ impl GlobalRoot { /// Returns the global object of the realm that the given DOM object's reflector was created in. pub fn global_root_from_reflector(reflector: &T) -> GlobalRoot { - global_root_from_object(*reflector.reflector().get_jsobject()) + unsafe { global_root_from_object(*reflector.reflector().get_jsobject()) } } /// Returns the Rust global object from a JS global object. #[allow(unrooted_must_root)] -pub fn global_root_from_global(global: *mut JSObject) -> GlobalRoot { - unsafe { - let clasp = JS_GetClass(global); - assert!(((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)) != 0); - match root_from_object(global) { - Ok(window) => return GlobalRoot::Window(window), - Err(_) => (), - } - - match root_from_object(global) { - Ok(worker) => return GlobalRoot::Worker(worker), - Err(_) => (), - } - - panic!("found DOM global that doesn't unwrap to Window or WorkerGlobalScope") +unsafe fn global_root_from_global(global: *mut JSObject) -> GlobalRoot { + assert!(!global.is_null()); + let clasp = JS_GetClass(global); + assert!(((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)) != 0); + match root_from_object(global) { + Ok(window) => return GlobalRoot::Window(window), + Err(_) => (), } + + match root_from_object(global) { + Ok(worker) => return GlobalRoot::Worker(worker), + Err(_) => (), + } + + panic!("found DOM global that doesn't unwrap to Window or WorkerGlobalScope") } /// Returns the global object of the realm that the given JS object was created in. #[allow(unrooted_must_root)] -pub fn global_root_from_object(obj: *mut JSObject) -> GlobalRoot { - unsafe { - let global = GetGlobalForObjectCrossCompartment(obj); - global_root_from_global(global) - } +pub unsafe fn global_root_from_object(obj: *mut JSObject) -> GlobalRoot { + assert!(!obj.is_null()); + let global = GetGlobalForObjectCrossCompartment(obj); + global_root_from_global(global) } /// Returns the global object for the given JSContext #[allow(unrooted_must_root)] -pub fn global_root_from_context(cx: *mut JSContext) -> GlobalRoot { - unsafe { - let global = CurrentGlobalOrNull(cx); - assert!(!global.is_null()); - global_root_from_global(global) - } +pub unsafe fn global_root_from_context(cx: *mut JSContext) -> GlobalRoot { + let global = CurrentGlobalOrNull(cx); + global_root_from_global(global) } From 34dfc28e989a8583aa925cc252f635693bb8bfbb Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Tue, 24 May 2016 00:10:01 +0200 Subject: [PATCH 11/12] Move mozbrowser_enabled to util::prefs --- components/constellation/constellation.rs | 15 +++++++-------- components/constellation/pipeline.rs | 2 +- components/script/dom/document.rs | 5 +++-- components/script/dom/htmliframeelement.rs | 6 +----- components/script/dom/xmlhttprequest.rs | 4 ++-- components/util/prefs.rs | 4 ++++ 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index c6e7c16052f..b80bf2fd61f 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -69,8 +69,9 @@ use style_traits::viewport::ViewportConstraints; use timer_scheduler::TimerScheduler; use url::Url; use util::geometry::PagePx; +use util::opts; +use util::prefs::mozbrowser_enabled; use util::thread::spawn_named; -use util::{opts, prefs}; use webrender_traits; #[derive(Debug, PartialEq)] @@ -1129,7 +1130,7 @@ impl Constellation } fn handle_alert(&mut self, pipeline_id: PipelineId, message: String, sender: IpcSender) { - let display_alert_dialog = if prefs::get_pref("dom.mozbrowser.enabled").as_boolean().unwrap_or(false) { + let display_alert_dialog = if mozbrowser_enabled() { let parent_pipeline_info = self.pipelines.get(&pipeline_id).and_then(|source| source.parent_info); if let Some(_) = parent_pipeline_info { let root_pipeline_id = self.root_frame_id @@ -1421,7 +1422,7 @@ impl Constellation containing_pipeline_id: PipelineId, subpage_id: SubpageId, event: MozBrowserEvent) { - assert!(prefs::get_pref("dom.mozbrowser.enabled").as_boolean().unwrap_or(false)); + assert!(mozbrowser_enabled()); // Find the script channel for the given parent pipeline, // and pass the event to that script thread. @@ -1993,9 +1994,7 @@ impl Constellation if let Some(pipeline_id) = rng.choose(&*pipeline_ids) { if let Some(pipeline) = self.pipelines.get(pipeline_id) { // Don't kill the mozbrowser pipeline - if prefs::get_pref("dom.mozbrowser.enabled").as_boolean().unwrap_or(false) && - pipeline.parent_info.is_none() - { + if mozbrowser_enabled() && pipeline.parent_info.is_none() { info!("Not closing mozbrowser pipeline {}.", pipeline_id); } else { // Note that we deliberately do not do any of the tidying up @@ -2088,7 +2087,7 @@ impl Constellation // https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowserlocationchange // Note that this is a no-op if the pipeline is not an immediate child iframe of the root fn trigger_mozbrowserlocationchange(&self, pipeline_id: PipelineId) { - if !prefs::get_pref("dom.mozbrowser.enabled").as_boolean().unwrap_or(false) { return; } + if !mozbrowser_enabled() { return; } let event_info = self.pipelines.get(&pipeline_id).and_then(|pipeline| { pipeline.parent_info.map(|(containing_pipeline_id, subpage_id)| { @@ -2114,7 +2113,7 @@ impl Constellation // https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowsererror // Note that this does not require the pipeline to be an immediate child of the root fn trigger_mozbrowsererror(&self, pipeline_id: PipelineId, reason: String, backtrace: String) { - if !prefs::get_pref("dom.mozbrowser.enabled").as_boolean().unwrap_or(false) { return; } + if !mozbrowser_enabled() { return; } let ancestor_info = self.get_root_pipeline_and_containing_parent(&pipeline_id); diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index b0a321cd5f9..d50b45b9392 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -356,7 +356,7 @@ impl Pipeline { pub fn trigger_mozbrowser_event(&self, subpage_id: SubpageId, event: MozBrowserEvent) { - assert!(prefs::get_pref("dom.mozbrowser.enabled").as_boolean().unwrap_or(false)); + assert!(prefs::mozbrowser_enabled()); let event = ConstellationControlMsg::MozBrowserEvent(self.id, subpage_id, diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 89755564bb6..d65efd7acd8 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -56,7 +56,7 @@ use dom::htmlembedelement::HTMLEmbedElement; use dom::htmlformelement::HTMLFormElement; use dom::htmlheadelement::HTMLHeadElement; use dom::htmlhtmlelement::HTMLHtmlElement; -use dom::htmliframeelement::{self, HTMLIFrameElement}; +use dom::htmliframeelement::HTMLIFrameElement; use dom::htmlimageelement::HTMLImageElement; use dom::htmllinkelement::HTMLLinkElement; use dom::htmlmetaelement::HTMLMetaElement; @@ -127,6 +127,7 @@ use task_source::dom_manipulation::DOMManipulationTask; use time; use url::Url; use url::percent_encoding::percent_decode; +use util::prefs::mozbrowser_enabled; use util::str::{split_html_space_chars, str_join}; #[derive(JSTraceable, PartialEq, HeapSizeOf)] @@ -1261,7 +1262,7 @@ impl Document { } pub fn trigger_mozbrowser_event(&self, event: MozBrowserEvent) { - if htmliframeelement::mozbrowser_enabled() { + if mozbrowser_enabled() { if let Some((containing_pipeline_id, subpage_id)) = self.window.parent_info() { let event = ConstellationMsg::MozBrowserEvent(containing_pipeline_id, subpage_id, diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index 8cec0aa6659..a2d6d4bac5a 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -42,13 +42,9 @@ use std::cell::Cell; use string_cache::Atom; use style::context::ReflowGoal; use url::Url; -use util::prefs; +use util::prefs::mozbrowser_enabled; use util::str::LengthOrPercentageOrAuto; -pub fn mozbrowser_enabled() -> bool { - prefs::get_pref("dom.mozbrowser.enabled").as_boolean().unwrap_or(false) -} - #[derive(HeapSizeOf)] enum SandboxAllowance { AllowNothing = 0x00, diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 27fe4a783f0..e1ce424a1c5 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -62,7 +62,7 @@ use string_cache::Atom; use time; use timers::{OneshotTimerCallback, OneshotTimerHandle}; use url::{Url, Position}; -use util::prefs; +use util::prefs::mozbrowser_enabled; #[derive(JSTraceable, PartialEq, Copy, Clone, HeapSizeOf)] enum XMLHttpRequestState { @@ -884,7 +884,7 @@ impl XMLHttpRequest { // story. See https://github.com/servo/servo/issues/9582 if let GlobalRoot::Window(win) = self.global() { let is_root_pipeline = win.parent_info().is_none(); - let is_mozbrowser_enabled = prefs::get_pref("dom.mozbrowser.enabled").as_boolean().unwrap_or(false); + let is_mozbrowser_enabled = mozbrowser_enabled(); is_root_pipeline && is_mozbrowser_enabled } else { false diff --git a/components/util/prefs.rs b/components/util/prefs.rs index 3d4492dd8f7..83363f93c35 100644 --- a/components/util/prefs.rs +++ b/components/util/prefs.rs @@ -243,3 +243,7 @@ pub fn reset_all_prefs() { reset_pref(name); } } + +pub fn mozbrowser_enabled() -> bool { + get_pref("dom.mozbrowser.enabled").as_boolean().unwrap_or(false) +} From 694deabcd56120ea81b4c88e3b806c3c230b83f9 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Tue, 24 May 2016 00:56:48 +0200 Subject: [PATCH 12/12] Use [Func] on HTMLIFrameElement.mozbrowser --- components/script/dom/htmliframeelement.rs | 23 ++++--------------- .../dom/webidls/HTMLIFrameElement.webidl | 4 ++-- components/script/dom/window.rs | 21 +++++++++++++---- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index a2d6d4bac5a..d9d6f624f16 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -433,29 +433,16 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement { // Experimental mozbrowser implementation is based on the webidl // present in the gecko source tree, and the documentation here: // https://developer.mozilla.org/en-US/docs/Web/API/Using_the_Browser_API - - // TODO(gw): Use experimental codegen when it is available to avoid - // exposing these APIs. See https://github.com/servo/servo/issues/5264. - // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-mozbrowser fn Mozbrowser(&self) -> bool { - // We don't want to allow mozbrowser iframes within iframes - let is_root_pipeline = window_from_node(self).parent_info().is_none(); - if mozbrowser_enabled() && is_root_pipeline { - let element = self.upcast::(); - element.has_attribute(&atom!("mozbrowser")) - } else { - false - } + let element = self.upcast::(); + element.has_attribute(&atom!("mozbrowser")) } // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-mozbrowser - fn SetMozbrowser(&self, value: bool) -> ErrorResult { - if mozbrowser_enabled() { - let element = self.upcast::(); - element.set_bool_attribute(&atom!("mozbrowser"), value); - } - Ok(()) + fn SetMozbrowser(&self, value: bool) { + let element = self.upcast::(); + element.set_bool_attribute(&atom!("mozbrowser"), value); } // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/goBack diff --git a/components/script/dom/webidls/HTMLIFrameElement.webidl b/components/script/dom/webidls/HTMLIFrameElement.webidl index 20bb563e908..0d78b56fb98 100644 --- a/components/script/dom/webidls/HTMLIFrameElement.webidl +++ b/components/script/dom/webidls/HTMLIFrameElement.webidl @@ -32,8 +32,8 @@ partial interface HTMLIFrameElement { }; partial interface HTMLIFrameElement { - [ChromeOnly,SetterThrows,Pref="dom.mozbrowser.enabled"] - attribute boolean mozbrowser; + [Func="Window::global_is_mozbrowser"] + attribute boolean mozbrowser; }; HTMLIFrameElement implements BrowserElement; diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 63a0ca2a36e..a46cac12296 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -14,7 +14,7 @@ use dom::bindings::codegen::Bindings::FunctionBinding::Function; use dom::bindings::codegen::Bindings::WindowBinding::{ScrollBehavior, ScrollToOptions}; use dom::bindings::codegen::Bindings::WindowBinding::{self, FrameRequestCallback, WindowMethods}; use dom::bindings::error::{Error, Fallible, report_pending_exception}; -use dom::bindings::global::GlobalRef; +use dom::bindings::global::{GlobalRef, global_root_from_object}; use dom::bindings::inheritance::Castable; use dom::bindings::js::{JS, MutNullableHeap, Root}; use dom::bindings::num::Finite; @@ -37,9 +37,8 @@ use dom::storage::Storage; use euclid::{Point2D, Rect, Size2D}; use gfx_traits::LayerId; use ipc_channel::ipc::{self, IpcSender}; -use js::jsapi::{Evaluate2, MutableHandleValue}; -use js::jsapi::{HandleValue, JSContext}; -use js::jsapi::{JSAutoCompartment, JS_GC, JS_GetRuntime, SetWindowProxy}; +use js::jsapi::{Evaluate2, HandleObject, HandleValue, JSAutoCompartment, JSContext}; +use js::jsapi::{JS_GetRuntime, JS_GC, MutableHandleValue, SetWindowProxy}; use js::rust::CompileOptionsWrapper; use js::rust::Runtime; use layout_interface::{ContentBoxResponse, ContentBoxesResponse, ResolvedStyleResponse, ScriptReflow}; @@ -93,6 +92,7 @@ use timers::{IsInterval, OneshotTimerCallback, OneshotTimerHandle, OneshotTimers use tinyfiledialogs::{self, MessageBoxIcon}; use url::Url; use util::geometry::{self, MAX_RECT}; +use util::prefs::mozbrowser_enabled; use util::str::HTML_SPACE_CHARACTERS; use util::{breakpoint, opts}; use webdriver_handlers::jsval_to_webdriver; @@ -1432,6 +1432,19 @@ impl Window { context.active_window() }) } + + /// Returns whether mozbrowser is enabled and `obj` has been created + /// in a top-level `Window` global. + #[allow(unsafe_code)] + pub unsafe fn global_is_mozbrowser(_: *mut JSContext, obj: HandleObject) -> bool { + if !mozbrowser_enabled() { + return false; + } + match global_root_from_object(obj.get()).r() { + GlobalRef::Window(window) => window.parent_info().is_none(), + _ => false, + } + } } impl Window {