diff options
-rw-r--r-- | components/compositing/constellation.rs | 4 | ||||
-rw-r--r-- | components/compositing/pipeline.rs | 2 | ||||
-rw-r--r-- | components/script/dom/htmliframeelement.rs | 2 | ||||
-rw-r--r-- | components/script/dom/mouseevent.rs | 2 | ||||
-rw-r--r-- | components/style/properties.mako.rs | 12 | ||||
-rw-r--r-- | components/style/stylesheets.rs | 2 | ||||
-rw-r--r-- | components/util/opts.rs | 4 | ||||
-rw-r--r-- | components/util/prefs.rs | 160 | ||||
-rw-r--r-- | components/webdriver_server/lib.rs | 13 | ||||
-rw-r--r-- | tests/unit/style/viewport.rs | 6 |
10 files changed, 174 insertions, 33 deletions
diff --git a/components/compositing/constellation.rs b/components/compositing/constellation.rs index a9797225454..81a35241b80 100644 --- a/components/compositing/constellation.rs +++ b/components/compositing/constellation.rs @@ -905,7 +905,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { containing_pipeline_id: PipelineId, subpage_id: SubpageId, event: MozBrowserEvent) { - assert!(prefs::get_pref("dom.mozbrowser.enabled").unwrap_or(false)); + assert!(prefs::get_pref("dom.mozbrowser.enabled").as_boolean().unwrap_or(false)); // Find the script channel for the given parent pipeline, // and pass the event to that script task. @@ -1387,7 +1387,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { // https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowserlocationchange fn trigger_mozbrowserlocationchange(&self, pipeline_id: PipelineId) { - if prefs::get_pref("dom.mozbrowser.enabled").unwrap_or(false) { + if prefs::get_pref("dom.mozbrowser.enabled").as_boolean().unwrap_or(false) { // Work around borrow checker let event_info = { let pipeline = self.pipeline(pipeline_id); diff --git a/components/compositing/pipeline.rs b/components/compositing/pipeline.rs index 8e07e220da8..73cabc1d35e 100644 --- a/components/compositing/pipeline.rs +++ b/components/compositing/pipeline.rs @@ -289,7 +289,7 @@ impl Pipeline { pub fn trigger_mozbrowser_event(&self, subpage_id: SubpageId, event: MozBrowserEvent) { - assert!(prefs::get_pref("dom.mozbrowser.enabled").unwrap_or(false)); + assert!(prefs::get_pref("dom.mozbrowser.enabled").as_boolean().unwrap_or(false)); let event = ConstellationControlMsg::MozBrowserEvent(self.id, subpage_id, diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index a5d2941e2ce..8e0016f4bb0 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -40,7 +40,7 @@ use util::str::DOMString; use util::str::{self, LengthOrPercentageOrAuto}; pub fn mozbrowser_enabled() -> bool { - prefs::get_pref("dom.mozbrowser.enabled").unwrap_or(false) + prefs::get_pref("dom.mozbrowser.enabled").as_boolean().unwrap_or(false) } #[derive(HeapSizeOf)] diff --git a/components/script/dom/mouseevent.rs b/components/script/dom/mouseevent.rs index 5e75d11ea9d..3e6f5c20e30 100644 --- a/components/script/dom/mouseevent.rs +++ b/components/script/dom/mouseevent.rs @@ -171,7 +171,7 @@ impl MouseEventMethods for MouseEvent { // This returns the same result as current gecko. // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/which fn Which(&self) -> i32 { - if prefs::get_pref("dom.mouseevent.which.enabled").unwrap_or(false) { + if prefs::get_pref("dom.mouseevent.which.enabled").as_boolean().unwrap_or(false) { (self.button.get() + 1) as i32 } else { 0 diff --git a/components/style/properties.mako.rs b/components/style/properties.mako.rs index 374b9b875d0..c1bca4d56dc 100644 --- a/components/style/properties.mako.rs +++ b/components/style/properties.mako.rs @@ -477,7 +477,8 @@ pub mod longhands { % for value in values[:-1]: "${value}" => { % if value in experimental_values: - if !::util::prefs::get_pref("layout.${value}.enabled").unwrap_or(false) { + if !::util::prefs::get_pref("layout.${value}.enabled") + .as_boolean().unwrap_or(false) { return Err(()) } % endif @@ -487,7 +488,8 @@ pub mod longhands { % for value in values[-1:]: "${value}" => { % if value in experimental_values: - if !::util::prefs::get_pref("layout.${value}.enabled".unwrap_or(false) { + if !::util::prefs::get_pref("layout.${value}.enabled") + .as_boolean().unwrap_or(false) { return Err(()) } % endif @@ -5945,7 +5947,8 @@ impl PropertyDeclaration { % if property.derived_from is None: "${property.name}" => { % if property.experimental: - if !::util::prefs::get_pref("${property.experimental}").unwrap_or(false) { + if !::util::prefs::get_pref("${property.experimental}") + .as_boolean().unwrap_or(false) { return PropertyDeclarationParseResult::ExperimentalProperty } % endif @@ -5964,7 +5967,8 @@ impl PropertyDeclaration { % for shorthand in SHORTHANDS: "${shorthand.name}" => { % if shorthand.experimental: - if !::util::prefs::get_pref("${shorthand.experimental}").unwrap_or(false) { + if !::util::prefs::get_pref("${shorthand.experimental}") + .as_boolean().unwrap_or(false) { return PropertyDeclarationParseResult::ExperimentalProperty } % endif diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index 8c78b19aa3c..c9d5354238a 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -426,7 +426,7 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> { Ok(AtRuleType::WithBlock(AtRulePrelude::FontFace)) }, "viewport" => { - if ::util::prefs::get_pref("layout.viewport.enabled").unwrap_or(false) { + if ::util::prefs::get_pref("layout.viewport.enabled").as_boolean().unwrap_or(false) { Ok(AtRuleType::WithBlock(AtRulePrelude::Viewport)) } else { Err(()) diff --git a/components/util/opts.rs b/components/util/opts.rs index 1a310dd543c..bdf8277adce 100644 --- a/components/util/opts.rs +++ b/components/util/opts.rs @@ -9,7 +9,7 @@ use euclid::size::{Size2D, TypedSize2D}; use geometry::ScreenPx; use getopts::Options; use num_cpus; -use prefs; +use prefs::{self, PrefValue}; use std::cmp; use std::default::Default; use std::env; @@ -614,7 +614,7 @@ pub fn from_cmdline_args(args: &[String]) { // This must happen after setting the default options, since the prefs rely on // on the resource path. for pref in opt_match.opt_strs("pref").iter() { - prefs::set_pref(pref, true); + prefs::set_pref(pref, PrefValue::Boolean(true)); } } diff --git a/components/util/prefs.rs b/components/util/prefs.rs index bd3110b6995..e2ee109ea00 100644 --- a/components/util/prefs.rs +++ b/components/util/prefs.rs @@ -3,19 +3,122 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use resource_files::resources_dir_path; -use rustc_serialize::json::Json; +use rustc_serialize::json::{Json, ToJson}; +use std::borrow::ToOwned; use std::collections::HashMap; use std::fs::File; use std::sync::{Arc, Mutex}; lazy_static! { - static ref PREFS: Arc<Mutex<HashMap<String, bool>>> = { + static ref PREFS: Arc<Mutex<HashMap<String, Pref>>> = { let prefs = read_prefs().unwrap_or(HashMap::new()); Arc::new(Mutex::new(prefs)) }; } -fn read_prefs() -> Result<HashMap<String, bool>, ()> { +#[derive(PartialEq, Clone, Debug)] +pub enum PrefValue { + Boolean(bool), + String(String), + Missing +} + +impl PrefValue { + pub fn from_json(data: Json) -> Result<PrefValue, ()> { + let value = match data { + Json::Boolean(x) => PrefValue::Boolean(x), + Json::String(x) => PrefValue::String(x), + _ => return Err(()) + }; + Ok(value) + } + + pub fn as_boolean(&self) -> Option<bool> { + match self { + &PrefValue::Boolean(value) => { + Some(value) + }, + _ => None + } + } + + pub fn as_string(&self) -> Option<&str> { + match *self { + PrefValue::String(ref value) => { + Some(&value) + }, + _ => None + } + } +} + +impl ToJson for PrefValue { + fn to_json(&self) -> Json { + match *self { + PrefValue::Boolean(x) => { + Json::Boolean(x) + }, + PrefValue::String(ref x) => { + Json::String(x.clone()) + } + PrefValue::Missing => Json::Null + } + } +} + +enum Pref { + NoDefault(Arc<PrefValue>), + WithDefault(Arc<PrefValue>, Option<Arc<PrefValue>>) +} + + +impl Pref { + pub fn new(value: PrefValue) -> Pref { + Pref::NoDefault(Arc::new(value)) + } + + fn new_default(value: PrefValue) -> Pref { + Pref::WithDefault(Arc::new(value), None) + } + + fn from_json(data: Json) -> Result<Pref, ()> { + let value = try!(PrefValue::from_json(data)); + Ok(Pref::new_default(value)) + } + + pub fn value(&self) -> &Arc<PrefValue> { + match self { + &Pref::NoDefault(ref x) => x, + &Pref::WithDefault(ref default, ref override_value) => { + match override_value { + &Some(ref x) => x, + &None => default + } + } + } + } + + fn set(&mut self, value: PrefValue) { + // TODO - this should error if we try to override a pref of one type + // with a value of a different type + match self { + &mut Pref::NoDefault(ref mut pref_value) => { + *pref_value = Arc::new(value) + }, + &mut Pref::WithDefault(_, ref mut override_value) => { + *override_value = Some(Arc::new(value)) + } + } + } +} + +impl ToJson for Pref { + fn to_json(&self) -> Json { + self.value().to_json() + } +} + +fn read_prefs() -> Result<HashMap<String, Pref>, ()> { let mut path = resources_dir_path(); path.push("prefs.json"); @@ -29,22 +132,53 @@ fn read_prefs() -> Result<HashMap<String, bool>, ()> { })); let mut prefs = HashMap::new(); - if let Some(obj) = json.as_object() { - for (name, value) in obj.iter() { - if let Some(bool_value) = value.as_boolean() { - prefs.insert(name.clone(), bool_value); - } else { - println!("Ignoring non-boolean preference value for {:?}", name); + if let Json::Object(obj) = json { + for (name, value) in obj.into_iter() { + match Pref::from_json(value) { + Ok(x) => { + prefs.insert(name, x); + }, + Err(_) => println!("Ignoring non-boolean/string preference value for {:?}", name) } } } Ok(prefs) } -pub fn get_pref(name: &str) -> Option<bool> { - PREFS.lock().unwrap().get(name).cloned() +pub fn get_pref(name: &str) -> Arc<PrefValue> { + PREFS.lock().unwrap().get(name).map(|x| x.value().clone()).unwrap_or(Arc::new(PrefValue::Missing)) +} + +pub fn set_pref(name: &str, value: PrefValue) { + let mut prefs = PREFS.lock().unwrap(); + if let Some(pref) = prefs.get_mut(name) { + pref.set(value); + return; + } + prefs.insert(name.to_owned(), Pref::new(value)); } -pub fn set_pref(name: &str, value: bool) { - let _ = PREFS.lock().unwrap().insert(name.to_owned(), value); +pub fn reset_pref(name: &str) -> Arc<PrefValue> { + let mut prefs = PREFS.lock().unwrap(); + let result = match prefs.get_mut(name) { + None => return Arc::new(PrefValue::Missing), + Some(&mut Pref::NoDefault(_)) => Arc::new(PrefValue::Missing), + Some(&mut Pref::WithDefault(ref default, ref mut set_value)) => { + *set_value = None; + default.clone() + }, + }; + if *result == PrefValue::Missing { + prefs.remove(name); + } + result +} + +pub fn reset_all_prefs() { + let names = { + PREFS.lock().unwrap().keys().map(|x| x.clone()).collect::<Vec<String>>() + }; + for name in names.iter() { + reset_pref(name); + } } diff --git a/components/webdriver_server/lib.rs b/components/webdriver_server/lib.rs index 6ecbdd18c68..29bac552568 100644 --- a/components/webdriver_server/lib.rs +++ b/components/webdriver_server/lib.rs @@ -35,7 +35,7 @@ use std::collections::BTreeMap; use std::net::SocketAddr; use std::thread::{self, sleep_ms}; use url::Url; -use util::prefs::{get_pref, set_pref}; +use util::prefs::{get_pref, reset_all_prefs, reset_pref, set_pref, PrefValue}; use util::task::spawn_named; use uuid::Uuid; use webdriver::command::{GetParameters, JavascriptCommandParameters, LocatorParameters}; @@ -150,7 +150,7 @@ impl ToJson for GetPrefsParameters { #[derive(Clone, PartialEq)] struct SetPrefsParameters { - prefs: Vec<(String, bool)> + prefs: Vec<(String, PrefValue)> } impl Parameters for SetPrefsParameters { @@ -166,9 +166,9 @@ impl Parameters for SetPrefsParameters { "prefs was not an array"))); let mut params = Vec::with_capacity(items.len()); for (name, val) in items.iter() { - let value = try!(val.as_boolean().ok_or( - WebDriverError::new(ErrorStatus::InvalidArgument, - "Pref is not a bool"))); + let value = try!(PrefValue::from_json(val).or( + Err(WebDriverError::new(ErrorStatus::InvalidArgument, + "Pref is not a boolean or string")))); let key = name.to_owned(); params.push((key, value)); } @@ -633,13 +633,14 @@ impl Handler { .iter() .map(|item| (item.clone(), get_pref(item).to_json())) .collect::<BTreeMap<_, _>>(); + Ok(WebDriverResponse::Generic(ValueResponse::new(prefs.to_json()))) } fn handle_set_prefs(&self, parameters: &SetPrefsParameters) -> WebDriverResult<WebDriverResponse> { for &(ref key, ref value) in parameters.prefs.iter() { - set_pref(key, *value); + set_pref(key, value.clone()); } Ok(WebDriverResponse::Void) } diff --git a/tests/unit/style/viewport.rs b/tests/unit/style/viewport.rs index 994908b3cfb..bd1a2c0195a 100644 --- a/tests/unit/style/viewport.rs +++ b/tests/unit/style/viewport.rs @@ -26,7 +26,8 @@ fn test_viewport_rule<F>(css: &str, callback: F) where F: Fn(&Vec<ViewportDescriptorDeclaration>, &str) { - ::util::prefs::set_pref("layout.viewport.enabled", true); + ::util::prefs::set_pref("layout.viewport.enabled", + ::util::prefs::PrefValue::Boolean(true)); let stylesheet = stylesheet!(css, Author); let mut rule_count = 0; @@ -173,7 +174,8 @@ fn cascading_within_viewport_rule() { #[test] fn multiple_stylesheets_cascading() { - ::util::prefs::set_pref("layout.viewport.enabled", true); + ::util::prefs::set_pref("layout.viewport.enabled", + ::util::prefs::PrefValue::Boolean(true)); let device = Device::new(MediaType::Screen, Size2D::typed(800., 600.)); let stylesheets = vec![ |