mirror of
https://github.com/servo/servo.git
synced 2025-06-17 12:54:28 +00:00
240 lines
7.1 KiB
Rust
240 lines
7.1 KiB
Rust
/* 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/. */
|
|
|
|
//! The `servo` test application.
|
|
//!
|
|
//! Creates a `Browser` instance with a simple implementation of
|
|
//! the compositor's `WindowMethods` to create a working web browser.
|
|
//!
|
|
//! This browser's implementation of `WindowMethods` is built on top
|
|
//! of [glutin], the cross-platform OpenGL utility and windowing
|
|
//! library.
|
|
//!
|
|
//! For the engine itself look next door in lib.rs.
|
|
//!
|
|
//! [glutin]: https://github.com/tomaka/glutin
|
|
|
|
#![feature(start)]
|
|
|
|
#[cfg(target_os = "android")]
|
|
#[macro_use]
|
|
extern crate android_glue;
|
|
extern crate env_logger;
|
|
// The window backed by glutin
|
|
extern crate glutin_app as app;
|
|
#[cfg(target_os = "android")]
|
|
extern crate libc;
|
|
#[cfg(target_os = "android")]
|
|
#[macro_use]
|
|
extern crate log;
|
|
// The Servo engine
|
|
extern crate servo;
|
|
|
|
use servo::Browser;
|
|
use servo::compositing::windowing::WindowEvent;
|
|
use servo::util::opts::{self, ArgumentParsingResult};
|
|
use servo::util::panicking::initiate_panic_hook;
|
|
use std::rc::Rc;
|
|
|
|
fn main() {
|
|
// Parse the command line options and store them globally
|
|
let opts_result = opts::from_cmdline_args(&*args());
|
|
|
|
let content_process_token = if let ArgumentParsingResult::ContentProcess(token) = opts_result {
|
|
Some(token)
|
|
} else {
|
|
if opts::get().is_running_problem_test && ::std::env::var("RUST_LOG").is_err() {
|
|
::std::env::set_var("RUST_LOG", "compositing::constellation");
|
|
}
|
|
|
|
None
|
|
};
|
|
|
|
initiate_panic_hook();
|
|
env_logger::init().unwrap();
|
|
|
|
setup_logging();
|
|
|
|
if let Some(token) = content_process_token {
|
|
return servo::run_content_process(token)
|
|
}
|
|
|
|
let window = app::create_window(None);
|
|
|
|
// Our wrapper around `Browser` that also implements some
|
|
// callbacks required by the glutin window implementation.
|
|
let mut browser = BrowserWrapper {
|
|
browser: Browser::new(window.clone()),
|
|
};
|
|
|
|
register_glutin_resize_handler(&window, &mut browser);
|
|
|
|
browser.browser.handle_events(vec![WindowEvent::InitializeCompositing]);
|
|
|
|
// Feed events from the window to the browser until the browser
|
|
// says to stop.
|
|
loop {
|
|
let should_continue = browser.browser.handle_events(window.wait_events());
|
|
if !should_continue {
|
|
break
|
|
}
|
|
};
|
|
|
|
unregister_glutin_resize_handler(&window);
|
|
}
|
|
|
|
fn register_glutin_resize_handler(window: &Rc<app::window::Window>,
|
|
browser: &mut BrowserWrapper) {
|
|
unsafe {
|
|
window.set_nested_event_loop_listener(browser);
|
|
}
|
|
}
|
|
|
|
fn unregister_glutin_resize_handler(window: &Rc<app::window::Window>) {
|
|
unsafe {
|
|
window.remove_nested_event_loop_listener();
|
|
}
|
|
}
|
|
|
|
struct BrowserWrapper {
|
|
browser: Browser<app::window::Window>,
|
|
}
|
|
|
|
impl app::NestedEventLoopListener for BrowserWrapper {
|
|
fn handle_event_from_nested_event_loop(&mut self, event: WindowEvent) -> bool {
|
|
let is_resize = match event {
|
|
WindowEvent::Resize(..) => true,
|
|
_ => false,
|
|
};
|
|
if !self.browser.handle_events(vec![event]) {
|
|
return false
|
|
}
|
|
if is_resize {
|
|
self.browser.repaint_synchronously()
|
|
}
|
|
true
|
|
}
|
|
}
|
|
|
|
#[cfg(target_os = "android")]
|
|
fn setup_logging() {
|
|
android::setup_logging();
|
|
}
|
|
|
|
#[cfg(not(target_os = "android"))]
|
|
fn setup_logging() {
|
|
}
|
|
|
|
#[cfg(target_os = "android")]
|
|
/// Attempt to read parameters from a file since they are not passed to us in Android environments.
|
|
/// The first line should be the "servo" argument and the last should be the URL to load.
|
|
/// Blank lines and those beginning with a '#' are ignored.
|
|
/// Each line should be a separate parameter as would be parsed by the shell.
|
|
/// For example, "servo -p 10 http://en.wikipedia.org/wiki/Rust" would take 4 lines.
|
|
fn args() -> Vec<String> {
|
|
use std::error::Error;
|
|
use std::fs::File;
|
|
use std::io::{BufRead, BufReader};
|
|
|
|
const PARAMS_FILE: &'static str = "/sdcard/servo/android_params";
|
|
match File::open(PARAMS_FILE) {
|
|
Ok(f) => {
|
|
let mut vec = Vec::new();
|
|
let file = BufReader::new(&f);
|
|
for line in file.lines() {
|
|
let l = line.unwrap().trim().to_owned();
|
|
// ignore blank lines and those that start with a '#'
|
|
match l.is_empty() || l.as_bytes()[0] == b'#' {
|
|
true => (),
|
|
false => vec.push(l),
|
|
}
|
|
}
|
|
vec
|
|
},
|
|
Err(e) => {
|
|
debug!("Failed to open params file '{}': {}", PARAMS_FILE, Error::description(&e));
|
|
vec![
|
|
"servo".to_owned(),
|
|
"http://en.wikipedia.org/wiki/Rust".to_owned()
|
|
]
|
|
},
|
|
}
|
|
}
|
|
|
|
#[cfg(not(target_os = "android"))]
|
|
fn args() -> Vec<String> {
|
|
use std::env;
|
|
env::args().collect()
|
|
}
|
|
|
|
|
|
// This extern definition ensures that the linker will not discard
|
|
// the static native lib bits, which are brought in from the NDK libraries
|
|
// we link in from build.rs.
|
|
#[cfg(target_os = "android")]
|
|
extern {
|
|
fn app_dummy() -> libc::c_void;
|
|
}
|
|
|
|
|
|
// This macro must be used at toplevel because it defines a nested
|
|
// module, but macros can only accept identifiers - not paths -
|
|
// preventing the expansion of this macro within the android module
|
|
// without use of an additionl stub method or other hackery.
|
|
#[cfg(target_os = "android")]
|
|
android_start!(main);
|
|
|
|
#[cfg(target_os = "android")]
|
|
mod android {
|
|
extern crate android_glue;
|
|
extern crate libc;
|
|
|
|
use self::libc::c_int;
|
|
use std::borrow::ToOwned;
|
|
|
|
pub fn setup_logging() {
|
|
use self::libc::{STDERR_FILENO, STDOUT_FILENO};
|
|
//use std::env;
|
|
|
|
//env::set_var("RUST_LOG", "servo,gfx,msg,util,layers,js,std,rt,extra");
|
|
redirect_output(STDERR_FILENO);
|
|
redirect_output(STDOUT_FILENO);
|
|
|
|
unsafe { super::app_dummy(); }
|
|
}
|
|
|
|
struct FilePtr(*mut self::libc::FILE);
|
|
|
|
unsafe impl Send for FilePtr {}
|
|
|
|
fn redirect_output(file_no: c_int) {
|
|
use self::libc::fdopen;
|
|
use self::libc::fgets;
|
|
use self::libc::{pipe, dup2};
|
|
use servo::util::thread::spawn_named;
|
|
use std::ffi::CStr;
|
|
use std::ffi::CString;
|
|
use std::str::from_utf8;
|
|
|
|
unsafe {
|
|
let mut pipes: [c_int; 2] = [ 0, 0 ];
|
|
pipe(pipes.as_mut_ptr());
|
|
dup2(pipes[1], file_no);
|
|
let mode = CString::new("r").unwrap();
|
|
let input_file = FilePtr(fdopen(pipes[0], mode.as_ptr()));
|
|
spawn_named("android-logger".to_owned(), move || {
|
|
static READ_SIZE: usize = 1024;
|
|
let mut read_buffer = vec![0; READ_SIZE];
|
|
let FilePtr(input_file) = input_file;
|
|
loop {
|
|
fgets(read_buffer.as_mut_ptr(), (read_buffer.len() as i32)-1, input_file);
|
|
let c_str = CStr::from_ptr(read_buffer.as_ptr());
|
|
let slice = from_utf8(c_str.to_bytes()).unwrap();
|
|
android_glue::write_log(slice);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
}
|