Auto merge of #11308 - nox:guarded, r=jdm

Implement [Func]

First part of #11292, this just includes support of `[Func]`.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/11308)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-05-27 04:45:06 -05:00
commit 073c5e3b6b
18 changed files with 253 additions and 211 deletions

View file

@ -69,8 +69,9 @@ use style_traits::viewport::ViewportConstraints;
use timer_scheduler::TimerScheduler; use timer_scheduler::TimerScheduler;
use url::Url; use url::Url;
use util::geometry::PagePx; use util::geometry::PagePx;
use util::opts;
use util::prefs::mozbrowser_enabled;
use util::thread::spawn_named; use util::thread::spawn_named;
use util::{opts, prefs};
use webrender_traits; use webrender_traits;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -1129,7 +1130,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
} }
fn handle_alert(&mut self, pipeline_id: PipelineId, message: String, sender: IpcSender<bool>) { fn handle_alert(&mut self, pipeline_id: PipelineId, message: String, sender: IpcSender<bool>) {
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); let parent_pipeline_info = self.pipelines.get(&pipeline_id).and_then(|source| source.parent_info);
if let Some(_) = parent_pipeline_info { if let Some(_) = parent_pipeline_info {
let root_pipeline_id = self.root_frame_id let root_pipeline_id = self.root_frame_id
@ -1421,7 +1422,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
containing_pipeline_id: PipelineId, containing_pipeline_id: PipelineId,
subpage_id: SubpageId, subpage_id: SubpageId,
event: MozBrowserEvent) { 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, // Find the script channel for the given parent pipeline,
// and pass the event to that script thread. // and pass the event to that script thread.
@ -1999,9 +2000,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
if let Some(pipeline_id) = rng.choose(&*pipeline_ids) { if let Some(pipeline_id) = rng.choose(&*pipeline_ids) {
if let Some(pipeline) = self.pipelines.get(pipeline_id) { if let Some(pipeline) = self.pipelines.get(pipeline_id) {
// Don't kill the mozbrowser pipeline // Don't kill the mozbrowser pipeline
if prefs::get_pref("dom.mozbrowser.enabled").as_boolean().unwrap_or(false) && if mozbrowser_enabled() && pipeline.parent_info.is_none() {
pipeline.parent_info.is_none()
{
info!("Not closing mozbrowser pipeline {}.", pipeline_id); info!("Not closing mozbrowser pipeline {}.", pipeline_id);
} else { } else {
// Note that we deliberately do not do any of the tidying up // Note that we deliberately do not do any of the tidying up
@ -2089,7 +2088,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowserlocationchange // https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowserlocationchange
// Note that this is a no-op if the pipeline is not a mozbrowser iframe // Note that this is a no-op if the pipeline is not a mozbrowser iframe
fn trigger_mozbrowserlocationchange(&self, pipeline_id: PipelineId) { 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| { let event_info = self.pipelines.get(&pipeline_id).and_then(|pipeline| {
pipeline.parent_info.map(|(containing_pipeline_id, subpage_id, frame_type)| { pipeline.parent_info.map(|(containing_pipeline_id, subpage_id, frame_type)| {
@ -2115,7 +2114,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowsererror // 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 // 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) { 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_mozbrowser_ancestor_info(pipeline_id); let ancestor_info = self.get_mozbrowser_ancestor_info(pipeline_id);

View file

@ -356,7 +356,7 @@ impl Pipeline {
pub fn trigger_mozbrowser_event(&self, pub fn trigger_mozbrowser_event(&self,
subpage_id: SubpageId, subpage_id: SubpageId,
event: MozBrowserEvent) { event: MozBrowserEvent) {
assert!(prefs::get_pref("dom.mozbrowser.enabled").as_boolean().unwrap_or(false)); assert!(prefs::mozbrowser_enabled());
let event = ConstellationControlMsg::MozBrowserEvent(self.id, let event = ConstellationControlMsg::MozBrowserEvent(self.id,
subpage_id, subpage_id,

View file

@ -164,7 +164,7 @@ impl CallSetup {
/// Performs the setup needed to make a call. /// Performs the setup needed to make a call.
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new<T: CallbackContainer>(callback: &T, handling: ExceptionHandling) -> CallSetup { pub fn new<T: CallbackContainer>(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 cx = global.r().get_cx();
let exception_compartment = unsafe { let exception_compartment = unsafe {

View file

@ -5,6 +5,7 @@
# Common codegen classes. # Common codegen classes.
from collections import defaultdict from collections import defaultdict
from itertools import groupby
import operator import operator
import re import re
@ -1322,31 +1323,23 @@ def getRetvalDeclarationForType(returnType, descriptorProvider):
returnType) returnType)
class MemberCondition: def MemberCondition(pref, func):
""" """
An object representing the condition for a member to actually be A string representing the condition for a member to actually be exposed.
exposed. Any of the arguments can be None. If not Any of the arguments can be None. If not None, they should have the
None, they should have the following types: following types:
pref: The name of the preference. pref: The name of the preference.
func: The name of the function. func: The name of the function.
""" """
def __init__(self, pref=None, func=None): assert pref is None or isinstance(pref, str)
assert pref is None or isinstance(pref, str) assert func is None or isinstance(func, str)
assert func is None or isinstance(func, str) assert func is None or pref is None
self.pref = pref if pref:
return 'Condition::Pref("%s")' % pref
def toFuncPtr(val): if func:
if val is None: return 'Condition::Func(%s)' % func
return "None" return "Condition::Satisfied"
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)
class PropertyDefiner: class PropertyDefiner:
@ -1390,8 +1383,8 @@ class PropertyDefiner:
PropertyDefiner.getStringAttr(interfaceMember, PropertyDefiner.getStringAttr(interfaceMember,
"Func")) "Func"))
def generatePrefableArray(self, array, name, specTemplate, specTerminator, def generateGuardedArray(self, array, name, specTemplate, specTerminator,
specType, getCondition, getDataTuple): specType, getCondition, getDataTuple):
""" """
This method generates our various arrays. This method generates our various arrays.
@ -1417,43 +1410,23 @@ class PropertyDefiner:
# members while still allowing us to define all the members in the smallest # members while still allowing us to define all the members in the smallest
# number of JSAPI calls. # number of JSAPI calls.
assert len(array) != 0 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 = [] specs = []
currentSpecs = []
prefableSpecs = [] prefableSpecs = []
prefableTemplate = ' Guard::new(%s, %s[%d])'
prefableTemplate = ' Prefable { pref: %s, specs: %s[%d], terminator: %s }' for cond, members in groupby(array, lambda m: getCondition(m, self.descriptor)):
currentSpecs = [specTemplate % getDataTuple(m) for m in members]
def switchToCondition(props, condition): if specTerminator:
prefableSpecs.append(prefableTemplate % currentSpecs.append(specTerminator)
('Some("%s")' % condition.pref if condition.pref else 'None',
name + "_specs",
len(specs),
'true' if specTerminator else 'false'))
specs.append("&[\n" + ",\n".join(currentSpecs) + "]\n") specs.append("&[\n" + ",\n".join(currentSpecs) + "]\n")
del currentSpecs[:] prefableSpecs.append(
prefableTemplate % (cond, name + "_specs", len(specs) - 1))
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)
specsArray = ("const %s_specs: &'static [&'static[%s]] = &[\n" + specsArray = ("const %s_specs: &'static [&'static[%s]] = &[\n" +
",\n".join(specs) + "\n" + ",\n".join(specs) + "\n" +
"];\n") % (name, specType) "];\n") % (name, specType)
prefArray = ("const %s: &'static [Prefable<%s>] = &[\n" + prefArray = ("const %s: &'static [Guard<&'static [%s]>] = &[\n" +
",\n".join(prefableSpecs) + "\n" + ",\n".join(prefableSpecs) + "\n" +
"];\n") % (name, specType) "];\n") % (name, specType)
return specsArray + prefArray return specsArray + prefArray
@ -1500,7 +1473,7 @@ class MethodDefiner(PropertyDefiner):
"methodInfo": False, "methodInfo": False,
"selfHostedName": "ArrayValues", "selfHostedName": "ArrayValues",
"length": 0, "length": 0,
"condition": MemberCondition()}) "condition": "Condition::Satisfied"})
isUnforgeableInterface = bool(descriptor.interface.getExtendedAttribute("Unforgeable")) isUnforgeableInterface = bool(descriptor.interface.getExtendedAttribute("Unforgeable"))
if not static and unforgeable == isUnforgeableInterface: if not static and unforgeable == isUnforgeableInterface:
@ -1551,7 +1524,7 @@ class MethodDefiner(PropertyDefiner):
% m["name"][2:], accessor, jitinfo, m["length"], flags, selfHostedName) % m["name"][2:], accessor, jitinfo, m["length"], flags, selfHostedName)
return (str_to_const_array(m["name"]), 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, array, name,
' JSFunctionSpec {\n' ' JSFunctionSpec {\n'
' name: %s as *const u8 as *const libc::c_char,\n' ' name: %s as *const u8 as *const libc::c_char,\n'
@ -1631,7 +1604,7 @@ class AttrDefiner(PropertyDefiner):
return (str_to_const_array(attr.identifier.name), flags, getter(attr), return (str_to_const_array(attr.identifier.name), flags, getter(attr),
setter(attr)) setter(attr))
return self.generatePrefableArray( return self.generateGuardedArray(
array, name, array, name,
' JSPropertySpec {\n' ' JSPropertySpec {\n'
' name: %s as *const u8 as *const libc::c_char,\n' ' name: %s as *const u8 as *const libc::c_char,\n'
@ -1666,7 +1639,7 @@ class ConstDefiner(PropertyDefiner):
return (str_to_const_array(const.identifier.name), return (str_to_const_array(const.identifier.name),
convertConstIDLValueToJSVal(const.value)) convertConstIDLValueToJSVal(const.value))
return self.generatePrefableArray( return self.generateGuardedArray(
array, name, array, name,
' ConstantSpec { name: %s, value: %s }', ' ConstantSpec { name: %s, value: %s }',
None, None,
@ -2327,8 +2300,8 @@ def InitUnforgeablePropertiesOnHolder(descriptor, properties):
""" """
unforgeables = [] unforgeables = []
defineUnforgeableAttrs = "define_prefable_properties(cx, unforgeable_holder.handle(), %s);" defineUnforgeableAttrs = "define_guarded_properties(cx, unforgeable_holder.handle(), %s);"
defineUnforgeableMethods = "define_prefable_methods(cx, unforgeable_holder.handle(), %s);" defineUnforgeableMethods = "define_guarded_methods(cx, unforgeable_holder.handle(), %s);"
unforgeableMembers = [ unforgeableMembers = [
(defineUnforgeableAttrs, properties.unforgeable_attrs), (defineUnforgeableAttrs, properties.unforgeable_attrs),
@ -2560,15 +2533,10 @@ assert!(!prototype_proto.ptr.is_null());""" % getPrototypeProto)]
properties = {"id": name} properties = {"id": name}
for arrayName in self.properties.arrayNames(): for arrayName in self.properties.arrayNames():
array = getattr(self.properties, arrayName) array = getattr(self.properties, arrayName)
if arrayName == "consts": if array.length():
if array.length(): properties[arrayName] = array.variableName()
properties[arrayName] = array.variableName()
else:
properties[arrayName] = "&[]"
elif array.length():
properties[arrayName] = "Some(%s)" % array.variableName()
else: else:
properties[arrayName] = "None" properties[arrayName] = "&[]"
code.append(CGGeneric(""" code.append(CGGeneric("""
let mut prototype = RootedObject::new(cx, ptr::null_mut()); let mut prototype = RootedObject::new(cx, ptr::null_mut());
@ -5563,13 +5531,13 @@ class CGBindingRoot(CGThing):
'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}',
'dom::bindings::interface::{create_named_constructors, create_noncallback_interface_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::{ConstantSpec, NonNullJSNative}',
'dom::bindings::interface::ConstantVal::{IntVal, UintVal}', 'dom::bindings::interface::ConstantVal::{IntVal, UintVal}',
'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}',
'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::{DOM_PROTO_UNFORGEABLE_HOLDER_SLOT, JSCLASS_DOM_GLOBAL}',
'dom::bindings::utils::{ProtoOrIfaceArray, create_dom_global}', 'dom::bindings::utils::{ProtoOrIfaceArray, create_dom_global}',
'dom::bindings::utils::{enumerate_global, finalize_global, find_enum_string_index}', 'dom::bindings::utils::{enumerate_global, finalize_global, find_enum_string_index}',
@ -5593,6 +5561,7 @@ class CGBindingRoot(CGThing):
'dom::bindings::error::{Fallible, Error, ErrorResult}', 'dom::bindings::error::{Fallible, Error, ErrorResult}',
'dom::bindings::error::Error::JSFailed', 'dom::bindings::error::Error::JSFailed',
'dom::bindings::error::throw_dom_exception', 'dom::bindings::error::throw_dom_exception',
'dom::bindings::guard::{Condition, Guard}',
'dom::bindings::proxyhandler', 'dom::bindings::proxyhandler',
'dom::bindings::proxyhandler::{ensure_expando_object, fill_property_descriptor}', 'dom::bindings::proxyhandler::{ensure_expando_object, fill_property_descriptor}',
'dom::bindings::proxyhandler::{get_expando_object, get_property_descriptor}', 'dom::bindings::proxyhandler::{get_expando_object, get_property_descriptor}',

View file

@ -302,44 +302,39 @@ impl GlobalRoot {
/// Returns the global object of the realm that the given DOM object's reflector was created in. /// Returns the global object of the realm that the given DOM object's reflector was created in.
pub fn global_root_from_reflector<T: Reflectable>(reflector: &T) -> GlobalRoot { pub fn global_root_from_reflector<T: Reflectable>(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. /// Returns the Rust global object from a JS global object.
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn global_root_from_global(global: *mut JSObject) -> GlobalRoot { unsafe fn global_root_from_global(global: *mut JSObject) -> GlobalRoot {
unsafe { assert!(!global.is_null());
let clasp = JS_GetClass(global); let clasp = JS_GetClass(global);
assert!(((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)) != 0); assert!(((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)) != 0);
match root_from_object(global) { match root_from_object(global) {
Ok(window) => return GlobalRoot::Window(window), Ok(window) => return GlobalRoot::Window(window),
Err(_) => (), 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")
} }
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. /// Returns the global object of the realm that the given JS object was created in.
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn global_root_from_object(obj: *mut JSObject) -> GlobalRoot { pub unsafe fn global_root_from_object(obj: *mut JSObject) -> GlobalRoot {
unsafe { assert!(!obj.is_null());
let global = GetGlobalForObjectCrossCompartment(obj); let global = GetGlobalForObjectCrossCompartment(obj);
global_root_from_global(global) global_root_from_global(global)
}
} }
/// Returns the global object for the given JSContext /// Returns the global object for the given JSContext
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn global_root_from_context(cx: *mut JSContext) -> GlobalRoot { pub unsafe fn global_root_from_context(cx: *mut JSContext) -> GlobalRoot {
unsafe { let global = CurrentGlobalOrNull(cx);
let global = CurrentGlobalOrNull(cx); global_root_from_global(global)
assert!(!global.is_null());
global_root_from_global(global)
}
} }

View file

@ -0,0 +1,55 @@
/* 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 js::jsapi::{HandleObject, JSContext};
use util::prefs::get_pref;
/// A container with a condition.
pub struct Guard<T: Clone + Copy> {
condition: Condition,
value: T,
}
impl<T: Clone + Copy> Guard<T> {
/// 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.
///
/// The passed handle is the object on which the value may be exposed.
pub unsafe fn expose(&self, cx: *mut JSContext, obj: HandleObject) -> Option<T> {
if self.condition.is_satisfied(cx, obj) {
Some(self.value)
} else {
None
}
}
}
/// 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.
Satisfied,
}
impl Condition {
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,
}
}
}

View file

@ -6,7 +6,8 @@
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::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::error::throw_type_error;
use js::glue::UncheckedUnwrapObject; use js::glue::UncheckedUnwrapObject;
use js::jsapi::{Class, ClassExtension, ClassSpec, GetGlobalForObjectCrossCompartment}; use js::jsapi::{Class, ClassExtension, ClassSpec, GetGlobalForObjectCrossCompartment};
@ -66,7 +67,10 @@ pub type NonNullJSNative =
/// Defines constants on `obj`. /// Defines constants on `obj`.
/// Fails on JSAPI failure. /// 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: &[ConstantSpec]) {
for spec in constants { for spec in constants {
let value = RootedValue::new(cx, spec.get_value()); let value = RootedValue::new(cx, spec.get_value());
unsafe { unsafe {
@ -208,18 +212,20 @@ impl InterfaceConstructorBehavior {
/// Create and define the interface object of a callback interface. /// Create and define the interface object of a callback interface.
pub unsafe fn create_callback_interface_object( pub unsafe fn create_callback_interface_object(
cx: *mut JSContext, cx: *mut JSContext,
receiver: HandleObject, global: HandleObject,
constants: &'static [Prefable<ConstantSpec>], constants: &[Guard<&[ConstantSpec]>],
name: &'static [u8], name: &[u8],
rval: MutableHandleObject) { rval: MutableHandleObject) {
assert!(!constants.is_empty()); assert!(!constants.is_empty());
rval.set(JS_NewObject(cx, ptr::null())); rval.set(JS_NewObject(cx, ptr::null()));
assert!(!rval.ptr.is_null()); assert!(!rval.ptr.is_null());
for prefable in constants { for guard in constants {
define_constants(cx, rval.handle(), prefable.specs()); if let Some(specs) = guard.expose(cx, rval.handle()) {
define_constants(cx, rval.handle(), specs);
}
} }
define_name(cx, rval.handle(), name); 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. /// Create the interface prototype object of a non-callback interface.
@ -227,9 +233,9 @@ pub unsafe fn create_interface_prototype_object(
cx: *mut JSContext, cx: *mut JSContext,
proto: HandleObject, proto: HandleObject,
class: &'static JSClass, class: &'static JSClass,
regular_methods: Option<&'static [Prefable<JSFunctionSpec>]>, regular_methods: &[Guard<&'static [JSFunctionSpec]>],
regular_properties: Option<&'static [Prefable<JSPropertySpec>]>, regular_properties: &[Guard<&'static [JSPropertySpec]>],
constants: &'static [Prefable<ConstantSpec>], constants: &[Guard<&[ConstantSpec]>],
rval: MutableHandleObject) { rval: MutableHandleObject) {
create_object(cx, proto, class, regular_methods, regular_properties, constants, rval); create_object(cx, proto, class, regular_methods, regular_properties, constants, rval);
} }
@ -237,14 +243,14 @@ pub unsafe fn create_interface_prototype_object(
/// Create and define the interface object of a non-callback interface. /// Create and define the interface object of a non-callback interface.
pub unsafe fn create_noncallback_interface_object( pub unsafe fn create_noncallback_interface_object(
cx: *mut JSContext, cx: *mut JSContext,
receiver: HandleObject, global: HandleObject,
proto: HandleObject, proto: HandleObject,
class: &'static NonCallbackInterfaceObjectClass, class: &'static NonCallbackInterfaceObjectClass,
static_methods: Option<&'static [Prefable<JSFunctionSpec>]>, static_methods: &[Guard<&'static [JSFunctionSpec]>],
static_properties: Option<&'static [Prefable<JSPropertySpec>]>, static_properties: &[Guard<&'static [JSPropertySpec]>],
constants: &'static [Prefable<ConstantSpec>], constants: &[Guard<&[ConstantSpec]>],
interface_prototype_object: HandleObject, interface_prototype_object: HandleObject,
name: &'static [u8], name: &[u8],
length: u32, length: u32,
rval: MutableHandleObject) { rval: MutableHandleObject) {
create_object(cx, create_object(cx,
@ -257,14 +263,14 @@ pub unsafe fn create_noncallback_interface_object(
assert!(JS_LinkConstructorAndPrototype(cx, rval.handle(), interface_prototype_object)); assert!(JS_LinkConstructorAndPrototype(cx, rval.handle(), interface_prototype_object));
define_name(cx, rval.handle(), name); define_name(cx, rval.handle(), name);
define_length(cx, rval.handle(), length); 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. /// Create and define the named constructors of a non-callback interface.
pub unsafe fn create_named_constructors( pub unsafe fn create_named_constructors(
cx: *mut JSContext, cx: *mut JSContext,
receiver: HandleObject, global: HandleObject,
named_constructors: &[(NonNullJSNative, &'static [u8], u32)], named_constructors: &[(NonNullJSNative, &[u8], u32)],
interface_prototype_object: HandleObject) { interface_prototype_object: HandleObject) {
let mut constructor = RootedObject::new(cx, ptr::null_mut()); let mut constructor = RootedObject::new(cx, ptr::null_mut());
@ -288,7 +294,7 @@ pub unsafe fn create_named_constructors(
None, None,
None)); None));
define_on_global_object(cx, receiver, name, constructor.handle()); define_on_global_object(cx, global, name, constructor.handle());
} }
} }
@ -354,42 +360,46 @@ unsafe fn create_object(
cx: *mut JSContext, cx: *mut JSContext,
proto: HandleObject, proto: HandleObject,
class: &'static JSClass, class: &'static JSClass,
methods: Option<&'static [Prefable<JSFunctionSpec>]>, methods: &[Guard<&'static [JSFunctionSpec]>],
properties: Option<&'static [Prefable<JSPropertySpec>]>, properties: &[Guard<&'static [JSPropertySpec]>],
constants: &'static [Prefable<ConstantSpec>], constants: &[Guard<&[ConstantSpec]>],
rval: MutableHandleObject) { rval: MutableHandleObject) {
rval.set(JS_NewObjectWithUniqueType(cx, class, proto)); rval.set(JS_NewObjectWithUniqueType(cx, class, proto));
assert!(!rval.ptr.is_null()); assert!(!rval.ptr.is_null());
if let Some(methods) = methods { define_guarded_methods(cx, rval.handle(), methods);
define_prefable_methods(cx, rval.handle(), methods); define_guarded_properties(cx, rval.handle(), properties);
} for guard in constants {
if let Some(properties) = properties { if let Some(specs) = guard.expose(cx, rval.handle()) {
define_prefable_properties(cx, rval.handle(), properties); define_constants(cx, rval.handle(), specs);
} }
for prefable in constants {
define_constants(cx, rval.handle(), prefable.specs());
} }
} }
/// Conditionally define methods on an object. /// Conditionally define methods on an object.
pub unsafe fn define_prefable_methods(cx: *mut JSContext, pub unsafe fn define_guarded_methods(
obj: HandleObject, cx: *mut JSContext,
methods: &'static [Prefable<JSFunctionSpec>]) { obj: HandleObject,
for prefable in methods { methods: &[Guard<&'static [JSFunctionSpec]>]) {
define_methods(cx, obj, prefable.specs()).unwrap(); for guard in methods {
if let Some(specs) = guard.expose(cx, obj) {
define_methods(cx, obj, specs).unwrap();
}
} }
} }
/// Conditionally define properties on an object. /// Conditionally define properties on an object.
pub unsafe fn define_prefable_properties(cx: *mut JSContext, pub unsafe fn define_guarded_properties(
obj: HandleObject, cx: *mut JSContext,
properties: &'static [Prefable<JSPropertySpec>]) { obj: HandleObject,
for prefable in properties { properties: &[Guard<&'static [JSPropertySpec]>]) {
define_properties(cx, obj, prefable.specs()).unwrap(); for guard in properties {
if let Some(specs) = guard.expose(cx, obj) {
define_properties(cx, obj, specs).unwrap();
}
} }
} }
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'); assert!(*name.last().unwrap() == b'\0');
let name = RootedString::new( let name = RootedString::new(
cx, JS_AtomizeAndPinString(cx, name.as_ptr() as *const libc::c_char)); cx, JS_AtomizeAndPinString(cx, name.as_ptr() as *const libc::c_char));
@ -413,12 +423,12 @@ unsafe fn define_length(cx: *mut JSContext, obj: HandleObject, length: u32) {
unsafe fn define_on_global_object( unsafe fn define_on_global_object(
cx: *mut JSContext, cx: *mut JSContext,
receiver: HandleObject, global: HandleObject,
name: &'static [u8], name: &[u8],
obj: HandleObject) { obj: HandleObject) {
assert!(*name.last().unwrap() == b'\0'); assert!(*name.last().unwrap() == b'\0');
assert!(JS_DefineProperty1(cx, assert!(JS_DefineProperty1(cx,
receiver, global,
name.as_ptr() as *const libc::c_char, name.as_ptr() as *const libc::c_char,
obj, obj,
JSPROP_RESOLVING, JSPROP_RESOLVING,

View file

@ -133,6 +133,7 @@ pub mod cell;
pub mod conversions; pub mod conversions;
pub mod error; pub mod error;
pub mod global; pub mod global;
pub mod guard;
pub mod inheritance; pub mod inheritance;
pub mod interface; pub mod interface;
pub mod js; pub mod js;

View file

@ -39,7 +39,6 @@ use std::ffi::CString;
use std::os::raw::c_void; use std::os::raw::c_void;
use std::ptr; use std::ptr;
use std::slice; use std::slice;
use util::prefs;
/// Proxy handler for a WindowProxy. /// Proxy handler for a WindowProxy.
pub struct WindowProxyHandler(pub *const libc::c_void); pub struct WindowProxyHandler(pub *const libc::c_void);
@ -550,31 +549,3 @@ unsafe extern "C" fn instance_class_has_proto_at_depth(clasp: *const js::jsapi::
pub const DOM_CALLBACKS: DOMCallbacks = DOMCallbacks { pub const DOM_CALLBACKS: DOMCallbacks = DOMCallbacks {
instanceClassMatchesProto: Some(instance_class_has_proto_at_depth), instanceClassMatchesProto: Some(instance_class_has_proto_at_depth),
}; };
/// A container around JS member specifications that are conditionally enabled.
pub struct Prefable<T: 'static> {
/// 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],
/// Whether the specifications contain special terminating entries that should be
/// included or not.
pub terminator: bool,
}
impl<T> Prefable<T> {
/// Retrieve the slice represented by this container, unless the condition
/// guarding it is false.
pub fn specs(&self) -> &'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 {
&[]
};
}
}
self.specs
}
}

View file

@ -56,7 +56,7 @@ use dom::htmlembedelement::HTMLEmbedElement;
use dom::htmlformelement::HTMLFormElement; use dom::htmlformelement::HTMLFormElement;
use dom::htmlheadelement::HTMLHeadElement; use dom::htmlheadelement::HTMLHeadElement;
use dom::htmlhtmlelement::HTMLHtmlElement; use dom::htmlhtmlelement::HTMLHtmlElement;
use dom::htmliframeelement::{self, HTMLIFrameElement}; use dom::htmliframeelement::HTMLIFrameElement;
use dom::htmlimageelement::HTMLImageElement; use dom::htmlimageelement::HTMLImageElement;
use dom::htmllinkelement::HTMLLinkElement; use dom::htmllinkelement::HTMLLinkElement;
use dom::htmlmetaelement::HTMLMetaElement; use dom::htmlmetaelement::HTMLMetaElement;
@ -127,6 +127,7 @@ use task_source::dom_manipulation::DOMManipulationTask;
use time; use time;
use url::Url; use url::Url;
use url::percent_encoding::percent_decode; use url::percent_encoding::percent_decode;
use util::prefs::mozbrowser_enabled;
use util::str::{split_html_space_chars, str_join}; use util::str::{split_html_space_chars, str_join};
#[derive(JSTraceable, PartialEq, HeapSizeOf)] #[derive(JSTraceable, PartialEq, HeapSizeOf)]
@ -1261,7 +1262,7 @@ impl Document {
} }
pub fn trigger_mozbrowser_event(&self, event: MozBrowserEvent) { 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() { if let Some((containing_pipeline_id, subpage_id)) = self.window.parent_info() {
let event = ConstellationMsg::MozBrowserEvent(containing_pipeline_id, let event = ConstellationMsg::MozBrowserEvent(containing_pipeline_id,
subpage_id, subpage_id,

View file

@ -42,13 +42,9 @@ use std::cell::Cell;
use string_cache::Atom; use string_cache::Atom;
use style::context::ReflowGoal; use style::context::ReflowGoal;
use url::Url; use url::Url;
use util::prefs; use util::prefs::mozbrowser_enabled;
use util::str::LengthOrPercentageOrAuto; use util::str::LengthOrPercentageOrAuto;
pub fn mozbrowser_enabled() -> bool {
prefs::get_pref("dom.mozbrowser.enabled").as_boolean().unwrap_or(false)
}
#[derive(HeapSizeOf)] #[derive(HeapSizeOf)]
enum SandboxAllowance { enum SandboxAllowance {
AllowNothing = 0x00, AllowNothing = 0x00,
@ -439,29 +435,16 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement {
// Experimental mozbrowser implementation is based on the webidl // Experimental mozbrowser implementation is based on the webidl
// present in the gecko source tree, and the documentation here: // present in the gecko source tree, and the documentation here:
// https://developer.mozilla.org/en-US/docs/Web/API/Using_the_Browser_API // 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 // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-mozbrowser
fn Mozbrowser(&self) -> bool { fn Mozbrowser(&self) -> bool {
// We don't want to allow mozbrowser iframes within iframes let element = self.upcast::<Element>();
let is_root_pipeline = window_from_node(self).parent_info().is_none(); element.has_attribute(&atom!("mozbrowser"))
if mozbrowser_enabled() && is_root_pipeline {
let element = self.upcast::<Element>();
element.has_attribute(&atom!("mozbrowser"))
} else {
false
}
} }
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-mozbrowser // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-mozbrowser
fn SetMozbrowser(&self, value: bool) -> ErrorResult { fn SetMozbrowser(&self, value: bool) {
if mozbrowser_enabled() { let element = self.upcast::<Element>();
let element = self.upcast::<Element>(); element.set_bool_attribute(&atom!("mozbrowser"), value);
element.set_bool_attribute(&atom!("mozbrowser"), value);
}
Ok(())
} }
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/goBack // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/goBack

View file

@ -24,7 +24,7 @@ use dom::bindings::str::{ByteString, DOMString, USVString};
use dom::bindings::weakref::MutableWeakRef; use dom::bindings::weakref::MutableWeakRef;
use dom::blob::{Blob, DataSlice}; use dom::blob::{Blob, DataSlice};
use dom::url::URL; use dom::url::URL;
use js::jsapi::{HandleValue, JSContext, JSObject}; use js::jsapi::{HandleObject, HandleValue, JSContext, JSObject};
use js::jsval::{JSVal, NullValue}; use js::jsval::{JSVal, NullValue};
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::ptr; use std::ptr;
@ -567,6 +567,10 @@ impl TestBindingMethods for TestBinding {
fn PrefControlledAttributeEnabled(&self) -> bool { false } fn PrefControlledAttributeEnabled(&self) -> bool { false }
fn PrefControlledMethodDisabled(&self) {} fn PrefControlledMethodDisabled(&self) {}
fn PrefControlledMethodEnabled(&self) {} fn PrefControlledMethodEnabled(&self) {}
fn FuncControlledAttributeDisabled(&self) -> bool { false }
fn FuncControlledAttributeEnabled(&self) -> bool { false }
fn FuncControlledMethodDisabled(&self) {}
fn FuncControlledMethodEnabled(&self) {}
} }
impl TestBinding { impl TestBinding {
@ -577,4 +581,14 @@ impl TestBinding {
pub fn PrefControlledStaticAttributeEnabled(_: GlobalRef) -> bool { false } pub fn PrefControlledStaticAttributeEnabled(_: GlobalRef) -> bool { false }
pub fn PrefControlledStaticMethodDisabled(_: GlobalRef) {} pub fn PrefControlledStaticMethodDisabled(_: GlobalRef) {}
pub fn PrefControlledStaticMethodEnabled(_: 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 }
} }

View file

@ -32,8 +32,8 @@ partial interface HTMLIFrameElement {
}; };
partial interface HTMLIFrameElement { partial interface HTMLIFrameElement {
[ChromeOnly,SetterThrows,Pref="dom.mozbrowser.enabled"] [Func="Window::global_is_mozbrowser"]
attribute boolean mozbrowser; attribute boolean mozbrowser;
}; };
HTMLIFrameElement implements BrowserElement; HTMLIFrameElement implements BrowserElement;

View file

@ -433,4 +433,26 @@ interface TestBinding {
static void prefControlledStaticMethodEnabled(); static void prefControlledStaticMethodEnabled();
[Pref="dom.testbinding.prefcontrolled2.enabled"] [Pref="dom.testbinding.prefcontrolled2.enabled"]
const unsigned short prefControlledConstEnabled = 0; 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;
}; };

View file

@ -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::{ScrollBehavior, ScrollToOptions};
use dom::bindings::codegen::Bindings::WindowBinding::{self, FrameRequestCallback, WindowMethods}; use dom::bindings::codegen::Bindings::WindowBinding::{self, FrameRequestCallback, WindowMethods};
use dom::bindings::error::{Error, Fallible, report_pending_exception}; 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::inheritance::Castable;
use dom::bindings::js::{JS, MutNullableHeap, Root}; use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::num::Finite; use dom::bindings::num::Finite;
@ -37,9 +37,8 @@ use dom::storage::Storage;
use euclid::{Point2D, Rect, Size2D}; use euclid::{Point2D, Rect, Size2D};
use gfx_traits::LayerId; use gfx_traits::LayerId;
use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::ipc::{self, IpcSender};
use js::jsapi::{Evaluate2, MutableHandleValue}; use js::jsapi::{Evaluate2, HandleObject, HandleValue, JSAutoCompartment, JSContext};
use js::jsapi::{HandleValue, JSContext}; use js::jsapi::{JS_GetRuntime, JS_GC, MutableHandleValue, SetWindowProxy};
use js::jsapi::{JSAutoCompartment, JS_GC, JS_GetRuntime, SetWindowProxy};
use js::rust::CompileOptionsWrapper; use js::rust::CompileOptionsWrapper;
use js::rust::Runtime; use js::rust::Runtime;
use layout_interface::{ContentBoxResponse, ContentBoxesResponse, ResolvedStyleResponse, ScriptReflow}; use layout_interface::{ContentBoxResponse, ContentBoxesResponse, ResolvedStyleResponse, ScriptReflow};
@ -93,6 +92,7 @@ use timers::{IsInterval, OneshotTimerCallback, OneshotTimerHandle, OneshotTimers
use tinyfiledialogs::{self, MessageBoxIcon}; use tinyfiledialogs::{self, MessageBoxIcon};
use url::Url; use url::Url;
use util::geometry::{self, MAX_RECT}; use util::geometry::{self, MAX_RECT};
use util::prefs::mozbrowser_enabled;
use util::str::HTML_SPACE_CHARACTERS; use util::str::HTML_SPACE_CHARACTERS;
use util::{breakpoint, opts}; use util::{breakpoint, opts};
use webdriver_handlers::jsval_to_webdriver; use webdriver_handlers::jsval_to_webdriver;
@ -1437,6 +1437,19 @@ impl Window {
context.active_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 { impl Window {

View file

@ -62,7 +62,7 @@ use string_cache::Atom;
use time; use time;
use timers::{OneshotTimerCallback, OneshotTimerHandle}; use timers::{OneshotTimerCallback, OneshotTimerHandle};
use url::{Url, Position}; use url::{Url, Position};
use util::prefs; use util::prefs::mozbrowser_enabled;
#[derive(JSTraceable, PartialEq, Copy, Clone, HeapSizeOf)] #[derive(JSTraceable, PartialEq, Copy, Clone, HeapSizeOf)]
enum XMLHttpRequestState { enum XMLHttpRequestState {
@ -884,7 +884,7 @@ impl XMLHttpRequest {
// story. See https://github.com/servo/servo/issues/9582 // story. See https://github.com/servo/servo/issues/9582
if let GlobalRoot::Window(win) = self.global() { if let GlobalRoot::Window(win) = self.global() {
let is_root_pipeline = win.parent_info().is_none(); 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 is_root_pipeline && is_mozbrowser_enabled
} else { } else {
false false

View file

@ -243,3 +243,7 @@ pub fn reset_all_prefs() {
reset_pref(name); reset_pref(name);
} }
} }
pub fn mozbrowser_enabled() -> bool {
get_pref("dom.mozbrowser.enabled").as_boolean().unwrap_or(false)
}

View file

@ -19,10 +19,15 @@ function test_member(name, enabled, target) {
} }
var members = [ var members = [
'funcControlledAttribute',
'funcControlledMethod',
'prefControlledAttribute', 'prefControlledAttribute',
'prefControlledMethod' 'prefControlledMethod'
]; ];
var staticMembers = [ var staticMembers = [
'funcControlledStaticAttribute',
'funcControlledStaticMethod',
'funcControlledConst',
'prefControlledStaticAttribute', 'prefControlledStaticAttribute',
'prefControlledStaticMethod', 'prefControlledStaticMethod',
'prefControlledConst' 'prefControlledConst'