Switch android to glutin.

This commit is contained in:
Glenn Watson 2014-12-11 15:13:26 +10:00
parent 80756a11d2
commit 9d192de63d
8 changed files with 268 additions and 91 deletions

3
.gitmodules vendored
View file

@ -1,3 +1,6 @@
[submodule "tests/wpt/web-platform-tests"] [submodule "tests/wpt/web-platform-tests"]
path = tests/wpt/web-platform-tests path = tests/wpt/web-platform-tests
url = https://github.com/servo/web-platform-tests.git url = https://github.com/servo/web-platform-tests.git
[submodule "support/android-rs-glue"]
path = support/android-rs-glue
url = https://github.com/servo/android-rs-glue

View file

@ -0,0 +1,2 @@
[target.arm-linux-androideabi]
linker = "../../support/android-rs-glue/apk-builder/target/apk-builder"

View file

@ -17,7 +17,7 @@ dependencies = [
[[package]] [[package]]
name = "android_glue" name = "android_glue"
version = "0.0.1" version = "0.0.1"
source = "git+https://github.com/tomaka/android-rs-glue#fe9acb5bd465da1df4561e2bd4ebcc6d305134a4" source = "git+https://github.com/tomaka/android-rs-glue#cac0adb90bc576758f1ebf3b5e567961b1605c1f"
dependencies = [ dependencies = [
"compile_msg 0.1.1 (git+https://github.com/huonw/compile_msg)", "compile_msg 0.1.1 (git+https://github.com/huonw/compile_msg)",
] ]
@ -299,7 +299,7 @@ dependencies = [
[[package]] [[package]]
name = "glutin" name = "glutin"
version = "0.0.2" version = "0.0.2"
source = "git+https://github.com/tomaka/glutin#c95b778e2c077c0b410f366ad3c85a93c40c6095" source = "git+https://github.com/tomaka/glutin#749c47d8c20af078b06e8506b68a54e3799c1a8b"
dependencies = [ dependencies = [
"android_glue 0.0.1 (git+https://github.com/tomaka/android-rs-glue)", "android_glue 0.0.1 (git+https://github.com/tomaka/android-rs-glue)",
"cocoa 0.1.1 (git+https://github.com/servo/rust-cocoa)", "cocoa 0.1.1 (git+https://github.com/servo/rust-cocoa)",

View file

@ -5,103 +5,169 @@
#![comment = "The Servo Parallel Browser Project"] #![comment = "The Servo Parallel Browser Project"]
#![license = "MPL"] #![license = "MPL"]
#![feature(phase)]
#![deny(unused_imports)] #![deny(unused_imports)]
#![deny(unused_variables)] #![deny(unused_variables)]
#[cfg(target_os="android")]
extern crate libc;
extern crate servo; extern crate servo;
extern crate native; extern crate native;
extern crate time; extern crate time;
extern crate "util" as servo_util; extern crate "util" as servo_util;
#[cfg(all(feature = "glutin",not(any(test,target_os="android"))))] #[cfg(all(feature = "glutin",not(test)))]
extern crate "glutin_app" as app; extern crate "glutin_app" as app;
#[cfg(all(feature = "glfw_app",not(any(test,target_os="android"))))] #[cfg(all(feature = "glfw_app",not(test)))]
extern crate "glfw_app" as app; extern crate "glfw_app" as app;
#[cfg(not(any(test,target_os="android")))] #[cfg(not(test))]
extern crate compositing; extern crate compositing;
#[cfg(not(any(test,target_os="android")))] #[cfg(target_os="android")]
#[phase(plugin, link)]
extern crate android_glue;
#[cfg(target_os="android")]
use libc::c_int;
#[cfg(not(test))]
use servo_util::opts; use servo_util::opts;
#[cfg(not(any(test,target_os="android")))] #[cfg(not(test))]
use servo_util::rtinstrument; use servo_util::rtinstrument;
#[cfg(not(any(test,target_os="android")))] #[cfg(not(test))]
use servo::Browser; use servo::Browser;
#[cfg(not(any(test,target_os="android")))] #[cfg(not(test))]
use compositing::windowing::{IdleWindowEvent, InitializeCompositingWindowEvent, ResizeWindowEvent}; use compositing::windowing::{IdleWindowEvent, InitializeCompositingWindowEvent, ResizeWindowEvent};
#[cfg(not(any(test,target_os="android")))] #[cfg(not(test))]
use compositing::windowing::{WindowEvent}; use compositing::windowing::{WindowEvent};
#[cfg(not(any(test,target_os="android")))] #[cfg(not(any(test,target_os="android")))]
use std::os; use std::os;
#[cfg(not(any(test,target_os="android")))] #[cfg(not(test))]
struct BrowserWrapper { struct BrowserWrapper {
browser: Browser<app::window::Window>, browser: Browser<app::window::Window>,
} }
#[cfg(not(any(test,target_os="android")))] #[cfg(target_os="android")]
#[start] android_start!(main)
#[allow(dead_code)]
fn start(argc: int, argv: *const *const u8) -> int {
native::start(argc, argv, proc() {
if opts::from_cmdline_args(os::args().as_slice()) {
let window = if opts::get().headless {
None
} else {
Some(app::create_window())
};
let mut browser = BrowserWrapper { #[cfg(target_os="android")]
browser: Browser::new(window.clone()), fn get_args() -> Vec<String> {
}; vec![
"servo".to_string(),
match window { "http://en.wikipedia.org/wiki/Rust".to_string()
None => {} ]
Some(ref window) => { }
unsafe {
window.set_nested_event_loop_listener(&mut browser); #[cfg(not(target_os="android"))]
} fn get_args() -> Vec<String> {
} os::args()
} }
browser.browser.handle_event(InitializeCompositingWindowEvent); #[cfg(target_os="android")]
fn redirect_output(file_no: c_int) {
loop { use libc::funcs::posix88::unistd::{pipe, dup2};
let should_continue = match window { use libc::funcs::posix88::stdio::fdopen;
None => browser.browser.handle_event(IdleWindowEvent), use libc::c_char;
Some(ref window) => { use libc::funcs::c95::stdio::fgets;
let event = window.wait_events(); use std::mem;
browser.browser.handle_event(event) use std::c_str::CString;
}
}; unsafe {
if !should_continue { let mut pipes: [c_int, ..2] = [ 0, 0 ];
break pipe(pipes.as_mut_ptr());
} dup2(pipes[1], file_no);
} let input_file = "r".with_c_str(|mode| {
fdopen(pipes[0], mode)
match window { });
None => {} spawn(proc() {
Some(ref window) => { loop {
unsafe { let mut read_buffer: [c_char, ..1024] = mem::zeroed();
window.remove_nested_event_loop_listener(); fgets(read_buffer.as_mut_ptr(), read_buffer.len() as i32, input_file);
} let cs = CString::new(read_buffer.as_ptr(), false);
} match cs.as_str() {
} Some(s) => android_glue::write_log(s),
None => {},
let BrowserWrapper { }
browser }
} = browser; });
browser.shutdown(); }
}
rtinstrument::teardown();
} #[cfg(target_os="android")]
}) fn setup_logging() {
use libc::consts::os::posix88::{STDERR_FILENO, STDOUT_FILENO};
//os::setenv("RUST_LOG", "servo,gfx,msg,util,layers,js,glut,std,rt,extra");
redirect_output(STDERR_FILENO);
redirect_output(STDOUT_FILENO);
}
#[cfg(not(target_os="android"))]
fn setup_logging() {
}
fn main() {
if opts::from_cmdline_args(get_args().as_slice()) {
setup_logging();
let window = if opts::get().headless {
None
} else {
Some(app::create_window())
};
let mut browser = BrowserWrapper {
browser: Browser::new(window.clone()),
};
match window {
None => {}
Some(ref window) => {
unsafe {
window.set_nested_event_loop_listener(&mut browser);
}
}
}
browser.browser.handle_event(InitializeCompositingWindowEvent);
loop {
let should_continue = match window {
None => browser.browser.handle_event(IdleWindowEvent),
Some(ref window) => {
let event = window.wait_events();
browser.browser.handle_event(event)
}
};
if !should_continue {
break
}
};
match window {
None => {}
Some(ref window) => {
unsafe {
window.remove_nested_event_loop_listener();
}
}
}
let BrowserWrapper {
browser
} = browser;
browser.shutdown();
rtinstrument::teardown();
}
} }
#[cfg(not(any(test,target_os="android")))]
impl app::NestedEventLoopListener for BrowserWrapper { impl app::NestedEventLoopListener for BrowserWrapper {
fn handle_event_from_nested_event_loop(&mut self, event: WindowEvent) -> bool { fn handle_event_from_nested_event_loop(&mut self, event: WindowEvent) -> bool {
let is_resize = match event { let is_resize = match event {

View file

@ -15,11 +15,11 @@ use compositing::windowing::{Forward, Back};
use geom::point::{Point2D, TypedPoint2D}; use geom::point::{Point2D, TypedPoint2D};
use geom::scale_factor::ScaleFactor; use geom::scale_factor::ScaleFactor;
use geom::size::TypedSize2D; use geom::size::TypedSize2D;
use gleam::gl;
use layers::geometry::DevicePixel; use layers::geometry::DevicePixel;
use layers::platform::surface::NativeGraphicsMetadata; use layers::platform::surface::NativeGraphicsMetadata;
use msg::compositor_msg::{IdlePaintState, PaintState, PaintingPaintState}; use msg::compositor_msg::{IdlePaintState, PaintState, PaintingPaintState};
use msg::compositor_msg::{FinishedLoading, Blank, Loading, PerformingLayout, ReadyState}; use msg::compositor_msg::{FinishedLoading, Blank, Loading, PerformingLayout, ReadyState};
use msg::constellation_msg::LoadData;
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::rc::Rc; use std::rc::Rc;
use time::{mod, Timespec}; use time::{mod, Timespec};
@ -28,14 +28,14 @@ use util::opts::{RenderApi, Mesa, OpenGL};
use glutin; use glutin;
use NestedEventLoopListener; use NestedEventLoopListener;
#[cfg(not(target_os="android"))]
use gleam::gl;
#[cfg(target_os="linux")] #[cfg(target_os="linux")]
use std::ptr; use std::ptr;
struct HeadlessContext { struct HeadlessContext {
// Although currently unused, this context needs to be stored. context: glutin::HeadlessContext,
// Otherwise, its drop() is called, deleting the mesa context
// before it can be used.
_context: glutin::HeadlessContext,
size: TypedSize2D<DevicePixel, uint>, size: TypedSize2D<DevicePixel, uint>,
} }
@ -72,6 +72,28 @@ pub struct Window {
last_title_set_time: Cell<Timespec>, last_title_set_time: Cell<Timespec>,
} }
#[cfg(not(target_os="android"))]
fn load_gl_functions(glutin: &WindowHandle) {
match glutin {
&Windowed(ref window) => gl::load_with(|s| window.get_proc_address(s)),
&Headless(ref headless) => gl::load_with(|s| headless.context.get_proc_address(s)),
}
}
#[cfg(target_os="android")]
fn load_gl_functions(_glutin: &WindowHandle) {
}
#[cfg(not(target_os="android"))]
fn gl_version() -> (uint, uint) {
(3, 0)
}
#[cfg(target_os="android")]
fn gl_version() -> (uint, uint) {
(2, 0)
}
impl Window { impl Window {
/// Creates a new window. /// Creates a new window.
pub fn new(is_foreground: bool, size: TypedSize2D<DevicePixel, uint>, render_api: RenderApi) pub fn new(is_foreground: bool, size: TypedSize2D<DevicePixel, uint>, render_api: RenderApi)
@ -85,14 +107,12 @@ impl Window {
let glutin_window = glutin::WindowBuilder::new() let glutin_window = glutin::WindowBuilder::new()
.with_title("Servo [glutin]".to_string()) .with_title("Servo [glutin]".to_string())
.with_dimensions(window_size.width, window_size.height) .with_dimensions(window_size.width, window_size.height)
.with_gl_version((3, 0)) .with_gl_version(gl_version())
.with_visibility(is_foreground) .with_visibility(is_foreground)
.build() .build()
.unwrap(); .unwrap();
unsafe { glutin_window.make_current() }; unsafe { glutin_window.make_current() };
gl::load_with(|s| glutin_window.get_proc_address(s));
Windowed(glutin_window) Windowed(glutin_window)
} }
Mesa => { Mesa => {
@ -101,15 +121,15 @@ impl Window {
let headless_context = headless_builder.build().unwrap(); let headless_context = headless_builder.build().unwrap();
unsafe { headless_context.make_current() }; unsafe { headless_context.make_current() };
gl::load_with(|s| headless_context.get_proc_address(s));
Headless(HeadlessContext { Headless(HeadlessContext {
_context: headless_context, context: headless_context,
size: size, size: size,
}) })
} }
}; };
load_gl_functions(&glutin);
let window = Window { let window = Window {
glutin: glutin, glutin: glutin,
event_queue: RefCell::new(vec!()), event_queue: RefCell::new(vec!()),
@ -184,6 +204,22 @@ impl WindowMethods for Window {
ScaleFactor(1.0) ScaleFactor(1.0)
} }
fn set_page_title(&self, _: Option<String>) {
// TODO(gw)
}
fn set_page_load_data(&self, _: LoadData) {
// TODO(gw)
}
fn load_end(&self) {
// TODO(gw)
}
fn prepare_for_composite(&self) -> bool {
true
}
#[cfg(target_os="linux")] #[cfg(target_os="linux")]
fn native_metadata(&self) -> NativeGraphicsMetadata { fn native_metadata(&self) -> NativeGraphicsMetadata {
match self.glutin { match self.glutin {
@ -209,6 +245,14 @@ impl WindowMethods for Window {
} }
} }
} }
#[cfg(target_os="android")]
fn native_metadata(&self) -> NativeGraphicsMetadata {
use egl::egl::GetCurrentDisplay;
NativeGraphicsMetadata {
display: GetCurrentDisplay(),
}
}
} }
impl Window { impl Window {
@ -416,7 +460,7 @@ impl Window {
match self.glutin { match self.glutin {
Windowed(ref window) => { Windowed(ref window) => {
let mut close_event = false; let mut close_event = false;
for event in window.poll_events() { for event in window.wait_events() {
close_event = self.handle_window_event(event); close_event = self.handle_window_event(event);
if close_event { if close_event {
break; break;
@ -453,3 +497,48 @@ impl CompositorProxy for GlutinCompositorProxy {
} as Box<CompositorProxy+Send> } as Box<CompositorProxy+Send>
} }
} }
// These functions aren't actually called. They are here as a link
// hack because Skia references them.
#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn glBindVertexArrayOES(_array: uint)
{
unimplemented!()
}
#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn glDeleteVertexArraysOES(_n: int, _arrays: *const ())
{
unimplemented!()
}
#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn glGenVertexArraysOES(_n: int, _arrays: *const ())
{
unimplemented!()
}
#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn glRenderbufferStorageMultisampleIMG(_: int, _: int, _: int, _: int, _: int)
{
unimplemented!()
}
#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn glFramebufferTexture2DMultisampleIMG(_: int, _: int, _: int, _: int, _: int, _: int)
{
unimplemented!()
}
#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn glDiscardFramebufferEXT(_: int, _: int, _: *const ())
{
unimplemented!()
}

View file

@ -46,6 +46,8 @@ class MachCommands(CommandBase):
android = self.config["build"]["android"] android = self.config["build"]["android"]
opts = [] opts = []
features = []
if release: if release:
opts += ["--release"] opts += ["--release"]
if target: if target:
@ -54,8 +56,17 @@ class MachCommands(CommandBase):
opts += ["-j", jobs] opts += ["-j", jobs]
if verbose: if verbose:
opts += ["-v"] opts += ["-v"]
if android:
# Ensure the APK builder submodule has been built first
apk_builder_dir = "support/android-rs-glue"
with cd(path.join(apk_builder_dir, "apk-builder")):
subprocess.call(["cargo", "build"], env=self.build_env())
# FIXME: This can be simplified when glutin becomes the default
# and glfw has been removed.
opts += ["--target", "arm-linux-androideabi", "--no-default-features"]
features += ["glutin"]
features = []
if debug_mozjs or self.config["build"]["debug-mozjs"]: if debug_mozjs or self.config["build"]["debug-mozjs"]:
features += ["script/debugmozjs"] features += ["script/debugmozjs"]
@ -72,16 +83,9 @@ class MachCommands(CommandBase):
env=self.build_env()) env=self.build_env())
env['OPENSSL_PATH'] = path.join(self.android_support_dir(), "openssl-1.0.1j") env['OPENSSL_PATH'] = path.join(self.android_support_dir(), "openssl-1.0.1j")
make_opts = [] status = subprocess.call(
if opts: ["cargo", "build"] + opts,
make_opts += ["CARGO_OPTS=" + " ".join(opts)] env=env, cwd=self.servo_crate())
status = subprocess.call(
["make", "-C", "ports/android"] + make_opts,
env=env)
else:
status = subprocess.call(
["cargo", "build"] + opts,
env=env, cwd=self.servo_crate())
elapsed = time() - build_start elapsed = time() - build_start
print("Build completed in %0.2fs" % elapsed) print("Build completed in %0.2fs" % elapsed)

View file

@ -140,6 +140,18 @@ class CommandBase(object):
if self.config["android"]["toolchain"]: if self.config["android"]["toolchain"]:
env["ANDROID_TOOLCHAIN"] = self.config["android"]["toolchain"] env["ANDROID_TOOLCHAIN"] = self.config["android"]["toolchain"]
# FIXME: These are set because they are the variable names that
# android-rs-glue expects. However, other submodules have makefiles that
# reference the env var names above. Once glutin is enabled and set as
# the default, we could modify the subproject makefiles to use the names
# below and remove the vars above, to avoid duplication.
if "ANDROID_SDK" in env:
env["ANDROID_HOME"] = env["ANDROID_SDK"]
if "ANDROID_NDK" in env:
env["NDK_HOME"] = env["ANDROID_NDK"]
if "ANDROID_TOOLCHAIN" in env:
env["NDK_STANDALONE"] = env["ANDROID_TOOLCHAIN"]
return env return env
def servo_crate(self): def servo_crate(self):

@ -0,0 +1 @@
Subproject commit e59b03e0d74e78852f8658aa038e1ae54758ba69