Format components config #21373

This commit is contained in:
kingdido999 2018-09-02 08:27:07 +08:00
parent c8f3abfdbc
commit ce41c95e05
6 changed files with 444 additions and 225 deletions

View file

@ -8,7 +8,12 @@
use std::path::PathBuf; use std::path::PathBuf;
#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))] #[cfg(all(
unix,
not(target_os = "macos"),
not(target_os = "ios"),
not(target_os = "android")
))]
pub fn default_config_dir() -> Option<PathBuf> { pub fn default_config_dir() -> Option<PathBuf> {
let mut config_dir = ::dirs::config_dir().unwrap(); let mut config_dir = ::dirs::config_dir().unwrap();
config_dir.push("servo"); config_dir.push("servo");

View file

@ -9,17 +9,21 @@ extern crate dirs;
extern crate embedder_traits; extern crate embedder_traits;
extern crate euclid; extern crate euclid;
extern crate getopts; extern crate getopts;
#[macro_use] extern crate lazy_static; #[macro_use]
#[macro_use] extern crate log; extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate num_cpus; extern crate num_cpus;
extern crate rustc_serialize; extern crate rustc_serialize;
#[macro_use] extern crate serde; #[macro_use]
extern crate serde;
extern crate servo_geometry; extern crate servo_geometry;
extern crate servo_url; extern crate servo_url;
extern crate url; extern crate url;
pub mod basedir; pub mod basedir;
#[allow(unsafe_code)] pub mod opts; #[allow(unsafe_code)]
pub mod opts;
pub mod prefs; pub mod prefs;
pub fn servo_version() -> String { pub fn servo_version() -> String {

View file

@ -22,7 +22,6 @@ use std::process;
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
use url::{self, Url}; use url::{self, Url};
/// Global flags for Servo, currently set on the command line. /// Global flags for Servo, currently set on the command line.
#[derive(Clone, Deserialize, Serialize)] #[derive(Clone, Deserialize, Serialize)]
pub struct Opts { pub struct Opts {
@ -230,11 +229,13 @@ pub struct Opts {
} }
fn print_usage(app: &str, opts: &Options) { fn print_usage(app: &str, opts: &Options) {
let message = format!("Usage: {} [ options ... ] [URL]\n\twhere options include", app); let message = format!(
"Usage: {} [ options ... ] [URL]\n\twhere options include",
app
);
println!("{}", opts.usage(&message)); println!("{}", opts.usage(&message));
} }
/// Debug options for Servo, currently set on the command line with -Z /// Debug options for Servo, currently set on the command line with -Z
#[derive(Default)] #[derive(Default)]
pub struct DebugOptions { pub struct DebugOptions {
@ -333,7 +334,6 @@ pub struct DebugOptions {
pub signpost: bool, pub signpost: bool,
} }
impl DebugOptions { impl DebugOptions {
pub fn extend(&mut self, debug_string: String) -> Result<(), String> { pub fn extend(&mut self, debug_string: String) -> Result<(), String> {
for option in debug_string.split(',') { for option in debug_string.split(',') {
@ -371,50 +371,103 @@ impl DebugOptions {
"" => {}, "" => {},
_ => return Err(String::from(option)), _ => return Err(String::from(option)),
}; };
}; }
Ok(()) Ok(())
} }
} }
fn print_debug_usage(app: &str) -> ! { fn print_debug_usage(app: &str) -> ! {
fn print_option(name: &str, description: &str) { fn print_option(name: &str, description: &str) {
println!("\t{:<35} {}", name, description); println!("\t{:<35} {}", name, description);
} }
println!("Usage: {} debug option,[options,...]\n\twhere options include\n\nOptions:", app); println!(
"Usage: {} debug option,[options,...]\n\twhere options include\n\nOptions:",
app
);
print_option("bubble-widths", "Bubble intrinsic widths separately like other engines."); print_option(
"bubble-widths",
"Bubble intrinsic widths separately like other engines.",
);
print_option("disable-text-aa", "Disable antialiasing of rendered text."); print_option("disable-text-aa", "Disable antialiasing of rendered text.");
print_option("disable-canvas-aa", "Disable antialiasing on the HTML canvas element."); print_option(
print_option("dump-style-tree", "Print the DOM with computed styles after each restyle."); "disable-canvas-aa",
"Disable antialiasing on the HTML canvas element.",
);
print_option(
"dump-style-tree",
"Print the DOM with computed styles after each restyle.",
);
print_option("dump-flow-tree", "Print the flow tree after each layout."); print_option("dump-flow-tree", "Print the flow tree after each layout.");
print_option("dump-display-list", "Print the display list after each layout."); print_option(
print_option("dump-display-list-json", "Print the display list in JSON form."); "dump-display-list",
print_option("relayout-event", "Print notifications when there is a relayout."); "Print the display list after each layout.",
print_option("profile-script-events", "Enable profiling of script-related events."); );
print_option("profile-heartbeats", "Enable heartbeats for all thread categories."); print_option(
print_option("show-fragment-borders", "Paint borders along fragment boundaries."); "dump-display-list-json",
print_option("show-parallel-layout", "Mark which thread laid each flow out with colors."); "Print the display list in JSON form.",
print_option("trace-layout", "Write layout trace to an external file for debugging."); );
print_option("disable-share-style-cache", print_option(
"Disable the style sharing cache."); "relayout-event",
print_option("parallel-display-list-building", "Build display lists in parallel."); "Print notifications when there is a relayout.",
print_option("convert-mouse-to-touch", "Send touch events instead of mouse events"); );
print_option("replace-surrogates", "Replace unpaires surrogates in DOM strings with U+FFFD. \ print_option(
See https://github.com/servo/servo/issues/6564"); "profile-script-events",
"Enable profiling of script-related events.",
);
print_option(
"profile-heartbeats",
"Enable heartbeats for all thread categories.",
);
print_option(
"show-fragment-borders",
"Paint borders along fragment boundaries.",
);
print_option(
"show-parallel-layout",
"Mark which thread laid each flow out with colors.",
);
print_option(
"trace-layout",
"Write layout trace to an external file for debugging.",
);
print_option(
"disable-share-style-cache",
"Disable the style sharing cache.",
);
print_option(
"parallel-display-list-building",
"Build display lists in parallel.",
);
print_option(
"convert-mouse-to-touch",
"Send touch events instead of mouse events",
);
print_option(
"replace-surrogates",
"Replace unpaires surrogates in DOM strings with U+FFFD. \
See https://github.com/servo/servo/issues/6564",
);
print_option("gc-profile", "Log GC passes and their durations."); print_option("gc-profile", "Log GC passes and their durations.");
print_option("load-webfonts-synchronously", print_option(
"Load web fonts synchronously to avoid non-deterministic network-driven reflows"); "load-webfonts-synchronously",
print_option("disable-vsync", "Load web fonts synchronously to avoid non-deterministic network-driven reflows",
"Disable vsync mode in the compositor to allow profiling at more than monitor refresh rate"); );
print_option(
"disable-vsync",
"Disable vsync mode in the compositor to allow profiling at more than monitor refresh rate",
);
print_option("wr-stats", "Show WebRender profiler on screen."); print_option("wr-stats", "Show WebRender profiler on screen.");
print_option("msaa", "Use multisample antialiasing in WebRender."); print_option("msaa", "Use multisample antialiasing in WebRender.");
print_option("full-backtraces", "Print full backtraces for all errors"); print_option("full-backtraces", "Print full backtraces for all errors");
print_option("wr-debug", "Display webrender tile borders."); print_option("wr-debug", "Display webrender tile borders.");
print_option("wr-no-batch", "Disable webrender instanced batching."); print_option("wr-no-batch", "Disable webrender instanced batching.");
print_option("precache-shaders", "Compile all shaders during init."); print_option("precache-shaders", "Compile all shaders during init.");
print_option("signpost", "Emit native OS signposts for profile events (currently macOS only)"); print_option(
"signpost",
"Emit native OS signposts for profile events (currently macOS only)",
);
println!(""); println!("");
@ -445,7 +498,7 @@ enum UserAgent {
Desktop, Desktop,
Android, Android,
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
iOS iOS,
} }
fn default_user_agent_string(agent: UserAgent) -> &'static str { fn default_user_agent_string(agent: UserAgent) -> &'static str {
@ -468,17 +521,12 @@ fn default_user_agent_string(agent: UserAgent) -> &'static str {
const DESKTOP_UA_STRING: &'static str = const DESKTOP_UA_STRING: &'static str =
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:55.0) Servo/1.0 Firefox/55.0"; "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:55.0) Servo/1.0 Firefox/55.0";
match agent { match agent {
UserAgent::Desktop => { UserAgent::Desktop => DESKTOP_UA_STRING,
DESKTOP_UA_STRING UserAgent::Android => "Mozilla/5.0 (Android; Mobile; rv:55.0) Servo/1.0 Firefox/55.0",
}
UserAgent::Android => {
"Mozilla/5.0 (Android; Mobile; rv:55.0) Servo/1.0 Firefox/55.0"
}
UserAgent::iOS => { UserAgent::iOS => {
"Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X; rv:55.0) Servo/1.0 Firefox/55.0" "Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X; rv:55.0) Servo/1.0 Firefox/55.0"
} },
} }
} }
@ -564,54 +612,146 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult {
opts.optopt("o", "output", "Output file", "output.png"); opts.optopt("o", "output", "Output file", "output.png");
opts.optopt("s", "size", "Size of tiles", "512"); opts.optopt("s", "size", "Size of tiles", "512");
opts.optopt("", "device-pixel-ratio", "Device pixels per px", ""); opts.optopt("", "device-pixel-ratio", "Device pixels per px", "");
opts.optflagopt("p", "profile", "Time profiler flag and either a TSV output filename \ opts.optflagopt(
OR an interval for output to Stdout (blank for Stdout with interval of 5s)", "10 \ "p",
OR time.tsv"); "profile",
opts.optflagopt("", "profiler-trace-path", "Time profiler flag and either a TSV output filename \
"Path to dump a self-contained HTML timeline of profiler traces", OR an interval for output to Stdout (blank for Stdout with interval of 5s)",
""); "10 \
opts.optflagopt("m", "memory-profile", "Memory profiler flag and output interval", "10"); OR time.tsv",
);
opts.optflagopt(
"",
"profiler-trace-path",
"Path to dump a self-contained HTML timeline of profiler traces",
"",
);
opts.optflagopt(
"m",
"memory-profile",
"Memory profiler flag and output interval",
"10",
);
opts.optflag("x", "exit", "Exit after load flag"); opts.optflag("x", "exit", "Exit after load flag");
opts.optopt("y", "layout-threads", "Number of threads to use for layout", "1"); opts.optopt(
opts.optflag("i", "nonincremental-layout", "Enable to turn off incremental layout."); "y",
opts.optflagopt("", "userscripts", "layout-threads",
"Uses userscripts in resources/user-agent-js, or a specified full path", ""); "Number of threads to use for layout",
opts.optmulti("", "user-stylesheet", "1",
"A user stylesheet to be added to every document", "file.css"); );
opts.optopt("", "shaders", opts.optflag(
"Shaders will be loaded from the specified directory instead of using the builtin ones.", ""); "i",
"nonincremental-layout",
"Enable to turn off incremental layout.",
);
opts.optflagopt(
"",
"userscripts",
"Uses userscripts in resources/user-agent-js, or a specified full path",
"",
);
opts.optmulti(
"",
"user-stylesheet",
"A user stylesheet to be added to every document",
"file.css",
);
opts.optopt(
"",
"shaders",
"Shaders will be loaded from the specified directory instead of using the builtin ones.",
"",
);
opts.optflag("z", "headless", "Headless mode"); opts.optflag("z", "headless", "Headless mode");
opts.optflag("f", "hard-fail", "Exit on thread failure instead of displaying about:failure"); opts.optflag(
opts.optflag("F", "soft-fail", "Display about:failure on thread failure instead of exiting"); "f",
opts.optflagopt("", "remote-debugging-port", "Start remote debugger server on port", "2794"); "hard-fail",
opts.optflagopt("", "devtools", "Start remote devtools server on port", "6000"); "Exit on thread failure instead of displaying about:failure",
opts.optflagopt("", "webdriver", "Start remote WebDriver server on port", "7000"); );
opts.optflag(
"F",
"soft-fail",
"Display about:failure on thread failure instead of exiting",
);
opts.optflagopt(
"",
"remote-debugging-port",
"Start remote debugger server on port",
"2794",
);
opts.optflagopt(
"",
"devtools",
"Start remote devtools server on port",
"6000",
);
opts.optflagopt(
"",
"webdriver",
"Start remote WebDriver server on port",
"7000",
);
opts.optopt("", "resolution", "Set window resolution.", "1024x740"); opts.optopt("", "resolution", "Set window resolution.", "1024x740");
opts.optopt("u", opts.optopt(
"user-agent", "u",
"Set custom user agent string (or ios / android / desktop for platform default)", "user-agent",
"NCSA Mosaic/1.0 (X11;SunOS 4.1.4 sun4m)"); "Set custom user agent string (or ios / android / desktop for platform default)",
"NCSA Mosaic/1.0 (X11;SunOS 4.1.4 sun4m)",
);
opts.optflag("M", "multiprocess", "Run in multiprocess mode"); opts.optflag("M", "multiprocess", "Run in multiprocess mode");
opts.optflag("S", "sandbox", "Run in a sandbox if multiprocess"); opts.optflag("S", "sandbox", "Run in a sandbox if multiprocess");
opts.optopt("", opts.optopt(
"random-pipeline-closure-probability", "",
"Probability of randomly closing a pipeline (for testing constellation hardening).", "random-pipeline-closure-probability",
"0.0"); "Probability of randomly closing a pipeline (for testing constellation hardening).",
opts.optopt("", "random-pipeline-closure-seed", "A fixed seed for repeatbility of random pipeline closure.", ""); "0.0",
opts.optmulti("Z", "debug", );
"A comma-separated string of debug options. Pass help to show available options.", ""); opts.optopt(
"",
"random-pipeline-closure-seed",
"A fixed seed for repeatbility of random pipeline closure.",
"",
);
opts.optmulti(
"Z",
"debug",
"A comma-separated string of debug options. Pass help to show available options.",
"",
);
opts.optflag("h", "help", "Print this message"); opts.optflag("h", "help", "Print this message");
opts.optopt("", "resources-path", "Path to find static resources", "/home/servo/resources"); opts.optopt(
opts.optopt("", "certificate-path", "Path to find SSL certificates", "/home/servo/resources/certs"); "",
opts.optopt("", "content-process" , "Run as a content process and connect to the given pipe", "resources-path",
"servo-ipc-channel.abcdefg"); "Path to find static resources",
opts.optmulti("", "pref", "/home/servo/resources",
"A preference to set to enable", "dom.bluetooth.enabled"); );
opts.optopt(
"",
"certificate-path",
"Path to find SSL certificates",
"/home/servo/resources/certs",
);
opts.optopt(
"",
"content-process",
"Run as a content process and connect to the given pipe",
"servo-ipc-channel.abcdefg",
);
opts.optmulti(
"",
"pref",
"A preference to set to enable",
"dom.bluetooth.enabled",
);
opts.optflag("b", "no-native-titlebar", "Do not use native titlebar"); opts.optflag("b", "no-native-titlebar", "Do not use native titlebar");
opts.optflag("w", "webrender", "Use webrender backend"); opts.optflag("w", "webrender", "Use webrender backend");
opts.optopt("G", "graphics", "Select graphics backend (gl or es2)", "gl"); opts.optopt("G", "graphics", "Select graphics backend (gl or es2)", "gl");
opts.optopt("", "config-dir", opts.optopt(
"config directory following xdg spec on linux platform", ""); "",
"config-dir",
"config directory following xdg spec on linux platform",
"",
);
opts.optflag("v", "version", "Display servo version information"); opts.optflag("v", "version", "Display servo version information");
opts.optflag("", "unminify-js", "Unminify Javascript"); opts.optflag("", "unminify-js", "Unminify Javascript");
opts.optopt("", "profiler-db-user", "Profiler database user", ""); opts.optopt("", "profiler-db-user", "Profiler database user", "");
@ -654,44 +794,50 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult {
} else { } else {
None None
}; };
let is_running_problem_test = let is_running_problem_test = url_opt.as_ref().map_or(false, |url| {
url_opt url.starts_with("http://web-platform.test:8000/2dcontext/drawing-images-to-the-canvas/") ||
.as_ref() url.starts_with("http://web-platform.test:8000/_mozilla/mozilla/canvas/") ||
.map_or(false, |url| url.starts_with("http://web-platform.test:8000/_mozilla/css/canvas_over_area.html")
url.starts_with("http://web-platform.test:8000/2dcontext/drawing-images-to-the-canvas/") || });
url.starts_with("http://web-platform.test:8000/_mozilla/mozilla/canvas/") ||
url.starts_with("http://web-platform.test:8000/_mozilla/css/canvas_over_area.html"));
let url_opt = url_opt.and_then(|url_string| parse_url_or_filename(&cwd, url_string) let url_opt = url_opt.and_then(|url_string| {
.or_else(|error| { parse_url_or_filename(&cwd, url_string)
warn!("URL parsing failed ({:?}).", error); .or_else(|error| {
Err(error) warn!("URL parsing failed ({:?}).", error);
}).ok()); Err(error)
}).ok()
});
let tile_size: usize = match opt_match.opt_str("s") { let tile_size: usize = match opt_match.opt_str("s") {
Some(tile_size_str) => tile_size_str.parse() Some(tile_size_str) => tile_size_str
.parse()
.unwrap_or_else(|err| args_fail(&format!("Error parsing option: -s ({})", err))), .unwrap_or_else(|err| args_fail(&format!("Error parsing option: -s ({})", err))),
None => 512, None => 512,
}; };
let device_pixels_per_px = opt_match.opt_str("device-pixel-ratio").map(|dppx_str| let device_pixels_per_px = opt_match.opt_str("device-pixel-ratio").map(|dppx_str| {
dppx_str.parse() dppx_str.parse().unwrap_or_else(|err| {
.unwrap_or_else(|err| args_fail(&format!("Error parsing option: --device-pixel-ratio ({})", err))) args_fail(&format!(
); "Error parsing option: --device-pixel-ratio ({})",
err
))
})
});
// If only the flag is present, default to a 5 second period for both profilers // If only the flag is present, default to a 5 second period for both profilers
let time_profiling = if opt_match.opt_present("p") { let time_profiling = if opt_match.opt_present("p") {
match opt_match.opt_str("p") { match opt_match.opt_str("p") {
Some(argument) => match argument.parse::<f64>() { Some(argument) => match argument.parse::<f64>() {
Ok(interval) => Some(OutputOptions::Stdout(interval)) , Ok(interval) => Some(OutputOptions::Stdout(interval)),
Err(_) => { Err(_) => match ServoUrl::parse(&argument) {
match ServoUrl::parse(&argument) { Ok(url) => Some(OutputOptions::DB(
Ok(url) => Some(OutputOptions::DB(url, opt_match.opt_str("profiler-db-name"), url,
opt_match.opt_str("profiler-db-user"), opt_match.opt_str("profiler-db-name"),
opt_match.opt_str("profiler-db-pass"))), opt_match.opt_str("profiler-db-user"),
Err(_) => Some(OutputOptions::FileName(argument)), opt_match.opt_str("profiler-db-pass"),
} )),
} Err(_) => Some(OutputOptions::FileName(argument)),
},
}, },
None => Some(OutputOptions::Stdout(5.0 as f64)), None => Some(OutputOptions::Stdout(5.0 as f64)),
} }
@ -704,34 +850,50 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult {
let mut path = PathBuf::from(time_profiler_trace_path); let mut path = PathBuf::from(time_profiler_trace_path);
path.pop(); path.pop();
if let Err(why) = fs::create_dir_all(&path) { if let Err(why) = fs::create_dir_all(&path) {
error!("Couldn't create/open {:?}: {:?}", error!(
Path::new(time_profiler_trace_path).to_string_lossy(), why); "Couldn't create/open {:?}: {:?}",
Path::new(time_profiler_trace_path).to_string_lossy(),
why
);
} }
} }
let mem_profiler_period = opt_match.opt_default("m", "5").map(|period| { let mem_profiler_period = opt_match.opt_default("m", "5").map(|period| {
period.parse().unwrap_or_else(|err| args_fail(&format!("Error parsing option: -m ({})", err))) period
.parse()
.unwrap_or_else(|err| args_fail(&format!("Error parsing option: -m ({})", err)))
}); });
let mut layout_threads: Option<usize> = opt_match.opt_str("y") let mut layout_threads: Option<usize> = opt_match.opt_str("y").map(|layout_threads_str| {
.map(|layout_threads_str| { layout_threads_str
layout_threads_str.parse() .parse()
.unwrap_or_else(|err| args_fail(&format!("Error parsing option: -y ({})", err))) .unwrap_or_else(|err| args_fail(&format!("Error parsing option: -y ({})", err)))
}); });
let nonincremental_layout = opt_match.opt_present("i"); let nonincremental_layout = opt_match.opt_present("i");
let random_pipeline_closure_probability = opt_match.opt_str("random-pipeline-closure-probability").map(|prob| let random_pipeline_closure_probability = opt_match
prob.parse().unwrap_or_else(|err| { .opt_str("random-pipeline-closure-probability")
args_fail(&format!("Error parsing option: --random-pipeline-closure-probability ({})", err)) .map(|prob| {
}) prob.parse().unwrap_or_else(|err| {
); args_fail(&format!(
"Error parsing option: --random-pipeline-closure-probability ({})",
err
))
})
});
let random_pipeline_closure_seed = opt_match.opt_str("random-pipeline-closure-seed").map(|seed| let random_pipeline_closure_seed =
seed.parse().unwrap_or_else(|err| { opt_match
args_fail(&format!("Error parsing option: --random-pipeline-closure-seed ({})", err)) .opt_str("random-pipeline-closure-seed")
}) .map(|seed| {
); seed.parse().unwrap_or_else(|err| {
args_fail(&format!(
"Error parsing option: --random-pipeline-closure-seed ({})",
err
))
})
});
let mut bubble_inline_sizes_separately = debug_options.bubble_widths; let mut bubble_inline_sizes_separately = debug_options.bubble_widths;
if debug_options.trace_layout { if debug_options.trace_layout {
@ -739,29 +901,40 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult {
bubble_inline_sizes_separately = true; bubble_inline_sizes_separately = true;
} }
let debugger_port = opt_match.opt_default("remote-debugging-port", "2794").map(|port| { let debugger_port = opt_match
port.parse() .opt_default("remote-debugging-port", "2794")
.unwrap_or_else(|err| args_fail(&format!("Error parsing option: --remote-debugging-port ({})", err))) .map(|port| {
}); port.parse().unwrap_or_else(|err| {
args_fail(&format!(
"Error parsing option: --remote-debugging-port ({})",
err
))
})
});
let devtools_port = opt_match.opt_default("devtools", "6000").map(|port| { let devtools_port = opt_match.opt_default("devtools", "6000").map(|port| {
port.parse().unwrap_or_else(|err| args_fail(&format!("Error parsing option: --devtools ({})", err))) port.parse()
.unwrap_or_else(|err| args_fail(&format!("Error parsing option: --devtools ({})", err)))
}); });
let webdriver_port = opt_match.opt_default("webdriver", "7000").map(|port| { let webdriver_port = opt_match.opt_default("webdriver", "7000").map(|port| {
port.parse().unwrap_or_else(|err| args_fail(&format!("Error parsing option: --webdriver ({})", err))) port.parse().unwrap_or_else(|err| {
args_fail(&format!("Error parsing option: --webdriver ({})", err))
})
}); });
let initial_window_size = match opt_match.opt_str("resolution") { let initial_window_size = match opt_match.opt_str("resolution") {
Some(res_string) => { Some(res_string) => {
let res: Vec<u32> = res_string.split('x').map(|r| { let res: Vec<u32> = res_string
r.parse().unwrap_or_else(|err| args_fail(&format!("Error parsing option: --resolution ({})", err))) .split('x')
}).collect(); .map(|r| {
r.parse().unwrap_or_else(|err| {
args_fail(&format!("Error parsing option: --resolution ({})", err))
})
}).collect();
TypedSize2D::new(res[0], res[1]) TypedSize2D::new(res[0], res[1])
} },
None => { None => TypedSize2D::new(1024, 740),
TypedSize2D::new(1024, 740)
}
}; };
if opt_match.opt_present("M") { if opt_match.opt_present("M") {
@ -776,20 +949,24 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult {
None => default_user_agent_string(DEFAULT_USER_AGENT).into(), None => default_user_agent_string(DEFAULT_USER_AGENT).into(),
}; };
let user_stylesheets = opt_match.opt_strs("user-stylesheet").iter().map(|filename| { let user_stylesheets = opt_match
let path = cwd.join(filename); .opt_strs("user-stylesheet")
let url = ServoUrl::from_url(Url::from_file_path(&path).unwrap()); .iter()
let mut contents = Vec::new(); .map(|filename| {
File::open(path) let path = cwd.join(filename);
.unwrap_or_else(|err| args_fail(&format!("Couldn't open {}: {}", filename, err))) let url = ServoUrl::from_url(Url::from_file_path(&path).unwrap());
.read_to_end(&mut contents) let mut contents = Vec::new();
.unwrap_or_else(|err| args_fail(&format!("Couldn't read {}: {}", filename, err))); File::open(path)
(contents, url) .unwrap_or_else(|err| args_fail(&format!("Couldn't open {}: {}", filename, err)))
}).collect(); .read_to_end(&mut contents)
.unwrap_or_else(|err| args_fail(&format!("Couldn't read {}: {}", filename, err)));
(contents, url)
}).collect();
let do_not_use_native_titlebar = let do_not_use_native_titlebar = opt_match.opt_present("b") || !PREFS
opt_match.opt_present("b") || .get("shell.native-titlebar.enabled")
!PREFS.get("shell.native-titlebar.enabled").as_boolean().unwrap(); .as_boolean()
.unwrap();
let is_printing_version = opt_match.opt_present("v") || opt_match.opt_present("version"); let is_printing_version = opt_match.opt_present("v") || opt_match.opt_present("version");
@ -870,7 +1047,10 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult {
if let Some(layout_threads) = layout_threads { if let Some(layout_threads) = layout_threads {
PREFS.set("layout.threads", PrefValue::Number(layout_threads as f64)); PREFS.set("layout.threads", PrefValue::Number(layout_threads as f64));
} else if let Some(layout_threads) = PREFS.get("layout.threads").as_string() { } else if let Some(layout_threads) = PREFS.get("layout.threads").as_string() {
PREFS.set("layout.threads", PrefValue::Number(layout_threads.parse::<f64>().unwrap())); PREFS.set(
"layout.threads",
PrefValue::Number(layout_threads.parse::<f64>().unwrap()),
);
} else if *PREFS.get("layout.threads") == PrefValue::Missing { } else if *PREFS.get("layout.threads") == PrefValue::Missing {
let layout_threads = cmp::max(num_cpus::get() * 3 / 4, 1); let layout_threads = cmp::max(num_cpus::get() * 3 / 4, 1);
PREFS.set("layout.threads", PrefValue::Number(layout_threads as f64)); PREFS.set("layout.threads", PrefValue::Number(layout_threads as f64));
@ -926,8 +1106,8 @@ pub fn parse_pref_from_command_line(pref: &str) {
Some(&"true") | None => PREFS.set(pref_name, PrefValue::Boolean(true)), Some(&"true") | None => PREFS.set(pref_name, PrefValue::Boolean(true)),
Some(value) => match value.parse::<f64>() { Some(value) => match value.parse::<f64>() {
Ok(v) => PREFS.set(pref_name, PrefValue::Number(v)), Ok(v) => PREFS.set(pref_name, PrefValue::Number(v)),
Err(_) => PREFS.set(pref_name, PrefValue::String(value.to_string())) Err(_) => PREFS.set(pref_name, PrefValue::String(value.to_string())),
} },
}; };
} }
@ -941,7 +1121,7 @@ pub fn parse_url_or_filename(cwd: &Path, input: &str) -> Result<ServoUrl, ()> {
Ok(url) => Ok(url), Ok(url) => Ok(url),
Err(url::ParseError::RelativeUrlWithoutBase) => { Err(url::ParseError::RelativeUrlWithoutBase) => {
Url::from_file_path(&*cwd.join(input)).map(ServoUrl::from_url) Url::from_file_path(&*cwd.join(input)).map(ServoUrl::from_url)
} },
Err(_) => Err(()), Err(_) => Err(()),
} }
} }

View file

@ -30,7 +30,7 @@ pub enum PrefValue {
Boolean(bool), Boolean(bool),
String(String), String(String),
Number(f64), Number(f64),
Missing Missing,
} }
impl PrefValue { impl PrefValue {
@ -41,26 +41,22 @@ impl PrefValue {
Json::F64(x) => PrefValue::Number(x), Json::F64(x) => PrefValue::Number(x),
Json::I64(x) => PrefValue::Number(x as f64), Json::I64(x) => PrefValue::Number(x as f64),
Json::U64(x) => PrefValue::Number(x as f64), Json::U64(x) => PrefValue::Number(x as f64),
_ => return Err(()) _ => return Err(()),
}; };
Ok(value) Ok(value)
} }
pub fn as_boolean(&self) -> Option<bool> { pub fn as_boolean(&self) -> Option<bool> {
match *self { match *self {
PrefValue::Boolean(value) => { PrefValue::Boolean(value) => Some(value),
Some(value) _ => None,
},
_ => None
} }
} }
pub fn as_string(&self) -> Option<&str> { pub fn as_string(&self) -> Option<&str> {
match *self { match *self {
PrefValue::String(ref value) => { PrefValue::String(ref value) => Some(&value),
Some(&value) _ => None,
},
_ => None
} }
} }
@ -82,16 +78,10 @@ impl PrefValue {
impl ToJson for PrefValue { impl ToJson for PrefValue {
fn to_json(&self) -> Json { fn to_json(&self) -> Json {
match *self { match *self {
PrefValue::Boolean(x) => { PrefValue::Boolean(x) => Json::Boolean(x),
Json::Boolean(x) PrefValue::String(ref x) => Json::String(x.clone()),
}, PrefValue::Number(x) => Json::F64(x),
PrefValue::String(ref x) => { PrefValue::Missing => Json::Null,
Json::String(x.clone())
},
PrefValue::Number(x) => {
Json::F64(x)
},
PrefValue::Missing => Json::Null
} }
} }
} }
@ -99,10 +89,9 @@ impl ToJson for PrefValue {
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub enum Pref { pub enum Pref {
NoDefault(Arc<PrefValue>), NoDefault(Arc<PrefValue>),
WithDefault(Arc<PrefValue>, Option<Arc<PrefValue>>) WithDefault(Arc<PrefValue>, Option<Arc<PrefValue>>),
} }
impl Pref { impl Pref {
pub fn new(value: PrefValue) -> Pref { pub fn new(value: PrefValue) -> Pref {
Pref::NoDefault(Arc::new(value)) Pref::NoDefault(Arc::new(value))
@ -120,12 +109,10 @@ impl Pref {
pub fn value(&self) -> &Arc<PrefValue> { pub fn value(&self) -> &Arc<PrefValue> {
match *self { match *self {
Pref::NoDefault(ref x) => x, Pref::NoDefault(ref x) => x,
Pref::WithDefault(ref default, ref override_value) => { Pref::WithDefault(ref default, ref override_value) => match *override_value {
match *override_value { Some(ref x) => x,
Some(ref x) => x, None => default,
None => default },
}
}
} }
} }
@ -133,12 +120,8 @@ impl Pref {
// TODO - this should error if we try to override a pref of one type // TODO - this should error if we try to override a pref of one type
// with a value of a different type // with a value of a different type
match *self { match *self {
Pref::NoDefault(ref mut pref_value) => { Pref::NoDefault(ref mut pref_value) => *pref_value = Arc::new(value),
*pref_value = Arc::new(value) Pref::WithDefault(_, ref mut override_value) => *override_value = Some(Arc::new(value)),
},
Pref::WithDefault(_, ref mut override_value) => {
*override_value = Some(Arc::new(value))
}
} }
} }
} }
@ -151,8 +134,10 @@ impl ToJson for Pref {
pub fn default_prefs() -> Preferences { pub fn default_prefs() -> Preferences {
let prefs = Preferences(Arc::new(RwLock::new(HashMap::new()))); let prefs = Preferences(Arc::new(RwLock::new(HashMap::new())));
prefs.set("layout.threads", PrefValue::Number( prefs.set(
max(num_cpus::get() * 3 / 4, 1) as f64)); "layout.threads",
PrefValue::Number(max(num_cpus::get() * 3 / 4, 1) as f64),
);
prefs prefs
} }
@ -169,7 +154,10 @@ pub fn read_prefs(txt: &str) -> Result<HashMap<String, Pref>, ()> {
Ok(x) => { Ok(x) => {
prefs.insert(name, x); prefs.insert(name, x);
}, },
Err(_) => println!("Ignoring non-boolean/string/i64 preference value for {:?}", name), Err(_) => println!(
"Ignoring non-boolean/string/i64 preference value for {:?}",
name
),
} }
} }
} }
@ -181,14 +169,14 @@ pub fn add_user_prefs() {
Some(ref config_path) => { Some(ref config_path) => {
let mut path = PathBuf::from(config_path); let mut path = PathBuf::from(config_path);
init_user_prefs(&mut path); init_user_prefs(&mut path);
} },
None => { None => {
if let Some(mut path) = default_config_dir() { if let Some(mut path) = default_config_dir() {
if path.join("prefs.json").exists() { if path.join("prefs.json").exists() {
init_user_prefs(&mut path); init_user_prefs(&mut path);
} }
} }
} },
} }
} }
@ -201,8 +189,10 @@ fn init_user_prefs(path: &mut PathBuf) {
PREFS.extend(prefs); PREFS.extend(prefs);
} }
} else { } else {
writeln!(&mut stderr(), "Error opening prefs.json from config directory") writeln!(
.expect("failed printing to stderr"); &mut stderr(),
"Error opening prefs.json from config directory"
).expect("failed printing to stderr");
} }
} }
@ -210,7 +200,11 @@ pub struct Preferences(Arc<RwLock<HashMap<String, Pref>>>);
impl Preferences { impl Preferences {
pub fn get(&self, name: &str) -> Arc<PrefValue> { pub fn get(&self, name: &str) -> Arc<PrefValue> {
self.0.read().unwrap().get(name).map_or(Arc::new(PrefValue::Missing), |x| x.value().clone()) self.0
.read()
.unwrap()
.get(name)
.map_or(Arc::new(PrefValue::Missing), |x| x.value().clone())
} }
pub fn cloned(&self) -> HashMap<String, Pref> { pub fn cloned(&self) -> HashMap<String, Pref> {
@ -244,7 +238,12 @@ impl Preferences {
pub fn reset_all(&self) { pub fn reset_all(&self) {
let names = { let names = {
self.0.read().unwrap().keys().cloned().collect::<Vec<String>>() self.0
.read()
.unwrap()
.keys()
.cloned()
.collect::<Vec<String>>()
}; };
for name in names.iter() { for name in names.iter() {
self.reset(name); self.reset(name);
@ -260,7 +259,9 @@ impl Preferences {
} }
pub fn is_dom_to_texture_enabled(&self) -> bool { pub fn is_dom_to_texture_enabled(&self) -> bool {
self.get("dom.webgl.dom_to_texture.enabled").as_boolean().unwrap_or(false) self.get("dom.webgl.dom_to_texture.enabled")
.as_boolean()
.unwrap_or(false)
} }
pub fn is_webgl2_enabled(&self) -> bool { pub fn is_webgl2_enabled(&self) -> bool {

View file

@ -24,7 +24,10 @@ fn test_argument_parsing() {
let url = parse_url_or_filename(fake_cwd, "file:///foo/bar.html").unwrap(); let url = parse_url_or_filename(fake_cwd, "file:///foo/bar.html").unwrap();
assert_eq!(url.scheme(), "file"); assert_eq!(url.scheme(), "file");
assert_eq!(url.path_segments().unwrap().collect::<Vec<_>>(), ["foo", "bar.html"]); assert_eq!(
url.path_segments().unwrap().collect::<Vec<_>>(),
["foo", "bar.html"]
);
} }
#[test] #[test]
@ -34,7 +37,10 @@ fn test_file_path_parsing() {
let url = parse_url_or_filename(fake_cwd, "bar.html").unwrap(); let url = parse_url_or_filename(fake_cwd, "bar.html").unwrap();
assert_eq!(url.scheme(), "file"); assert_eq!(url.scheme(), "file");
assert_eq!(url.path_segments().unwrap().collect::<Vec<_>>(), ["fake", "cwd", "bar.html"]); assert_eq!(
url.path_segments().unwrap().collect::<Vec<_>>(),
["fake", "cwd", "bar.html"]
);
} }
#[test] #[test]
@ -44,7 +50,10 @@ fn test_file_path_parsing() {
let url = parse_url_or_filename(fake_cwd, "bar.html").unwrap(); let url = parse_url_or_filename(fake_cwd, "bar.html").unwrap();
assert_eq!(url.scheme(), "file"); assert_eq!(url.scheme(), "file");
assert_eq!(url.path_segments().unwrap().collect::<Vec<_>>(), ["C:", "fake", "cwd", "bar.html"]); assert_eq!(
url.path_segments().unwrap().collect::<Vec<_>>(),
["C:", "fake", "cwd", "bar.html"]
);
} }
#[test] #[test]
@ -57,16 +66,24 @@ fn test_argument_parsing_special() {
let url = parse_url_or_filename(fake_cwd, "file:///foo/bar?baz#buzz.html").unwrap(); let url = parse_url_or_filename(fake_cwd, "file:///foo/bar?baz#buzz.html").unwrap();
assert_eq!(&*url.to_file_path().unwrap(), Path::new("/foo/bar")); assert_eq!(&*url.to_file_path().unwrap(), Path::new("/foo/bar"));
assert_eq!(url.scheme(), "file"); assert_eq!(url.scheme(), "file");
assert_eq!(url.path_segments().unwrap().collect::<Vec<_>>(), ["foo", "bar"]); assert_eq!(
url.path_segments().unwrap().collect::<Vec<_>>(),
["foo", "bar"]
);
assert_eq!(url.query(), Some("baz")); assert_eq!(url.query(), Some("baz"));
assert_eq!(url.fragment(), Some("buzz.html")); assert_eq!(url.fragment(), Some("buzz.html"));
// but not in file names. // but not in file names.
let url = parse_url_or_filename(fake_cwd, "./bar?baz#buzz.html").unwrap(); let url = parse_url_or_filename(fake_cwd, "./bar?baz#buzz.html").unwrap();
assert_eq!(&*url.to_file_path().unwrap(), Path::new("/fake/cwd/bar?baz#buzz.html")); assert_eq!(
&*url.to_file_path().unwrap(),
Path::new("/fake/cwd/bar?baz#buzz.html")
);
assert_eq!(url.scheme(), "file"); assert_eq!(url.scheme(), "file");
assert_eq!(url.path_segments().unwrap().collect::<Vec<_>>(), assert_eq!(
["fake", "cwd", "bar%3Fbaz%23buzz.html"]); url.path_segments().unwrap().collect::<Vec<_>>(),
["fake", "cwd", "bar%3Fbaz%23buzz.html"]
);
assert_eq!(url.query(), None); assert_eq!(url.query(), None);
assert_eq!(url.fragment(), None); assert_eq!(url.fragment(), None);
} }

View file

@ -12,10 +12,10 @@ use std::io::{Read, Write};
#[test] #[test]
fn test_create_pref() { fn test_create_pref() {
let json_str = "{\ let json_str = "{\
\"layout.writing-mode.enabled\": true,\ \"layout.writing-mode.enabled\": true,\
\"network.mime.sniff\": false,\ \"network.mime.sniff\": false,\
\"shell.homepage\": \"https://servo.org\"\ \"shell.homepage\": \"https://servo.org\"\
}"; }";
let prefs = read_prefs(json_str); let prefs = read_prefs(json_str);
assert!(prefs.is_ok()); assert!(prefs.is_ok());
@ -27,40 +27,52 @@ fn test_create_pref() {
#[test] #[test]
fn test_get_set_reset_extend() { fn test_get_set_reset_extend() {
let json_str = "{\ let json_str = "{\
\"layout.writing-mode.enabled\": true,\ \"layout.writing-mode.enabled\": true,\
\"extra.stuff\": false,\ \"extra.stuff\": false,\
\"shell.homepage\": \"https://google.com\"\ \"shell.homepage\": \"https://google.com\"\
}"; }";
assert_eq!(*PREFS.get("test"), PrefValue::Missing); assert_eq!(*PREFS.get("test"), PrefValue::Missing);
PREFS.set("test", PrefValue::String("hi".to_owned())); PREFS.set("test", PrefValue::String("hi".to_owned()));
assert_eq!(*PREFS.get("test"), PrefValue::String("hi".to_owned())); assert_eq!(*PREFS.get("test"), PrefValue::String("hi".to_owned()));
assert_eq!(*PREFS.get("shell.homepage"), PrefValue::String("https://servo.org".to_owned())); assert_eq!(
*PREFS.get("shell.homepage"),
PrefValue::String("https://servo.org".to_owned())
);
PREFS.set("shell.homepage", PrefValue::Boolean(true)); PREFS.set("shell.homepage", PrefValue::Boolean(true));
assert_eq!(*PREFS.get("shell.homepage"), PrefValue::Boolean(true)); assert_eq!(*PREFS.get("shell.homepage"), PrefValue::Boolean(true));
PREFS.reset("shell.homepage"); PREFS.reset("shell.homepage");
assert_eq!(*PREFS.get("shell.homepage"), PrefValue::String("https://servo.org".to_owned())); assert_eq!(
*PREFS.get("shell.homepage"),
PrefValue::String("https://servo.org".to_owned())
);
let extension = read_prefs(json_str).unwrap(); let extension = read_prefs(json_str).unwrap();
PREFS.extend(extension); PREFS.extend(extension);
assert_eq!(*PREFS.get("shell.homepage"), PrefValue::String("https://google.com".to_owned())); assert_eq!(
assert_eq!(*PREFS.get("layout.writing-mode.enabled"), PrefValue::Boolean(true)); *PREFS.get("shell.homepage"),
PrefValue::String("https://google.com".to_owned())
);
assert_eq!(
*PREFS.get("layout.writing-mode.enabled"),
PrefValue::Boolean(true)
);
assert_eq!(*PREFS.get("extra.stuff"), PrefValue::Boolean(false)); assert_eq!(*PREFS.get("extra.stuff"), PrefValue::Boolean(false));
} }
#[cfg(not(target_os = "android"))] #[cfg(not(target_os = "android"))]
#[test] #[test]
fn test_default_config_dir_create_read_write() { fn test_default_config_dir_create_read_write() {
let json_str = "{\ let json_str = "{\
\"layout.writing-mode.enabled\": true,\ \"layout.writing-mode.enabled\": true,\
\"extra.stuff\": false,\ \"extra.stuff\": false,\
\"shell.homepage\": \"https://google.com\"\ \"shell.homepage\": \"https://google.com\"\
}"; }";
let mut expected_json = String::new(); let mut expected_json = String::new();
let config_path = basedir::default_config_dir().unwrap(); let config_path = basedir::default_config_dir().unwrap();
if !config_path.exists() { if !config_path.exists() {
fs::create_dir_all(&config_path).unwrap(); fs::create_dir_all(&config_path).unwrap();
} }
let json_path = config_path.join("test_config.json"); let json_path = config_path.join("test_config.json");