diff options
author | Alan Jeffrey <ajeffrey@mozilla.com> | 2018-09-12 17:21:51 -0500 |
---|---|---|
committer | Alan Jeffrey <ajeffrey@mozilla.com> | 2018-10-29 08:49:41 -0500 |
commit | dab8f4a97fe8c122d24281ea7c62ccb3c7bba621 (patch) | |
tree | fec6a477145188b9dda3713c8ff8992a2f60b030 /ports/libmlservo | |
parent | e580250d5d99060b0ee8d88e3ff66b6d9ec24050 (diff) | |
download | servo-dab8f4a97fe8c122d24281ea7c62ccb3c7bba621.tar.gz servo-dab8f4a97fe8c122d24281ea7c62ccb3c7bba621.zip |
Support building for Magic Leap.
Diffstat (limited to 'ports/libmlservo')
-rw-r--r-- | ports/libmlservo/Cargo.toml | 19 | ||||
-rw-r--r-- | ports/libmlservo/src/lib.rs | 232 |
2 files changed, 251 insertions, 0 deletions
diff --git a/ports/libmlservo/Cargo.toml b/ports/libmlservo/Cargo.toml new file mode 100644 index 00000000000..793435db093 --- /dev/null +++ b/ports/libmlservo/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "libmlservo" +version = "0.0.1" +authors = ["The Servo Project Developers"] +license = "MPL-2.0" +publish = false + +[lib] +name = "mlservo" +crate-type = ["staticlib"] +test = false +bench = false + +[dependencies] +libservo = { path = "../../components/servo" } +log = "0.4" +servo-egl = "0.2" +smallvec = "0.6" + diff --git a/ports/libmlservo/src/lib.rs b/ports/libmlservo/src/lib.rs new file mode 100644 index 00000000000..109279c7ee2 --- /dev/null +++ b/ports/libmlservo/src/lib.rs @@ -0,0 +1,232 @@ +/* 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/. */ + +extern crate egl; +#[macro_use] extern crate log; +extern crate servo; +extern crate smallvec; + +use egl::eglext::eglGetProcAddress; +use servo::BrowserId; +use servo::Servo; +use servo::compositing::windowing::AnimationState; +use servo::compositing::windowing::EmbedderCoordinates; +use servo::compositing::windowing::WindowEvent; +use servo::compositing::windowing::WindowMethods; +use servo::embedder_traits::EventLoopWaker; +use servo::embedder_traits::resources::Resource; +use servo::embedder_traits::resources::ResourceReaderMethods; +use servo::euclid::Length; +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::servo_url::ServoUrl; +use servo::style_traits::DevicePixel; +use smallvec::SmallVec; +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; + +type EGLContext = *const c_void; +type EGLSurface = *const c_void; +type EGLDisplay = *const c_void; + +type ServoInstance = *mut c_void; + +#[repr(u32)] +pub enum MLLogLevel { + Fatal = 0, + Error = 1, + Warning = 2, + Info = 3, + Debug = 4, + Verbose = 5, +} + +#[repr(transparent)] +pub struct MLLogger(extern "C" fn (MLLogLevel, *const c_char)); + +const LOG_LEVEL: log::LevelFilter = log::LevelFilter::Info; + +#[no_mangle] +pub unsafe extern "C" fn init_servo(_ctxt: EGLContext, + _surf: EGLSurface, + _disp: EGLDisplay, + logger: MLLogger, + url: *const c_char, + width: u32, + height: u32, + hidpi: f32) -> 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::new(gl, width, height, hidpi)); + + info!("Starting servo"); + let mut servo = Box::new(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), + ]); + + Box::into_raw(servo) as ServoInstance +} + +#[no_mangle] +pub unsafe extern "C" fn heartbeat_servo(servo: ServoInstance) { + // Servo heartbeat goes here! + if let Some(servo) = (servo as *mut Servo<WindowInstance>).as_mut() { + servo.handle_events(vec![]); + } +} + +#[no_mangle] +pub unsafe extern "C" fn discard_servo(servo: ServoInstance) { + // Servo drop goes here! + if !servo.is_null() { + Box::from_raw(servo as *mut Servo<WindowInstance>); + } +} + +struct WindowInstance { + gl: Rc<Gl>, + width: u32, + height: u32, + hidpi: f32, +} + +impl WindowInstance { + fn new(gl: Rc<Gl>, width: u32, height: u32, hidpi: f32) -> WindowInstance { + WindowInstance { + gl: gl, + width: width, + height: height, + hidpi: hidpi, + } + } +} + +impl WindowMethods for WindowInstance { + fn present(&self) { + } + + fn prepare_for_composite(&self, _w: Length<u32, DevicePixel>, _h: Length<u32, DevicePixel>) -> bool { + 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, self.height), + screen_avail: TypedSize2D::new(self.width, self.height), + window: (TypedSize2D::new(self.width, self.height), TypedPoint2D::new(0, 0)), + framebuffer: TypedSize2D::new(self.width, self.height), + viewport: TypedRect::new(TypedPoint2D::new(0, 0), TypedSize2D::new(self.width, self.height)), + } + } + + 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) + } + + 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 + } + + fn log(&self, record: &log::Record) { + let lvl = match record.level() { + log::Level::Error => MLLogLevel::Error, + log::Level::Warn => MLLogLevel::Warning, + log::Level::Info => MLLogLevel::Info, + log::Level::Debug => MLLogLevel::Debug, + log::Level::Trace => MLLogLevel::Verbose, + }; + let mut msg = SmallVec::<[c_char; 128]>::new(); + write!(msg, "{}\0", record.args()); + (self.0)(lvl, &msg[0] as *const _ as *const _); + } + + fn flush(&self) {} +} |