Skip to content

Commit

Permalink
Support building for Magic Leap.
Browse files Browse the repository at this point in the history
  • Loading branch information
Alan Jeffrey committed Oct 29, 2018
1 parent e580250 commit dab8f4a
Show file tree
Hide file tree
Showing 34 changed files with 1,601 additions and 7 deletions.
16 changes: 13 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -2,6 +2,7 @@
members = [
"ports/servo",
"ports/libsimpleservo/",
"ports/libmlservo/",
"tests/unit/*",
]
exclude = [".cargo"]
Expand Down
13 changes: 11 additions & 2 deletions components/gfx/platform/freetype/android/font_list.rs
Expand Up @@ -127,7 +127,7 @@ struct FontList {
impl FontList {
fn new() -> FontList {
// Possible paths containing the font mapping xml file.
let paths = ["/etc/fonts.xml", "/system/etc/system_fonts.xml"];
let paths = ["/etc/fonts.xml", "/system/etc/system_fonts.xml", "/package/etc/fonts.xml"];

// Try to load and parse paths until one of them success.
let mut result = None;
Expand All @@ -136,6 +136,10 @@ impl FontList {
!result.is_some()
});

if result.is_none() {
warn!("Couldn't find font list");
}

match result {
Some(result) => result,
// If no xml mapping file is found fallback to some default
Expand Down Expand Up @@ -209,6 +213,7 @@ impl FontList {
let alternatives = [
("sans-serif", "Roboto-Regular.ttf"),
("Droid Sans", "DroidSans.ttf"),
("Lomino", "/system/etc/ml/kali/Fonts/Lomino/Medium/LominoUI_Md.ttf"),
];

alternatives
Expand All @@ -225,7 +230,11 @@ impl FontList {

// All Android fonts are located in /system/fonts
fn font_absolute_path(filename: &str) -> String {
format!("/system/fonts/{}", filename)
if filename.starts_with("/") {
String::from(filename)
} else {
format!("/system/fonts/{}", filename)
}
}

fn find_family(&self, name: &str) -> Option<&FontFamily> {
Expand Down
19 changes: 19 additions & 0 deletions 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"

232 changes: 232 additions & 0 deletions 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) {}
}

0 comments on commit dab8f4a

Please sign in to comment.