Auto merge of #22871 - jdm:simpleml, r=ajeffrey,paul

Use simpleservo embedding API for Magic Leap

This removes the duplication between the two ports and makes it easier to improve all of our embeddings simultaneously.

---
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #22065
- [x] These changes do not require tests because no automated tests for embedded devices.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/22871)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2019-03-04 13:46:28 -05:00 committed by GitHub
commit cfb401eea9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 266 additions and 386 deletions

3
Cargo.lock generated
View file

@ -2307,10 +2307,10 @@ dependencies = [
name = "libmlservo" name = "libmlservo"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"keyboard-types 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libservo 0.0.1", "libservo 0.0.1",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"simpleservo 0.0.1",
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -2336,6 +2336,7 @@ dependencies = [
"gfx 0.0.1", "gfx 0.0.1",
"gleam 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
"keyboard-types 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"layout_thread 0.0.1", "layout_thread 0.0.1",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"msg 0.0.1", "msg 0.0.1",

View file

@ -51,6 +51,7 @@ euclid = "0.19"
gfx = {path = "../gfx"} gfx = {path = "../gfx"}
gleam = "0.6" gleam = "0.6"
ipc-channel = "0.11" ipc-channel = "0.11"
keyboard-types = "0.4"
layout_thread = {path = "../layout_thread"} layout_thread = {path = "../layout_thread"}
log = "0.4" log = "0.4"
msg = {path = "../msg"} msg = {path = "../msg"}

View file

@ -112,6 +112,7 @@ use webrender::{RendererKind, ShaderPrecacheFlags};
use webvr::{VRServiceManager, WebVRCompositorHandler, WebVRThread}; use webvr::{VRServiceManager, WebVRCompositorHandler, WebVRThread};
pub use gleam::gl; pub use gleam::gl;
pub use keyboard_types;
pub use msg::constellation_msg::TopLevelBrowsingContextId as BrowserId; pub use msg::constellation_msg::TopLevelBrowsingContextId as BrowserId;
pub use servo_config as config; pub use servo_config as config;
pub use servo_url as url; pub use servo_url as url;

View file

@ -13,8 +13,8 @@ test = false
bench = false bench = false
[dependencies] [dependencies]
keyboard-types = "0.4"
libservo = { path = "../../components/servo", features = ["no_static_freetype"] } libservo = { path = "../../components/servo", features = ["no_static_freetype"] }
simpleservo = { path = "../libsimpleservo/api", features = ["no_static_freetype"] }
log = "0.4" log = "0.4"
servo-egl = "0.2" servo-egl = "0.2"
smallvec = "0.6" smallvec = "0.6"

View file

@ -7,45 +7,24 @@ use egl::egl::EGLDisplay;
use egl::egl::EGLSurface; use egl::egl::EGLSurface;
use egl::egl::MakeCurrent; use egl::egl::MakeCurrent;
use egl::egl::SwapBuffers; use egl::egl::SwapBuffers;
use egl::eglext::eglGetProcAddress;
use keyboard_types::Key;
use keyboard_types::KeyState;
use keyboard_types::KeyboardEvent;
use log::info; use log::info;
use log::warn; use log::warn;
use servo::compositing::windowing::AnimationState;
use servo::compositing::windowing::EmbedderCoordinates;
use servo::compositing::windowing::MouseWindowEvent;
use servo::compositing::windowing::WindowEvent;
use servo::compositing::windowing::WindowMethods;
use servo::embedder_traits::resources::Resource;
use servo::embedder_traits::resources::ResourceReaderMethods;
use servo::embedder_traits::EmbedderMsg;
use servo::embedder_traits::EventLoopWaker;
use servo::euclid::TypedPoint2D;
use servo::euclid::TypedRect;
use servo::euclid::TypedScale; use servo::euclid::TypedScale;
use servo::euclid::TypedSize2D; use servo::keyboard_types::Key;
use servo::gl;
use servo::gl::Gl;
use servo::gl::GlesFns;
use servo::msg::constellation_msg::TraversalDirection;
use servo::script_traits::MouseButton;
use servo::script_traits::TouchEventType;
use servo::servo_url::ServoUrl; use servo::servo_url::ServoUrl;
use servo::webrender_api::DevicePixel; use servo::webrender_api::DevicePixel;
use servo::webrender_api::DevicePoint; use servo::webrender_api::DevicePoint;
use servo::webrender_api::LayoutPixel; use servo::webrender_api::LayoutPixel;
use servo::webrender_api::ScrollLocation; use simpleservo::{
use servo::BrowserId; self, deinit, gl_glue, EventLoopWaker, HostTrait, InitOptions, MouseButton, ServoGlue, SERVO,
use servo::Servo; };
use smallvec::SmallVec; use smallvec::SmallVec;
use std::cell::Cell;
use std::ffi::CStr; use std::ffi::CStr;
use std::ffi::CString; use std::ffi::CString;
use std::io::Write; use std::io::Write;
use std::os::raw::c_char; use std::os::raw::c_char;
use std::os::raw::c_void; use std::os::raw::c_void;
use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
use std::thread; use std::thread;
use std::time::Duration; use std::time::Duration;
@ -90,7 +69,10 @@ pub enum MLKeyType {
pub struct MLLogger(extern "C" fn(MLLogLevel, *const c_char)); pub struct MLLogger(extern "C" fn(MLLogLevel, *const c_char));
#[repr(transparent)] #[repr(transparent)]
pub struct MLHistoryUpdate(extern "C" fn(MLApp, bool, *const c_char, bool)); pub struct MLHistoryUpdate(extern "C" fn(MLApp, bool, bool));
#[repr(transparent)]
pub struct MLURLUpdate(extern "C" fn(MLApp, *const c_char));
#[repr(transparent)] #[repr(transparent)]
pub struct MLKeyboard(extern "C" fn(MLApp, bool)); pub struct MLKeyboard(extern "C" fn(MLApp, bool));
@ -101,6 +83,16 @@ pub struct MLApp(*mut c_void);
const LOG_LEVEL: log::LevelFilter = log::LevelFilter::Info; const LOG_LEVEL: log::LevelFilter = log::LevelFilter::Info;
fn call<F, T>(f: F) -> Result<T, &'static str>
where
F: FnOnce(&mut ServoGlue) -> Result<T, &'static str>,
{
SERVO.with(|s| match s.borrow_mut().as_mut() {
Some(ref mut s) => (f)(s),
None => Err("Servo is not available in this thread"),
})
}
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn init_servo( pub unsafe extern "C" fn init_servo(
ctxt: EGLContext, ctxt: EGLContext,
@ -109,150 +101,72 @@ pub unsafe extern "C" fn init_servo(
app: MLApp, app: MLApp,
logger: MLLogger, logger: MLLogger,
history_update: MLHistoryUpdate, history_update: MLHistoryUpdate,
url_update: MLURLUpdate,
keyboard: MLKeyboard, keyboard: MLKeyboard,
url: *const c_char, url: *const c_char,
width: u32, width: u32,
height: u32, height: u32,
hidpi: f32, hidpi: f32,
) -> *mut ServoInstance { ) -> *mut ServoInstance {
// Servo initialization goes here!
servo::embedder_traits::resources::set(Box::new(ResourceReaderInstance::new()));
let _ = log::set_boxed_logger(Box::new(logger)); let _ = log::set_boxed_logger(Box::new(logger));
log::set_max_level(LOG_LEVEL); log::set_max_level(LOG_LEVEL);
let gl = GlesFns::load_with(|symbol| {
let cstr = CString::new(symbol).expect("Failed to convert GL symbol to a char*");
eglGetProcAddress(cstr.as_ptr() as _) as _
});
info!("OpenGL version {}", gl.get_string(gl::VERSION)); let gl = gl_glue::egl::init().expect("EGL initialization failure");
let window = Rc::new(WindowInstance {
ctxt: ctxt, let url = CStr::from_ptr(url).to_str().unwrap_or("about:blank");
surf: surf, let opts = InitOptions {
disp: disp, args: None,
gl: gl, url: Some(url.to_string()),
width: width, width: width,
height: height, height: height,
hidpi: hidpi, density: hidpi,
enable_subpixel_text_antialiasing: false,
vr_pointer: None,
};
let wakeup = Box::new(EventLoopWakerInstance);
let shut_down_complete = Rc::new(Cell::new(false));
let callbacks = Box::new(HostCallbacks {
app,
ctxt,
surf,
disp,
shut_down_complete: shut_down_complete.clone(),
history_update,
url_update,
keyboard,
}); });
info!("Starting servo"); info!("Starting servo");
let mut servo = Servo::new(window); simpleservo::init(opts, gl, wakeup, callbacks).expect("error initializing Servo");
let browser_id = BrowserId::new();
let blank_url = ServoUrl::parse("about:blank").expect("Failed to parse about:blank!");
let url = CStr::from_ptr(url).to_str().unwrap_or("about:blank");
let url = ServoUrl::parse(url).unwrap_or(blank_url);
servo.handle_events(vec![WindowEvent::NewBrowser(url, browser_id)]);
let result = Box::new(ServoInstance { let result = Box::new(ServoInstance {
app: app,
browser_id: browser_id,
history_update: history_update,
keyboard: keyboard,
scroll_state: ScrollState::TriggerUp, scroll_state: ScrollState::TriggerUp,
scroll_scale: TypedScale::new(SCROLL_SCALE / hidpi), scroll_scale: TypedScale::new(SCROLL_SCALE / hidpi),
servo: servo, shut_down_complete,
}); });
Box::into_raw(result) Box::into_raw(result)
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn heartbeat_servo(servo: *mut ServoInstance) { pub unsafe extern "C" fn heartbeat_servo(_servo: *mut ServoInstance) {
// Servo heartbeat goes here! let _ = call(|s| s.perform_updates());
if let Some(servo) = servo.as_mut() {
servo.servo.handle_events(vec![]);
for (browser_id, event) in servo.servo.get_events() {
match event {
// Respond to any messages with a response channel
// to avoid deadlocking the constellation
EmbedderMsg::AllowNavigationRequest(pipeline_id, _url) => {
if let Some(_browser_id) = browser_id {
let window_event = WindowEvent::AllowNavigationResponse(pipeline_id, true);
servo.servo.handle_events(vec![window_event]);
}
},
EmbedderMsg::GetSelectedBluetoothDevice(_, sender) => {
let _ = sender.send(None);
},
EmbedderMsg::AllowUnload(sender) => {
let _ = sender.send(true);
},
EmbedderMsg::Alert(_, sender) => {
let _ = sender.send(());
},
EmbedderMsg::AllowOpeningBrowser(sender) => {
let _ = sender.send(false);
},
// Update the history UI
EmbedderMsg::HistoryChanged(urls, index) => {
if let Some(url) = urls.get(index) {
if let Ok(cstr) = CString::new(url.as_str()) {
let can_go_back = index > 0;
let can_go_fwd = (index + 1) < urls.len();
(servo.history_update.0)(
servo.app,
can_go_back,
cstr.as_ptr(),
can_go_fwd,
);
}
}
},
EmbedderMsg::ShowIME(..) => (servo.keyboard.0)(servo.app, true),
EmbedderMsg::HideIME => (servo.keyboard.0)(servo.app, false),
// Ignore most messages for now
EmbedderMsg::ChangePageTitle(..) |
EmbedderMsg::BrowserCreated(..) |
EmbedderMsg::LoadStart |
EmbedderMsg::LoadComplete |
EmbedderMsg::CloseBrowser |
EmbedderMsg::Status(..) |
EmbedderMsg::SelectFiles(..) |
EmbedderMsg::MoveTo(..) |
EmbedderMsg::ResizeTo(..) |
EmbedderMsg::Keyboard(..) |
EmbedderMsg::SetCursor(..) |
EmbedderMsg::NewFavicon(..) |
EmbedderMsg::HeadParsed |
EmbedderMsg::SetFullscreenState(..) |
EmbedderMsg::Shutdown |
EmbedderMsg::Panic(..) => {},
}
}
}
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn keyboard_servo( pub unsafe extern "C" fn keyboard_servo(
servo: *mut ServoInstance, _servo: *mut ServoInstance,
key_code: char, key_code: char,
key_type: MLKeyType, key_type: MLKeyType,
) { ) {
if let Some(servo) = servo.as_mut() {
let key = match key_type { let key = match key_type {
MLKeyType::kCharacter => Key::Character([key_code].iter().collect()), MLKeyType::kCharacter => Key::Character([key_code].iter().collect()),
MLKeyType::kBackspace => Key::Backspace, MLKeyType::kBackspace => Key::Backspace,
MLKeyType::kEnter => Key::Enter, MLKeyType::kEnter => Key::Enter,
_ => return, _ => return,
}; };
let key_down = KeyboardEvent {
state: KeyState::Down,
key: key,
..KeyboardEvent::default()
};
let key_up = KeyboardEvent {
state: KeyState::Up,
..key_down.clone()
};
// TODO: can the ML1 generate separate press and release events? // TODO: can the ML1 generate separate press and release events?
servo.servo.handle_events(vec![ let key2 = key.clone();
WindowEvent::Keyboard(key_down), let _ = call(move |s| s.key_down(key2));
WindowEvent::Keyboard(key_up), let _ = call(move |s| s.key_up(key));
]);
}
} }
// Some magic numbers. // Some magic numbers.
@ -269,41 +183,31 @@ pub unsafe extern "C" fn move_servo(servo: *mut ServoInstance, x: f32, y: f32) {
// Servo's cursor was moved // Servo's cursor was moved
if let Some(servo) = servo.as_mut() { if let Some(servo) = servo.as_mut() {
let point = DevicePoint::new(x, y); let point = DevicePoint::new(x, y);
let (new_state, window_events) = match servo.scroll_state { match servo.scroll_state {
ScrollState::TriggerUp => ( ScrollState::TriggerUp => {
ScrollState::TriggerUp, servo.scroll_state = ScrollState::TriggerUp;
vec![WindowEvent::MouseWindowMoveEventClass(point)], let _ = call(|s| s.move_mouse(x, y));
), },
ScrollState::TriggerDown(start) ScrollState::TriggerDown(start)
if (start - point).square_length() < DRAG_CUTOFF_SQUARED => if (start - point).square_length() < DRAG_CUTOFF_SQUARED =>
{ {
return; return;
} }
ScrollState::TriggerDown(start) => ( ScrollState::TriggerDown(start) => {
ScrollState::TriggerDragging(start, point), servo.scroll_state = ScrollState::TriggerDragging(start, point);
vec![ let _ = call(|s| s.move_mouse(x, y));
WindowEvent::MouseWindowMoveEventClass(point), let delta = (point - start) * servo.scroll_scale;
WindowEvent::Scroll( let start = start.to_i32();
ScrollLocation::Delta((point - start) * servo.scroll_scale), let _ = call(|s| s.scroll_start(delta.x, delta.y, start.x, start.y));
start.to_i32(), },
TouchEventType::Down, ScrollState::TriggerDragging(start, prev) => {
), servo.scroll_state = ScrollState::TriggerDragging(start, point);
], let _ = call(|s| s.move_mouse(x, y));
), let delta = (point - prev) * servo.scroll_scale;
ScrollState::TriggerDragging(start, prev) => ( let start = start.to_i32();
ScrollState::TriggerDragging(start, point), let _ = call(|s| s.scroll(delta.x, delta.y, start.x, start.y));
vec![ },
WindowEvent::MouseWindowMoveEventClass(point), }
WindowEvent::Scroll(
ScrollLocation::Delta((point - prev) * servo.scroll_scale),
start.to_i32(),
TouchEventType::Move,
),
],
),
};
servo.scroll_state = new_state;
servo.servo.handle_events(window_events);
} }
} }
@ -312,70 +216,43 @@ pub unsafe extern "C" fn trigger_servo(servo: *mut ServoInstance, x: f32, y: f32
// Servo was triggered // Servo was triggered
if let Some(servo) = servo.as_mut() { if let Some(servo) = servo.as_mut() {
let point = DevicePoint::new(x, y); let point = DevicePoint::new(x, y);
let (new_state, window_events) = match servo.scroll_state { match servo.scroll_state {
ScrollState::TriggerUp if down => ( ScrollState::TriggerUp if down => {
ScrollState::TriggerDown(point), servo.scroll_state = ScrollState::TriggerDown(point);
vec![WindowEvent::MouseWindowEventClass( let _ = call(|s| s.mouse_down(x, y, MouseButton::Left));
MouseWindowEvent::MouseDown(MouseButton::Left, point), },
)], ScrollState::TriggerDown(start) if !down => {
), servo.scroll_state = ScrollState::TriggerUp;
ScrollState::TriggerDown(start) if !down => ( let _ = call(|s| s.mouse_up(start.x, start.y, MouseButton::Left));
ScrollState::TriggerUp, let _ = call(|s| s.click(start.x, start.y));
vec![ let _ = call(|s| s.move_mouse(start.x, start.y));
WindowEvent::MouseWindowEventClass(MouseWindowEvent::MouseUp( },
MouseButton::Left, ScrollState::TriggerDragging(start, prev) if !down => {
start, servo.scroll_state = ScrollState::TriggerUp;
)), let delta = (point - prev) * servo.scroll_scale;
WindowEvent::MouseWindowEventClass(MouseWindowEvent::Click( let start = start.to_i32();
MouseButton::Left, let _ = call(|s| s.scroll_end(delta.x, delta.y, start.x, start.y));
start, let _ = call(|s| s.mouse_up(x, y, MouseButton::Left));
)), },
WindowEvent::MouseWindowMoveEventClass(point),
],
),
ScrollState::TriggerDragging(start, prev) if !down => (
ScrollState::TriggerUp,
vec![
WindowEvent::Scroll(
ScrollLocation::Delta((point - prev) * servo.scroll_scale),
start.to_i32(),
TouchEventType::Up,
),
WindowEvent::MouseWindowEventClass(MouseWindowEvent::MouseUp(
MouseButton::Left,
point,
)),
WindowEvent::MouseWindowMoveEventClass(point),
],
),
_ => return, _ => return,
}; }
servo.scroll_state = new_state;
servo.servo.handle_events(window_events);
} }
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn traverse_servo(servo: *mut ServoInstance, delta: i32) { pub unsafe extern "C" fn traverse_servo(_servo: *mut ServoInstance, delta: i32) {
// Traverse the session history // Traverse the session history
if let Some(servo) = servo.as_mut() { if delta == 0 {
let window_event = if delta == 0 { let _ = call(|s| s.reload());
WindowEvent::Reload(servo.browser_id)
} else if delta < 0 { } else if delta < 0 {
WindowEvent::Navigation(servo.browser_id, TraversalDirection::Back(-delta as usize)) let _ = call(|s| s.go_back());
} else { } else {
WindowEvent::Navigation( let _ = call(|s| s.go_forward());
servo.browser_id,
TraversalDirection::Forward(delta as usize),
)
};
servo.servo.handle_events(vec![window_event]);
} }
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn navigate_servo(servo: *mut ServoInstance, text: *const c_char) { pub unsafe extern "C" fn navigate_servo(_servo: *mut ServoInstance, text: *const c_char) {
if let Some(servo) = servo.as_mut() {
let text = CStr::from_ptr(text) let text = CStr::from_ptr(text)
.to_str() .to_str()
.expect("Failed to convert text to UTF-8"); .expect("Failed to convert text to UTF-8");
@ -386,9 +263,7 @@ pub unsafe extern "C" fn navigate_servo(servo: *mut ServoInstance, text: *const
search.query_pairs_mut().append_pair("q", text); search.query_pairs_mut().append_pair("q", text);
ServoUrl::from_url(search) ServoUrl::from_url(search)
}); });
let window_event = WindowEvent::LoadUrl(servo.browser_id, url); let _ = call(|s| s.load_uri(url.as_str()));
servo.servo.handle_events(vec![window_event]);
}
} }
// Some magic numbers for shutdown // Some magic numbers for shutdown
@ -398,44 +273,68 @@ const SHUTDOWN_POLL_INTERVAL: Duration = Duration::from_millis(100);
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn discard_servo(servo: *mut ServoInstance) { pub unsafe extern "C" fn discard_servo(servo: *mut ServoInstance) {
if let Some(servo) = servo.as_mut() { if let Some(servo) = servo.as_mut() {
let mut servo = Box::from_raw(servo); let servo = Box::from_raw(servo);
let finish = Instant::now() + SHUTDOWN_DURATION; let finish = Instant::now() + SHUTDOWN_DURATION;
servo.servo.handle_events(vec![WindowEvent::Quit]); let _ = call(|s| s.request_shutdown());
'outer: loop { while !servo.shut_down_complete.get() {
for (_, msg) in servo.servo.get_events() { let _ = call(|s| s.perform_updates());
if let EmbedderMsg::Shutdown = msg {
break 'outer;
}
}
if Instant::now() > finish { if Instant::now() > finish {
warn!("Incomplete shutdown."); warn!("Incomplete shutdown.");
break 'outer;
} }
thread::sleep(SHUTDOWN_POLL_INTERVAL); thread::sleep(SHUTDOWN_POLL_INTERVAL);
servo.servo.handle_events(vec![]);
} }
servo.servo.deinit(); deinit();
}
}
struct HostCallbacks {
ctxt: EGLContext,
surf: EGLSurface,
disp: EGLDisplay,
shut_down_complete: Rc<Cell<bool>>,
history_update: MLHistoryUpdate,
url_update: MLURLUpdate,
app: MLApp,
keyboard: MLKeyboard,
}
impl HostTrait for HostCallbacks {
fn flush(&self) {
SwapBuffers(self.disp, self.surf);
}
fn make_current(&self) {
MakeCurrent(self.disp, self.surf, self.surf, self.ctxt);
}
fn on_load_started(&self) {}
fn on_load_ended(&self) {}
fn on_title_changed(&self, _title: String) {}
fn on_url_changed(&self, url: String) {
if let Ok(cstr) = CString::new(url.as_str()) {
(self.url_update.0)(self.app, cstr.as_ptr());
}
}
fn on_history_changed(&self, can_go_back: bool, can_go_forward: bool) {
(self.history_update.0)(self.app, can_go_back, can_go_forward);
}
fn on_animating_changed(&self, _animating: bool) {}
fn on_shutdown_complete(&self) {
self.shut_down_complete.set(true);
}
fn on_ime_state_changed(&self, show: bool) {
(self.keyboard.0)(self.app, show)
} }
} }
pub struct ServoInstance { pub struct ServoInstance {
app: MLApp,
browser_id: BrowserId,
history_update: MLHistoryUpdate,
keyboard: MLKeyboard,
servo: Servo<WindowInstance>,
scroll_state: ScrollState, scroll_state: ScrollState,
scroll_scale: TypedScale<f32, DevicePixel, LayoutPixel>, scroll_scale: TypedScale<f32, DevicePixel, LayoutPixel>,
} shut_down_complete: Rc<Cell<bool>>,
struct WindowInstance {
ctxt: EGLContext,
surf: EGLSurface,
disp: EGLDisplay,
gl: Rc<Gl>,
width: u32,
height: u32,
hidpi: f32,
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -445,52 +344,8 @@ enum ScrollState {
TriggerDragging(DevicePoint, DevicePoint), TriggerDragging(DevicePoint, DevicePoint),
} }
impl WindowMethods for WindowInstance {
fn present(&self) {
SwapBuffers(self.disp, self.surf);
}
fn prepare_for_composite(&self) -> bool {
MakeCurrent(self.disp, self.surf, self.surf, self.ctxt);
true
}
fn gl(&self) -> Rc<Gl> {
self.gl.clone()
}
fn create_event_loop_waker(&self) -> Box<EventLoopWaker> {
Box::new(EventLoopWakerInstance::new())
}
fn get_coordinates(&self) -> EmbedderCoordinates {
EmbedderCoordinates {
hidpi_factor: TypedScale::new(self.hidpi),
screen: TypedSize2D::new(self.width as i32, self.height as i32),
screen_avail: TypedSize2D::new(self.width as i32, self.height as i32),
window: (
TypedSize2D::new(self.width as i32, self.height as i32),
TypedPoint2D::new(0, 0),
),
framebuffer: TypedSize2D::new(self.width as i32, self.height as i32),
viewport: TypedRect::new(
TypedPoint2D::new(0, 0),
TypedSize2D::new(self.width as i32, self.height as i32),
),
}
}
fn set_animation_state(&self, _state: AnimationState) {}
}
struct EventLoopWakerInstance; struct EventLoopWakerInstance;
impl EventLoopWakerInstance {
fn new() -> EventLoopWakerInstance {
EventLoopWakerInstance
}
}
impl EventLoopWaker for EventLoopWakerInstance { impl EventLoopWaker for EventLoopWakerInstance {
fn clone(&self) -> Box<EventLoopWaker + Send> { fn clone(&self) -> Box<EventLoopWaker + Send> {
Box::new(EventLoopWakerInstance) Box::new(EventLoopWakerInstance)
@ -499,47 +354,6 @@ impl EventLoopWaker for EventLoopWakerInstance {
fn wake(&self) {} fn wake(&self) {}
} }
struct ResourceReaderInstance;
impl ResourceReaderInstance {
fn new() -> ResourceReaderInstance {
ResourceReaderInstance
}
}
impl ResourceReaderMethods for ResourceReaderInstance {
fn read(&self, res: Resource) -> Vec<u8> {
Vec::from(match res {
Resource::Preferences => &include_bytes!("../../../resources/prefs.json")[..],
Resource::HstsPreloadList => {
&include_bytes!("../../../resources/hsts_preload.json")[..]
},
Resource::SSLCertificates => &include_bytes!("../../../resources/certs")[..],
Resource::BadCertHTML => &include_bytes!("../../../resources/badcert.html")[..],
Resource::NetErrorHTML => &include_bytes!("../../../resources/neterror.html")[..],
Resource::UserAgentCSS => &include_bytes!("../../../resources/user-agent.css")[..],
Resource::ServoCSS => &include_bytes!("../../../resources/servo.css")[..],
Resource::PresentationalHintsCSS => {
&include_bytes!("../../../resources/presentational-hints.css")[..]
},
Resource::QuirksModeCSS => &include_bytes!("../../../resources/quirks-mode.css")[..],
Resource::RippyPNG => &include_bytes!("../../../resources/rippy.png")[..],
Resource::DomainList => &include_bytes!("../../../resources/public_domains.txt")[..],
Resource::BluetoothBlocklist => {
&include_bytes!("../../../resources/gatt_blocklist.txt")[..]
},
})
}
fn sandbox_access_files(&self) -> Vec<PathBuf> {
vec![]
}
fn sandbox_access_files_dirs(&self) -> Vec<PathBuf> {
vec![]
}
}
impl log::Log for MLLogger { impl log::Log for MLLogger {
fn enabled(&self, metadata: &log::Metadata) -> bool { fn enabled(&self, metadata: &log::Metadata) -> bool {
metadata.level() <= LOG_LEVEL metadata.level() <= LOG_LEVEL

View file

@ -39,3 +39,4 @@ oculusvr = ["libservo/oculusvr"]
native-bluetooth = ["libservo/native-bluetooth"] native-bluetooth = ["libservo/native-bluetooth"]
webgl_backtrace = ["libservo/webgl_backtrace"] webgl_backtrace = ["libservo/webgl_backtrace"]
js_backtrace = ["libservo/js_backtrace"] js_backtrace = ["libservo/js_backtrace"]
no_static_freetype = ["libservo/no_static_freetype"]

View file

@ -7,14 +7,17 @@ extern crate log;
pub mod gl_glue; pub mod gl_glue;
pub use servo::script_traits::MouseButton;
use servo::compositing::windowing::{ use servo::compositing::windowing::{
AnimationState, EmbedderCoordinates, MouseWindowEvent, WindowEvent, WindowMethods, AnimationState, EmbedderCoordinates, MouseWindowEvent, WindowEvent, WindowMethods,
}; };
use servo::embedder_traits::resources::{self, Resource, ResourceReaderMethods}; use servo::embedder_traits::resources::{self, Resource, ResourceReaderMethods};
use servo::embedder_traits::EmbedderMsg; use servo::embedder_traits::EmbedderMsg;
use servo::euclid::{TypedPoint2D, TypedScale, TypedSize2D, TypedVector2D}; use servo::euclid::{TypedPoint2D, TypedScale, TypedSize2D, TypedVector2D};
use servo::keyboard_types::{Key, KeyState, KeyboardEvent};
use servo::msg::constellation_msg::TraversalDirection; use servo::msg::constellation_msg::TraversalDirection;
use servo::script_traits::{MouseButton, TouchEventType, TouchId}; use servo::script_traits::{TouchEventType, TouchId};
use servo::servo_config::opts; use servo::servo_config::opts;
use servo::servo_config::prefs::{PrefValue, PREFS}; use servo::servo_config::prefs::{PrefValue, PREFS};
use servo::servo_url::ServoUrl; use servo::servo_url::ServoUrl;
@ -82,6 +85,8 @@ pub trait HostTrait {
fn on_animating_changed(&self, animating: bool); fn on_animating_changed(&self, animating: bool);
/// Servo finished shutting down. /// Servo finished shutting down.
fn on_shutdown_complete(&self); fn on_shutdown_complete(&self);
/// A text input is focused.
fn on_ime_state_changed(&self, show: bool);
} }
pub struct ServoGlue { pub struct ServoGlue {
@ -276,12 +281,12 @@ impl ServoGlue {
/// Start scrolling. /// Start scrolling.
/// x/y are scroll coordinates. /// x/y are scroll coordinates.
/// dx/dy are scroll deltas. /// dx/dy are scroll deltas.
pub fn scroll_start(&mut self, dx: i32, dy: i32, x: u32, y: u32) -> Result<(), &'static str> { pub fn scroll_start(&mut self, dx: f32, dy: f32, x: i32, y: i32) -> Result<(), &'static str> {
let delta = TypedVector2D::new(dx as f32, dy as f32); let delta = TypedVector2D::new(dx, dy);
let scroll_location = webrender_api::ScrollLocation::Delta(delta); let scroll_location = webrender_api::ScrollLocation::Delta(delta);
let event = WindowEvent::Scroll( let event = WindowEvent::Scroll(
scroll_location, scroll_location,
TypedPoint2D::new(x as i32, y as i32), TypedPoint2D::new(x, y),
TouchEventType::Down, TouchEventType::Down,
); );
self.process_event(event) self.process_event(event)
@ -290,12 +295,12 @@ impl ServoGlue {
/// Scroll. /// Scroll.
/// x/y are scroll coordinates. /// x/y are scroll coordinates.
/// dx/dy are scroll deltas. /// dx/dy are scroll deltas.
pub fn scroll(&mut self, dx: i32, dy: i32, x: u32, y: u32) -> Result<(), &'static str> { pub fn scroll(&mut self, dx: f32, dy: f32, x: i32, y: i32) -> Result<(), &'static str> {
let delta = TypedVector2D::new(dx as f32, dy as f32); let delta = TypedVector2D::new(dx, dy);
let scroll_location = webrender_api::ScrollLocation::Delta(delta); let scroll_location = webrender_api::ScrollLocation::Delta(delta);
let event = WindowEvent::Scroll( let event = WindowEvent::Scroll(
scroll_location, scroll_location,
TypedPoint2D::new(x as i32, y as i32), TypedPoint2D::new(x, y),
TouchEventType::Move, TouchEventType::Move,
); );
self.process_event(event) self.process_event(event)
@ -304,14 +309,11 @@ impl ServoGlue {
/// End scrolling. /// End scrolling.
/// x/y are scroll coordinates. /// x/y are scroll coordinates.
/// dx/dy are scroll deltas. /// dx/dy are scroll deltas.
pub fn scroll_end(&mut self, dx: i32, dy: i32, x: u32, y: u32) -> Result<(), &'static str> { pub fn scroll_end(&mut self, dx: f32, dy: f32, x: i32, y: i32) -> Result<(), &'static str> {
let delta = TypedVector2D::new(dx as f32, dy as f32); let delta = TypedVector2D::new(dx, dy);
let scroll_location = webrender_api::ScrollLocation::Delta(delta); let scroll_location = webrender_api::ScrollLocation::Delta(delta);
let event = WindowEvent::Scroll( let event =
scroll_location, WindowEvent::Scroll(scroll_location, TypedPoint2D::new(x, y), TouchEventType::Up);
TypedPoint2D::new(x as i32, y as i32),
TouchEventType::Up,
);
self.process_event(event) self.process_event(event)
} }
@ -355,6 +357,27 @@ impl ServoGlue {
self.process_event(event) self.process_event(event)
} }
/// Register a mouse movement.
pub fn move_mouse(&mut self, x: f32, y: f32) -> Result<(), &'static str> {
let point = TypedPoint2D::new(x, y);
let event = WindowEvent::MouseWindowMoveEventClass(point);
self.process_event(event)
}
/// Register a mouse button press.
pub fn mouse_down(&mut self, x: f32, y: f32, button: MouseButton) -> Result<(), &'static str> {
let point = TypedPoint2D::new(x, y);
let event = WindowEvent::MouseWindowEventClass(MouseWindowEvent::MouseDown(button, point));
self.process_event(event)
}
/// Register a mouse button release.
pub fn mouse_up(&mut self, x: f32, y: f32, button: MouseButton) -> Result<(), &'static str> {
let point = TypedPoint2D::new(x, y);
let event = WindowEvent::MouseWindowEventClass(MouseWindowEvent::MouseUp(button, point));
self.process_event(event)
}
/// Start pinchzoom. /// Start pinchzoom.
/// x/y are pinch origin coordinates. /// x/y are pinch origin coordinates.
pub fn pinchzoom_start(&mut self, factor: f32, _x: u32, _y: u32) -> Result<(), &'static str> { pub fn pinchzoom_start(&mut self, factor: f32, _x: u32, _y: u32) -> Result<(), &'static str> {
@ -374,13 +397,30 @@ impl ServoGlue {
} }
/// Perform a click. /// Perform a click.
pub fn click(&mut self, x: u32, y: u32) -> Result<(), &'static str> { pub fn click(&mut self, x: f32, y: f32) -> Result<(), &'static str> {
let mouse_event = let mouse_event = MouseWindowEvent::Click(MouseButton::Left, TypedPoint2D::new(x, y));
MouseWindowEvent::Click(MouseButton::Left, TypedPoint2D::new(x as f32, y as f32));
let event = WindowEvent::MouseWindowEventClass(mouse_event); let event = WindowEvent::MouseWindowEventClass(mouse_event);
self.process_event(event) self.process_event(event)
} }
pub fn key_down(&mut self, key: Key) -> Result<(), &'static str> {
let key_event = KeyboardEvent {
state: KeyState::Down,
key,
..KeyboardEvent::default()
};
self.process_event(WindowEvent::Keyboard(key_event))
}
pub fn key_up(&mut self, key: Key) -> Result<(), &'static str> {
let key_event = KeyboardEvent {
state: KeyState::Up,
key,
..KeyboardEvent::default()
};
self.process_event(WindowEvent::Keyboard(key_event))
}
fn process_event(&mut self, event: WindowEvent) -> Result<(), &'static str> { fn process_event(&mut self, event: WindowEvent) -> Result<(), &'static str> {
self.events.push(event); self.events.push(event);
if !self.batch_mode { if !self.batch_mode {

View file

@ -40,6 +40,7 @@ pub struct CHostCallbacks {
pub on_history_changed: extern "C" fn(can_go_back: bool, can_go_forward: bool), pub on_history_changed: extern "C" fn(can_go_back: bool, can_go_forward: bool),
pub on_animating_changed: extern "C" fn(animating: bool), pub on_animating_changed: extern "C" fn(animating: bool),
pub on_shutdown_complete: extern "C" fn(), pub on_shutdown_complete: extern "C" fn(),
pub on_ime_state_changed: extern "C" fn(show: bool),
} }
/// Servo options /// Servo options
@ -191,19 +192,19 @@ pub extern "C" fn go_forward() {
#[no_mangle] #[no_mangle]
pub extern "C" fn scroll_start(dx: i32, dy: i32, x: i32, y: i32) { pub extern "C" fn scroll_start(dx: i32, dy: i32, x: i32, y: i32) {
debug!("scroll_start"); debug!("scroll_start");
call(|s| s.scroll_start(dx as i32, dy as i32, x as u32, y as u32)); call(|s| s.scroll_start(dx as f32, dy as f32, x, y));
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn scroll_end(dx: i32, dy: i32, x: i32, y: i32) { pub extern "C" fn scroll_end(dx: i32, dy: i32, x: i32, y: i32) {
debug!("scroll_end"); debug!("scroll_end");
call(|s| s.scroll_end(dx as i32, dy as i32, x as u32, y as u32)); call(|s| s.scroll_end(dx as f32, dy as f32, x, y));
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn scroll(dx: i32, dy: i32, x: i32, y: i32) { pub extern "C" fn scroll(dx: i32, dy: i32, x: i32, y: i32) {
debug!("scroll"); debug!("scroll");
call(|s| s.scroll(dx as i32, dy as i32, x as u32, y as u32)); call(|s| s.scroll(dx as f32, dy as f32, x, y));
} }
#[no_mangle] #[no_mangle]
@ -251,7 +252,7 @@ pub extern "C" fn pinchzoom_end(factor: f32, x: i32, y: i32) {
#[no_mangle] #[no_mangle]
pub extern "C" fn click(x: i32, y: i32) { pub extern "C" fn click(x: i32, y: i32) {
debug!("click"); debug!("click");
call(|s| s.click(x as u32, y as u32)); call(|s| s.click(x as f32, y as f32));
} }
pub struct WakeupCallback(extern "C" fn()); pub struct WakeupCallback(extern "C" fn());
@ -330,4 +331,9 @@ impl HostTrait for HostCallbacks {
debug!("on_shutdown_complete"); debug!("on_shutdown_complete");
(self.0.on_shutdown_complete)(); (self.0.on_shutdown_complete)();
} }
fn on_ime_state_changed(&self, show: bool) {
debug!("on_ime_state_changed");
(self.0.on_ime_state_changed)(show);
}
} }

View file

@ -200,7 +200,7 @@ pub fn Java_org_mozilla_servoview_JNIServo_scrollStart(
) { ) {
debug!("scrollStart"); debug!("scrollStart");
call(&env, |s| { call(&env, |s| {
s.scroll_start(dx as i32, dy as i32, x as u32, y as u32) s.scroll_start(dx as f32, dy as f32, x as i32, y as i32)
}); });
} }
@ -215,7 +215,7 @@ pub fn Java_org_mozilla_servoview_JNIServo_scrollEnd(
) { ) {
debug!("scrollEnd"); debug!("scrollEnd");
call(&env, |s| { call(&env, |s| {
s.scroll_end(dx as i32, dy as i32, x as u32, y as u32) s.scroll_end(dx as f32, dy as f32, x as i32, y as i32)
}); });
} }
@ -229,7 +229,7 @@ pub fn Java_org_mozilla_servoview_JNIServo_scroll(
y: jint, y: jint,
) { ) {
debug!("scroll"); debug!("scroll");
call(&env, |s| s.scroll(dx as i32, dy as i32, x as u32, y as u32)); call(&env, |s| s.scroll(dx as f32, dy as f32, x as i32, y as i32));
} }
#[no_mangle] #[no_mangle]
@ -321,7 +321,7 @@ pub fn Java_org_mozilla_servoview_JNIServo_pinchZoomEnd(
#[no_mangle] #[no_mangle]
pub fn Java_org_mozilla_servoview_JNIServo_click(env: JNIEnv, _: JClass, x: jint, y: jint) { pub fn Java_org_mozilla_servoview_JNIServo_click(env: JNIEnv, _: JClass, x: jint, y: jint) {
debug!("click"); debug!("click");
call(&env, |s| s.click(x as u32, y as u32)); call(&env, |s| s.click(x as f32, y as f32));
} }
pub struct WakeupCallback { pub struct WakeupCallback {
@ -454,6 +454,8 @@ impl HostTrait for HostCallbacks {
) )
.unwrap(); .unwrap();
} }
fn on_ime_state_changed(&self, _show: bool) {}
} }
fn initialize_android_glue(env: &JNIEnv, activity: JObject) { fn initialize_android_glue(env: &JNIEnv, activity: JObject) {

View file

@ -59,7 +59,12 @@ public:
/** /**
* Update the browser history UI * Update the browser history UI
*/ */
void updateHistory(bool canGoBack, const char* url, bool canGoForward); void updateHistory(bool canGoBack, bool canGoForward);
/**
* Update the browser url bar.
*/
void updateUrl(const char* url);
/** /**
* Make the keyboard visible * Make the keyboard visible

View file

@ -48,9 +48,15 @@ void logger(MLLogLevel lvl, char* msg) {
} }
// A function which updates the history ui, suitable for passing into Servo // A function which updates the history ui, suitable for passing into Servo
typedef void (*MLHistoryUpdate)(Servo2D* app, bool canGoBack, char* url, bool canGoForward); typedef void (*MLHistoryUpdate)(Servo2D* app, bool canGoBack, bool canGoForward);
void history(Servo2D* app, bool canGoBack, char* url, bool canGoForward) { void history(Servo2D* app, bool canGoBack, bool canGoForward) {
app->updateHistory(canGoBack, url, canGoForward); app->updateHistory(canGoBack, canGoForward);
}
// A function which updates the url ui, suitable for passing into Servo
typedef void (*MLURLUpdate)(Servo2D* app, char* url);
void url(Servo2D* app, char* url) {
app->updateUrl(url);
} }
// A function to show or hide the keyboard // A function to show or hide the keyboard
@ -61,7 +67,7 @@ void keyboard(Servo2D* app, bool visible) {
// The functions Servo provides for hooking up to the ML. // The functions Servo provides for hooking up to the ML.
extern "C" ServoInstance* init_servo(EGLContext, EGLSurface, EGLDisplay, extern "C" ServoInstance* init_servo(EGLContext, EGLSurface, EGLDisplay,
Servo2D*, MLLogger, MLHistoryUpdate, MLKeyboard, Servo2D*, MLLogger, MLHistoryUpdate, MLURLUpdate, MLKeyboard,
const char* url, int width, int height, float hidpi); const char* url, int width, int height, float hidpi);
extern "C" void heartbeat_servo(ServoInstance*); extern "C" void heartbeat_servo(ServoInstance*);
extern "C" void keyboard_servo(ServoInstance*, char32_t code, lumin::ui::KeyType keyType); extern "C" void keyboard_servo(ServoInstance*, char32_t code, lumin::ui::KeyType keyType);
@ -165,7 +171,7 @@ int Servo2D::init() {
EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
// Hook into servo // Hook into servo
servo_ = init_servo(ctx, surf, dpy, this, logger, history, keyboard, HOME_PAGE, VIEWPORT_W, VIEWPORT_H, HIDPI); servo_ = init_servo(ctx, surf, dpy, this, logger, history, url, keyboard, HOME_PAGE, VIEWPORT_W, VIEWPORT_H, HIDPI);
if (!servo_) { if (!servo_) {
ML_LOG(Error, "Servo2D Failed to init servo instance"); ML_LOG(Error, "Servo2D Failed to init servo instance");
abort(); abort();
@ -401,8 +407,11 @@ bool Servo2D::keyboardEventListener(const lumin::ui::KeyboardEvent::EventData& e
return true; return true;
} }
void Servo2D::updateHistory(bool canGoBack, const char* url, bool canGoForward) { void Servo2D::updateUrl(const char* url) {
back_button_->setEnabled(canGoBack);
fwd_button_->setEnabled(canGoForward);
url_bar_->setText(url); url_bar_->setText(url);
} }
void Servo2D::updateHistory(bool canGoBack, bool canGoForward) {
back_button_->setEnabled(canGoBack);
fwd_button_->setEnabled(canGoForward);
}