mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Build MagicLeap port using libsimpleservo.
This commit is contained in:
parent
887333ae82
commit
5b7be2548a
10 changed files with 201 additions and 371 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -2290,10 +2290,10 @@ dependencies = [
|
|||
name = "libmlservo"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"keyboard-types 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libservo 0.0.1",
|
||||
"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)",
|
||||
"simpleservo 0.0.1",
|
||||
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -2319,6 +2319,7 @@ dependencies = [
|
|||
"gfx 0.0.1",
|
||||
"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)",
|
||||
"keyboard-types 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"layout_thread 0.0.1",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"msg 0.0.1",
|
||||
|
|
|
@ -51,6 +51,7 @@ euclid = "0.19"
|
|||
gfx = {path = "../gfx"}
|
||||
gleam = "0.6"
|
||||
ipc-channel = "0.11"
|
||||
keyboard-types = "0.4"
|
||||
layout_thread = {path = "../layout_thread"}
|
||||
log = "0.4"
|
||||
msg = {path = "../msg"}
|
||||
|
|
|
@ -110,6 +110,7 @@ use webrender::{RendererKind, ShaderPrecacheFlags};
|
|||
use webvr::{VRExternalShmemPtr, WebVRCompositorHandler, WebVRThread};
|
||||
|
||||
pub use gleam::gl;
|
||||
pub use keyboard_types;
|
||||
pub use msg::constellation_msg::TopLevelBrowsingContextId as BrowserId;
|
||||
pub use servo_config as config;
|
||||
pub use servo_url as url;
|
||||
|
|
|
@ -13,8 +13,8 @@ test = false
|
|||
bench = false
|
||||
|
||||
[dependencies]
|
||||
keyboard-types = "0.4"
|
||||
libservo = { path = "../../components/servo", features = ["no_static_freetype"] }
|
||||
simpleservo = { path = "../libsimpleservo/api", features = ["no_static_freetype"] }
|
||||
log = "0.4"
|
||||
servo-egl = "0.2"
|
||||
smallvec = "0.6"
|
||||
|
|
|
@ -7,45 +7,24 @@ use egl::egl::EGLDisplay;
|
|||
use egl::egl::EGLSurface;
|
||||
use egl::egl::MakeCurrent;
|
||||
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::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::TypedSize2D;
|
||||
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::keyboard_types::Key;
|
||||
use servo::servo_url::ServoUrl;
|
||||
use servo::webrender_api::DevicePixel;
|
||||
use servo::webrender_api::DevicePoint;
|
||||
use servo::webrender_api::LayoutPixel;
|
||||
use servo::webrender_api::ScrollLocation;
|
||||
use servo::BrowserId;
|
||||
use servo::Servo;
|
||||
use simpleservo::{
|
||||
self, deinit, gl_glue, EventLoopWaker, HostTrait, InitOptions, MouseButton, ServoGlue, SERVO,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
use std::cell::Cell;
|
||||
use std::ffi::CStr;
|
||||
use std::ffi::CString;
|
||||
use std::io::Write;
|
||||
use std::os::raw::c_char;
|
||||
use std::os::raw::c_void;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
@ -90,7 +69,10 @@ pub enum MLKeyType {
|
|||
pub struct MLLogger(extern "C" fn(MLLogLevel, *const c_char));
|
||||
|
||||
#[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)]
|
||||
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;
|
||||
|
||||
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]
|
||||
pub unsafe extern "C" fn init_servo(
|
||||
ctxt: EGLContext,
|
||||
|
@ -109,150 +101,72 @@ pub unsafe extern "C" fn init_servo(
|
|||
app: MLApp,
|
||||
logger: MLLogger,
|
||||
history_update: MLHistoryUpdate,
|
||||
url_update: MLURLUpdate,
|
||||
keyboard: MLKeyboard,
|
||||
url: *const c_char,
|
||||
width: u32,
|
||||
height: u32,
|
||||
hidpi: f32,
|
||||
) -> *mut ServoInstance {
|
||||
// Servo initialization goes here!
|
||||
servo::embedder_traits::resources::set(Box::new(ResourceReaderInstance::new()));
|
||||
let _ = log::set_boxed_logger(Box::new(logger));
|
||||
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 window = Rc::new(WindowInstance {
|
||||
ctxt: ctxt,
|
||||
surf: surf,
|
||||
disp: disp,
|
||||
gl: gl,
|
||||
let gl = gl_glue::egl::init().expect("EGL initialization failure");
|
||||
|
||||
let url = CStr::from_ptr(url).to_str().unwrap_or("about:blank");
|
||||
let opts = InitOptions {
|
||||
args: None,
|
||||
url: Some(url.to_string()),
|
||||
width: width,
|
||||
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");
|
||||
let mut servo = Servo::new(window);
|
||||
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)]);
|
||||
simpleservo::init(opts, gl, wakeup, callbacks).expect("error initializing Servo");
|
||||
|
||||
let result = Box::new(ServoInstance {
|
||||
app: app,
|
||||
browser_id: browser_id,
|
||||
history_update: history_update,
|
||||
keyboard: keyboard,
|
||||
scroll_state: ScrollState::TriggerUp,
|
||||
scroll_scale: TypedScale::new(SCROLL_SCALE / hidpi),
|
||||
servo: servo,
|
||||
shut_down_complete,
|
||||
});
|
||||
Box::into_raw(result)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn heartbeat_servo(servo: *mut ServoInstance) {
|
||||
// Servo heartbeat goes here!
|
||||
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(..) => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
pub unsafe extern "C" fn heartbeat_servo(_servo: *mut ServoInstance) {
|
||||
let _ = call(|s| s.perform_updates());
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn keyboard_servo(
|
||||
servo: *mut ServoInstance,
|
||||
_servo: *mut ServoInstance,
|
||||
key_code: char,
|
||||
key_type: MLKeyType,
|
||||
) {
|
||||
if let Some(servo) = servo.as_mut() {
|
||||
let key = match key_type {
|
||||
MLKeyType::kCharacter => Key::Character([key_code].iter().collect()),
|
||||
MLKeyType::kBackspace => Key::Backspace,
|
||||
MLKeyType::kEnter => Key::Enter,
|
||||
_ => 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?
|
||||
servo.servo.handle_events(vec![
|
||||
WindowEvent::Keyboard(key_down),
|
||||
WindowEvent::Keyboard(key_up),
|
||||
]);
|
||||
}
|
||||
let key = match key_type {
|
||||
MLKeyType::kCharacter => Key::Character([key_code].iter().collect()),
|
||||
MLKeyType::kBackspace => Key::Backspace,
|
||||
MLKeyType::kEnter => Key::Enter,
|
||||
_ => return,
|
||||
};
|
||||
// TODO: can the ML1 generate separate press and release events?
|
||||
let key2 = key.clone();
|
||||
let _ = call(move |s| s.key_down(key2));
|
||||
let _ = call(move |s| s.key_up(key));
|
||||
}
|
||||
|
||||
// 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
|
||||
if let Some(servo) = servo.as_mut() {
|
||||
let point = DevicePoint::new(x, y);
|
||||
let (new_state, window_events) = match servo.scroll_state {
|
||||
ScrollState::TriggerUp => (
|
||||
ScrollState::TriggerUp,
|
||||
vec![WindowEvent::MouseWindowMoveEventClass(point)],
|
||||
),
|
||||
match servo.scroll_state {
|
||||
ScrollState::TriggerUp => {
|
||||
servo.scroll_state = ScrollState::TriggerUp;
|
||||
let _ = call(|s| s.move_mouse(x, y));
|
||||
},
|
||||
ScrollState::TriggerDown(start)
|
||||
if (start - point).square_length() < DRAG_CUTOFF_SQUARED =>
|
||||
{
|
||||
return;
|
||||
}
|
||||
ScrollState::TriggerDown(start) => (
|
||||
ScrollState::TriggerDragging(start, point),
|
||||
vec![
|
||||
WindowEvent::MouseWindowMoveEventClass(point),
|
||||
WindowEvent::Scroll(
|
||||
ScrollLocation::Delta((point - start) * servo.scroll_scale),
|
||||
start.to_i32(),
|
||||
TouchEventType::Down,
|
||||
),
|
||||
],
|
||||
),
|
||||
ScrollState::TriggerDragging(start, prev) => (
|
||||
ScrollState::TriggerDragging(start, point),
|
||||
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);
|
||||
ScrollState::TriggerDown(start) => {
|
||||
servo.scroll_state = ScrollState::TriggerDragging(start, point);
|
||||
let _ = call(|s| s.move_mouse(x, y));
|
||||
let delta = (point - start) * servo.scroll_scale;
|
||||
let start = start.to_i32();
|
||||
let _ = call(|s| s.scroll_start(delta.x, delta.y, start.x, start.y));
|
||||
},
|
||||
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;
|
||||
let start = start.to_i32();
|
||||
let _ = call(|s| s.scroll(delta.x, delta.y, start.x, start.y));
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -312,83 +216,54 @@ pub unsafe extern "C" fn trigger_servo(servo: *mut ServoInstance, x: f32, y: f32
|
|||
// Servo was triggered
|
||||
if let Some(servo) = servo.as_mut() {
|
||||
let point = DevicePoint::new(x, y);
|
||||
let (new_state, window_events) = match servo.scroll_state {
|
||||
ScrollState::TriggerUp if down => (
|
||||
ScrollState::TriggerDown(point),
|
||||
vec![WindowEvent::MouseWindowEventClass(
|
||||
MouseWindowEvent::MouseDown(MouseButton::Left, point),
|
||||
)],
|
||||
),
|
||||
ScrollState::TriggerDown(start) if !down => (
|
||||
ScrollState::TriggerUp,
|
||||
vec![
|
||||
WindowEvent::MouseWindowEventClass(MouseWindowEvent::MouseUp(
|
||||
MouseButton::Left,
|
||||
start,
|
||||
)),
|
||||
WindowEvent::MouseWindowEventClass(MouseWindowEvent::Click(
|
||||
MouseButton::Left,
|
||||
start,
|
||||
)),
|
||||
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),
|
||||
],
|
||||
),
|
||||
match servo.scroll_state {
|
||||
ScrollState::TriggerUp if down => {
|
||||
servo.scroll_state = ScrollState::TriggerDown(point);
|
||||
let _ = call(|s| s.mouse_down(x, y, MouseButton::Left));
|
||||
},
|
||||
ScrollState::TriggerDown(start) if !down => {
|
||||
servo.scroll_state = ScrollState::TriggerUp;
|
||||
let _ = call(|s| s.mouse_up(start.x, start.y, MouseButton::Left));
|
||||
let _ = call(|s| s.click(start.x, start.y));
|
||||
let _ = call(|s| s.move_mouse(start.x, start.y));
|
||||
},
|
||||
ScrollState::TriggerDragging(start, prev) if !down => {
|
||||
servo.scroll_state = ScrollState::TriggerUp;
|
||||
let delta = (point - prev) * servo.scroll_scale;
|
||||
let start = start.to_i32();
|
||||
let _ = call(|s| s.scroll_end(delta.x, delta.y, start.x, start.y));
|
||||
let _ = call(|s| s.mouse_up(x, y, MouseButton::Left));
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
servo.scroll_state = new_state;
|
||||
servo.servo.handle_events(window_events);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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
|
||||
if let Some(servo) = servo.as_mut() {
|
||||
let window_event = if delta == 0 {
|
||||
WindowEvent::Reload(servo.browser_id)
|
||||
} else if delta < 0 {
|
||||
WindowEvent::Navigation(servo.browser_id, TraversalDirection::Back(-delta as usize))
|
||||
} else {
|
||||
WindowEvent::Navigation(
|
||||
servo.browser_id,
|
||||
TraversalDirection::Forward(delta as usize),
|
||||
)
|
||||
};
|
||||
servo.servo.handle_events(vec![window_event]);
|
||||
if delta == 0 {
|
||||
let _ = call(|s| s.reload());
|
||||
} else if delta < 0 {
|
||||
let _ = call(|s| s.go_back());
|
||||
} else {
|
||||
let _ = call(|s| s.go_forward());
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
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)
|
||||
.to_str()
|
||||
.expect("Failed to convert text to UTF-8");
|
||||
let url = ServoUrl::parse(text).unwrap_or_else(|_| {
|
||||
let mut search = ServoUrl::parse("https://duckduckgo.com")
|
||||
.expect("Failed to parse search URL")
|
||||
.into_url();
|
||||
search.query_pairs_mut().append_pair("q", text);
|
||||
ServoUrl::from_url(search)
|
||||
});
|
||||
let window_event = WindowEvent::LoadUrl(servo.browser_id, url);
|
||||
servo.servo.handle_events(vec![window_event]);
|
||||
}
|
||||
pub unsafe extern "C" fn navigate_servo(_servo: *mut ServoInstance, text: *const c_char) {
|
||||
let text = CStr::from_ptr(text)
|
||||
.to_str()
|
||||
.expect("Failed to convert text to UTF-8");
|
||||
let url = ServoUrl::parse(text).unwrap_or_else(|_| {
|
||||
let mut search = ServoUrl::parse("https://duckduckgo.com")
|
||||
.expect("Failed to parse search URL")
|
||||
.into_url();
|
||||
search.query_pairs_mut().append_pair("q", text);
|
||||
ServoUrl::from_url(search)
|
||||
});
|
||||
let _ = call(|s| s.load_uri(url.as_str()));
|
||||
}
|
||||
|
||||
// Some magic numbers for shutdown
|
||||
|
@ -398,44 +273,68 @@ const SHUTDOWN_POLL_INTERVAL: Duration = Duration::from_millis(100);
|
|||
#[no_mangle]
|
||||
pub unsafe extern "C" fn discard_servo(servo: *mut ServoInstance) {
|
||||
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;
|
||||
servo.servo.handle_events(vec![WindowEvent::Quit]);
|
||||
'outer: loop {
|
||||
for (_, msg) in servo.servo.get_events() {
|
||||
if let EmbedderMsg::Shutdown = msg {
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
let _ = call(|s| s.request_shutdown());
|
||||
while !servo.shut_down_complete.get() {
|
||||
let _ = call(|s| s.perform_updates());
|
||||
if Instant::now() > finish {
|
||||
warn!("Incomplete shutdown.");
|
||||
break 'outer;
|
||||
}
|
||||
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 {
|
||||
app: MLApp,
|
||||
browser_id: BrowserId,
|
||||
history_update: MLHistoryUpdate,
|
||||
keyboard: MLKeyboard,
|
||||
servo: Servo<WindowInstance>,
|
||||
scroll_state: ScrollState,
|
||||
scroll_scale: TypedScale<f32, DevicePixel, LayoutPixel>,
|
||||
}
|
||||
|
||||
struct WindowInstance {
|
||||
ctxt: EGLContext,
|
||||
surf: EGLSurface,
|
||||
disp: EGLDisplay,
|
||||
gl: Rc<Gl>,
|
||||
width: u32,
|
||||
height: u32,
|
||||
hidpi: f32,
|
||||
shut_down_complete: Rc<Cell<bool>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
|
@ -445,52 +344,8 @@ enum ScrollState {
|
|||
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;
|
||||
|
||||
impl EventLoopWakerInstance {
|
||||
fn new() -> EventLoopWakerInstance {
|
||||
EventLoopWakerInstance
|
||||
}
|
||||
}
|
||||
|
||||
impl EventLoopWaker for EventLoopWakerInstance {
|
||||
fn clone(&self) -> Box<EventLoopWaker + Send> {
|
||||
Box::new(EventLoopWakerInstance)
|
||||
|
@ -499,47 +354,6 @@ impl EventLoopWaker for EventLoopWakerInstance {
|
|||
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 {
|
||||
fn enabled(&self, metadata: &log::Metadata) -> bool {
|
||||
metadata.level() <= LOG_LEVEL
|
||||
|
|
|
@ -36,3 +36,4 @@ oculusvr = ["libservo/oculusvr"]
|
|||
native-bluetooth = ["libservo/native-bluetooth"]
|
||||
webgl_backtrace = ["libservo/webgl_backtrace"]
|
||||
js_backtrace = ["libservo/js_backtrace"]
|
||||
no_static_freetype = ["libservo/no_static_freetype"]
|
||||
|
|
|
@ -7,14 +7,17 @@ extern crate log;
|
|||
|
||||
pub mod gl_glue;
|
||||
|
||||
pub use servo::script_traits::MouseButton;
|
||||
|
||||
use servo::compositing::windowing::{
|
||||
AnimationState, EmbedderCoordinates, MouseWindowEvent, WindowEvent, WindowMethods,
|
||||
};
|
||||
use servo::embedder_traits::resources::{self, Resource, ResourceReaderMethods};
|
||||
use servo::embedder_traits::EmbedderMsg;
|
||||
use servo::euclid::{TypedPoint2D, TypedScale, TypedSize2D, TypedVector2D};
|
||||
use servo::keyboard_types::{Key, KeyState, KeyboardEvent};
|
||||
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::prefs::{PrefValue, PREFS};
|
||||
use servo::servo_url::ServoUrl;
|
||||
|
@ -308,11 +311,8 @@ impl ServoGlue {
|
|||
pub fn scroll_end(&mut self, dx: f32, dy: f32, x: i32, y: i32) -> Result<(), &'static str> {
|
||||
let delta = TypedVector2D::new(dx, dy);
|
||||
let scroll_location = webrender_api::ScrollLocation::Delta(delta);
|
||||
let event = WindowEvent::Scroll(
|
||||
scroll_location,
|
||||
TypedPoint2D::new(x, y),
|
||||
TouchEventType::Up,
|
||||
);
|
||||
let event =
|
||||
WindowEvent::Scroll(scroll_location, TypedPoint2D::new(x, y), TouchEventType::Up);
|
||||
self.process_event(event)
|
||||
}
|
||||
|
||||
|
@ -397,8 +397,7 @@ impl ServoGlue {
|
|||
|
||||
/// Perform a click.
|
||||
pub fn click(&mut self, x: f32, y: f32) -> Result<(), &'static str> {
|
||||
let mouse_event =
|
||||
MouseWindowEvent::Click(MouseButton::Left, TypedPoint2D::new(x, y));
|
||||
let mouse_event = MouseWindowEvent::Click(MouseButton::Left, TypedPoint2D::new(x, y));
|
||||
let event = WindowEvent::MouseWindowEventClass(mouse_event);
|
||||
self.process_event(event)
|
||||
}
|
||||
|
|
|
@ -455,8 +455,7 @@ impl HostTrait for HostCallbacks {
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
fn on_ime_state_changed(&self, _show: bool) {
|
||||
}
|
||||
fn on_ime_state_changed(&self, _show: bool) {}
|
||||
}
|
||||
|
||||
fn initialize_android_glue(env: &JNIEnv, activity: JObject) {
|
||||
|
|
|
@ -59,7 +59,12 @@ public:
|
|||
/**
|
||||
* 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
|
||||
|
|
|
@ -48,9 +48,15 @@ void logger(MLLogLevel lvl, char* msg) {
|
|||
}
|
||||
|
||||
// A function which updates the history ui, suitable for passing into Servo
|
||||
typedef void (*MLHistoryUpdate)(Servo2D* app, bool canGoBack, char* url, bool canGoForward);
|
||||
void history(Servo2D* app, bool canGoBack, char* url, bool canGoForward) {
|
||||
app->updateHistory(canGoBack, url, canGoForward);
|
||||
typedef void (*MLHistoryUpdate)(Servo2D* app, bool canGoBack, bool canGoForward);
|
||||
void history(Servo2D* app, bool canGoBack, bool 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
|
||||
|
@ -61,7 +67,7 @@ void keyboard(Servo2D* app, bool visible) {
|
|||
|
||||
// The functions Servo provides for hooking up to the ML.
|
||||
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);
|
||||
extern "C" void heartbeat_servo(ServoInstance*);
|
||||
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);
|
||||
|
||||
// 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_) {
|
||||
ML_LOG(Error, "Servo2D Failed to init servo instance");
|
||||
abort();
|
||||
|
@ -401,8 +407,11 @@ bool Servo2D::keyboardEventListener(const lumin::ui::KeyboardEvent::EventData& e
|
|||
return true;
|
||||
}
|
||||
|
||||
void Servo2D::updateHistory(bool canGoBack, const char* url, bool canGoForward) {
|
||||
back_button_->setEnabled(canGoBack);
|
||||
fwd_button_->setEnabled(canGoForward);
|
||||
void Servo2D::updateUrl(const char* url) {
|
||||
url_bar_->setText(url);
|
||||
}
|
||||
|
||||
void Servo2D::updateHistory(bool canGoBack, bool canGoForward) {
|
||||
back_button_->setEnabled(canGoBack);
|
||||
fwd_button_->setEnabled(canGoForward);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue