diff --git a/ports/cef/browser.rs b/ports/cef/browser.rs index a0d0032d430..2092f4cf824 100644 --- a/ports/cef/browser.rs +++ b/ports/cef/browser.rs @@ -3,9 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use browser_host::{ServoCefBrowserHost, ServoCefBrowserHostExtensions}; -use core::{mod, ServoCefGlobals, globals}; use eutil::Downcast; -use frame::ServoCefFrame; +use frame::{ServoCefFrame, ServoCefFrameExtensions}; use interfaces::{CefBrowser, CefBrowserHost, CefClient, CefFrame, CefRequestContext}; use interfaces::{cef_browser_t, cef_browser_host_t, cef_client_t, cef_frame_t}; use interfaces::{cef_request_context_t}; @@ -19,18 +18,52 @@ use libc::c_int; use servo_util::opts; use std::cell::{Cell, RefCell}; +thread_local!(pub static BROWSERS: RefCell> = RefCell::new(vec!())) + +pub enum ServoBrowser { + Invalid, + OnScreen(Browser), + OffScreen(Browser), +} + +impl ServoBrowser { + fn handle_event(&mut self, event: WindowEvent) { + match *self { + ServoBrowser::OnScreen(ref mut browser) => { browser.handle_event(event); } + ServoBrowser::OffScreen(ref mut browser) => { browser.handle_event(event); } + ServoBrowser::Invalid => {} + } + } + + pub fn get_title_for_main_frame(&self) { + match *self { + ServoBrowser::OnScreen(ref browser) => browser.get_title_for_main_frame(), + ServoBrowser::OffScreen(ref browser) => browser.get_title_for_main_frame(), + ServoBrowser::Invalid => {} + } + } + + pub fn pinch_zoom_level(&self) -> f32 { + match *self { + ServoBrowser::OnScreen(ref browser) => browser.pinch_zoom_level(), + ServoBrowser::OffScreen(ref browser) => browser.pinch_zoom_level(), + ServoBrowser::Invalid => 1.0, + } + } +} + cef_class_impl! { ServoCefBrowser : CefBrowser, cef_browser_t { fn get_host(&this) -> *mut cef_browser_host_t { this.downcast().host.clone() } - fn go_back(&_this) -> () { - core::send_window_event(WindowEvent::Navigation(WindowNavigateMsg::Back)); + fn go_back(&this) -> () { + this.send_window_event(WindowEvent::Navigation(WindowNavigateMsg::Back)); } - fn go_forward(&_this) -> () { - core::send_window_event(WindowEvent::Navigation(WindowNavigateMsg::Forward)); + fn go_forward(&this) -> () { + this.send_window_event(WindowEvent::Navigation(WindowNavigateMsg::Forward)); } // Returns the main (top-level) frame for the browser window. @@ -49,53 +82,93 @@ pub struct ServoCefBrowser { pub client: CefClient, /// Whether the on-created callback has fired yet. pub callback_executed: Cell, + + servo_browser: RefCell, + message_queue: RefCell>, } impl ServoCefBrowser { pub fn new(window_info: &cef_window_info_t, client: CefClient) -> ServoCefBrowser { let frame = ServoCefFrame::new().as_cef_interface(); let host = ServoCefBrowserHost::new(client.clone()).as_cef_interface(); - if window_info.windowless_rendering_enabled == 0 { - globals.with(|ref r| { - let glfw_window = glfw_app::create_window(); - *r.borrow_mut() = Some(ServoCefGlobals::OnScreenGlobals( - RefCell::new(glfw_window.clone()), - RefCell::new(Browser::new(Some(glfw_window))))); - }); - } + + let servo_browser = if window_info.windowless_rendering_enabled == 0 { + let glfw_window = glfw_app::create_window(); + let servo_browser = Browser::new(Some(glfw_window.clone())); + ServoBrowser::OnScreen(servo_browser) + } else { + ServoBrowser::Invalid + }; ServoCefBrowser { frame: frame, host: host, client: client, callback_executed: Cell::new(false), + servo_browser: RefCell::new(servo_browser), + message_queue: RefCell::new(vec!()), } } } -trait ServoCefBrowserExtensions { +pub trait ServoCefBrowserExtensions { fn init(&self, window_info: &cef_window_info_t); + fn send_window_event(&self, event: WindowEvent); + fn get_title_for_main_frame(&self); + fn pinch_zoom_level(&self) -> f32; } impl ServoCefBrowserExtensions for CefBrowser { fn init(&self, window_info: &cef_window_info_t) { if window_info.windowless_rendering_enabled != 0 { - globals.with(|ref r| { - let window = window::Window::new(); - let servo_browser = Browser::new(Some(window.clone())); - window.set_browser(self.clone()); - - *r.borrow_mut() = Some(ServoCefGlobals::OffScreenGlobals( - RefCell::new(window), - RefCell::new(servo_browser))); - }); + let window = window::Window::new(); + let servo_browser = Browser::new(Some(window.clone())); + window.set_browser(self.clone()); + *self.downcast().servo_browser.borrow_mut() = ServoBrowser::OffScreen(servo_browser); } self.downcast().host.set_browser((*self).clone()); + self.downcast().frame.set_browser((*self).clone()); + } + + fn send_window_event(&self, event: WindowEvent) { + self.downcast().message_queue.borrow_mut().push(event); + + loop { + match self.downcast().servo_browser.try_borrow_mut() { + None => { + // We're trying to send an event while processing another one. This will + // cause general badness, so queue up that event instead of immediately + // processing it. + break + } + Some(ref mut browser) => { + let event = match self.downcast().message_queue.borrow_mut().pop() { + None => return, + Some(event) => event, + }; + browser.handle_event(event); + } + } + } + } + + fn get_title_for_main_frame(&self) { + self.downcast().servo_browser.borrow().get_title_for_main_frame() + } + + fn pinch_zoom_level(&self) -> f32 { + self.downcast().servo_browser.borrow().pinch_zoom_level() } } -thread_local!(pub static GLOBAL_BROWSERS: RefCell> = RefCell::new(vec!())) +pub fn update() { + BROWSERS.with(|browsers| { + for browser in browsers.borrow().iter() { + browser.send_window_event(WindowEvent::Idle); + } + }); +} pub fn browser_callback_after_created(browser: CefBrowser) { if browser.downcast().client.is_null_cef_object() { @@ -122,7 +195,9 @@ fn browser_host_create(window_info: &cef_window_info_t, if callback_executed { browser_callback_after_created(browser.clone()); } - GLOBAL_BROWSERS.with(|ref r| r.borrow_mut().push(browser.clone())); + BROWSERS.with(|browsers| { + browsers.borrow_mut().push(browser.clone()); + }); browser } diff --git a/ports/cef/browser_host.rs b/ports/cef/browser_host.rs index 403090bd424..7bfd0581ec7 100644 --- a/ports/cef/browser_host.rs +++ b/ports/cef/browser_host.rs @@ -2,11 +2,11 @@ * 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/. */ -use core; use eutil::Downcast; use interfaces::{CefBrowser, CefBrowserHost, CefClient, cef_browser_host_t, cef_client_t}; use types::{cef_mouse_button_type_t, cef_mouse_event, cef_rect_t, cef_key_event}; use types::cef_key_event_type_t::{KEYEVENT_CHAR, KEYEVENT_KEYDOWN, KEYEVENT_KEYUP, KEYEVENT_RAWKEYDOWN}; +use browser::ServoCefBrowserExtensions; use compositing::windowing::{WindowEvent, MouseWindowEvent}; use geom::point::TypedPoint2D; @@ -34,11 +34,20 @@ cef_class_impl! { .get_render_handler() .get_backing_rect(this.downcast().browser.borrow().clone().unwrap(), &mut rect); let size = TypedSize2D(rect.width as uint, rect.height as uint); - core::send_window_event(WindowEvent::Resize(size)); - core::repaint_synchronously(); + this.downcast().send_window_event(WindowEvent::Resize(size)); } - fn send_key_event(&_this, event: *const cef_key_event) -> () { + fn close_browser(&_this, _force: c_int) -> () { + // TODO: Clean shutdown. + } + + fn send_focus_event(&this, focus: c_int) -> () { + if focus != 0 { + this.downcast().send_window_event(WindowEvent::Refresh); + } + } + + fn send_key_event(&this, event: *const cef_key_event) -> () { // FIXME(pcwalton): So awful. But it's nearly midnight here and I have to get // Google working. let event: &cef_key_event = event; @@ -88,10 +97,10 @@ cef_class_impl! { KEYEVENT_KEYUP => KeyState::Released, }; let key_modifiers = KeyModifiers::empty(); // TODO(pcwalton) - core::send_window_event(WindowEvent::KeyEvent(key, key_state, key_modifiers)) + this.downcast().send_window_event(WindowEvent::KeyEvent(key, key_state, key_modifiers)) } - fn send_mouse_click_event(&_this, + fn send_mouse_click_event(&this, event: *const cef_mouse_event, mouse_button_type: cef_mouse_button_type_t, mouse_up: c_int, @@ -101,22 +110,22 @@ cef_class_impl! { let button_type = mouse_button_type as uint; let point = TypedPoint2D((*event).x as f32, (*event).y as f32); if mouse_up != 0 { - core::send_window_event(WindowEvent::MouseWindowEventClass( + this.downcast().send_window_event(WindowEvent::MouseWindowEventClass( MouseWindowEvent::Click(button_type, point))) } else { - core::send_window_event(WindowEvent::MouseWindowEventClass( + this.downcast().send_window_event(WindowEvent::MouseWindowEventClass( MouseWindowEvent::MouseUp(button_type, point))) } } - fn send_mouse_move_event(&_this, event: *const cef_mouse_event, _mouse_exited: c_int) + fn send_mouse_move_event(&this, event: *const cef_mouse_event, _mouse_exited: c_int) -> () { let event: &cef_mouse_event = event; let point = TypedPoint2D((*event).x as f32, (*event).y as f32); - core::send_window_event(WindowEvent::MouseWindowMoveEventClass(point)) + this.downcast().send_window_event(WindowEvent::MouseWindowMoveEventClass(point)) } - fn send_mouse_wheel_event(&_this, + fn send_mouse_wheel_event(&this, event: *const cef_mouse_event, delta_x: c_int, delta_y: c_int) @@ -124,20 +133,20 @@ cef_class_impl! { let event: &cef_mouse_event = event; let delta = TypedPoint2D(delta_x as f32, delta_y as f32); let origin = TypedPoint2D((*event).x as i32, (*event).y as i32); - core::send_window_event(WindowEvent::Scroll(delta, origin)) + this.downcast().send_window_event(WindowEvent::Scroll(delta, origin)) } - fn get_zoom_level(&_this) -> c_double { - core::pinch_zoom_level() as c_double + fn get_zoom_level(&this) -> c_double { + this.downcast().pinch_zoom_level() as c_double } fn set_zoom_level(&this, new_zoom_level: c_double) -> () { let old_zoom_level = this.get_zoom_level(); - core::send_window_event(WindowEvent::PinchZoom((new_zoom_level / old_zoom_level) as f32)) + this.downcast().send_window_event(WindowEvent::PinchZoom((new_zoom_level / old_zoom_level) as f32)) } - fn initialize_compositing(&_this) -> () { - core::send_window_event(WindowEvent::InitializeCompositing); + fn initialize_compositing(&this) -> () { + this.downcast().send_window_event(WindowEvent::InitializeCompositing); } } } @@ -149,6 +158,14 @@ impl ServoCefBrowserHost { client: client, } } + + fn send_window_event(&self, event: WindowEvent) { + self.browser.borrow_mut().as_mut().unwrap().send_window_event(event); + } + + fn pinch_zoom_level(&self) -> f32 { + self.browser.borrow_mut().as_mut().unwrap().pinch_zoom_level() + } } pub trait ServoCefBrowserHostExtensions { diff --git a/ports/cef/core.rs b/ports/cef/core.rs index b9541f775a2..98e3fcfc168 100644 --- a/ports/cef/core.rs +++ b/ports/cef/core.rs @@ -5,36 +5,22 @@ use command_line::command_line_init; use interfaces::cef_app_t; use types::{cef_main_args_t, cef_settings_t}; -use window; -use compositing::windowing::WindowEvent; use geom::size::TypedSize2D; -use glfw_app; use libc::{c_char, c_int, c_void}; -use servo::Browser; +use rustrt::local::Local; +use rustrt::task; use servo_util::opts; use servo_util::opts::RenderApi; use std::c_str::CString; -use std::cell::RefCell; -use std::rc::Rc; use std::rt; +use browser; const MAX_RENDERING_THREADS: uint = 128; // TODO(pcwalton): Get the home page via the CEF API. static HOME_URL: &'static str = "http://s27.postimg.org/vqbtrolyr/servo.jpg"; -// TODO(pcwalton): Support multiple windows. -pub enum ServoCefGlobals { - OnScreenGlobals(RefCell>, - RefCell>), - OffScreenGlobals(RefCell>, RefCell>), -} - -thread_local!(pub static globals: Rc>> = Rc::new(RefCell::new(None))) - -thread_local!(pub static message_queue: Rc>> = Rc::new(RefCell::new(vec!()))) - static CEF_API_HASH_UNIVERSAL: &'static [u8] = b"8efd129f4afc344bd04b2feb7f73a149b6c4e27f\0"; #[cfg(target_os="windows")] static CEF_API_HASH_PLATFORM: &'static [u8] = b"5c7f3e50ff5265985d11dc1a466513e25748bedd\0"; @@ -53,6 +39,11 @@ fn resources_path() -> Option { None } +fn create_rust_task() { + let task = box task::Task::new(None, None); + Local::put(task); +} + #[no_mangle] pub extern "C" fn cef_initialize(args: *const cef_main_args_t, settings: *mut cef_settings_t, @@ -77,6 +68,8 @@ pub extern "C" fn cef_initialize(args: *const cef_main_args_t, } } + create_rust_task(); + let urls = vec![HOME_URL.into_string()]; opts::set_opts(opts::Opts { urls: urls, @@ -124,22 +117,17 @@ pub extern "C" fn cef_shutdown() { #[no_mangle] pub extern "C" fn cef_run_message_loop() { - globals.with(|ref r| { - let mut the_globals = r.borrow_mut(); - match *the_globals.as_mut().unwrap() { - ServoCefGlobals::OnScreenGlobals(ref window, ref browser) => { - while browser.borrow_mut().handle_event(window.borrow_mut().wait_events()) {} - } - ServoCefGlobals::OffScreenGlobals(ref window, ref browser) => { - while browser.borrow_mut().handle_event(window.borrow_mut().wait_events()) {} - } - } - }); + // GWTODO: Support blocking message loop + // again. Although, will it ever actually + // be used or will everything use the + // cef_do_message_loop_work function below + // as our current miniservo apps do? + unimplemented!() } #[no_mangle] pub extern "C" fn cef_do_message_loop_work() { - send_window_event(WindowEvent::Idle) + browser::update(); } #[no_mangle] @@ -154,79 +142,6 @@ pub extern "C" fn cef_execute_process(_args: *const cef_main_args_t, -1 } -pub fn send_window_event(event: WindowEvent) { - message_queue.with(|ref r| r.borrow_mut().push(event.clone())); - - globals.with(|ref r| { - let mut the_globals = r.borrow_mut(); - match &mut *the_globals { - &None => return, - &Some(ref mut the_globals) => loop { - match *the_globals { - ServoCefGlobals::OnScreenGlobals(_, ref browser) => { - match browser.try_borrow_mut() { - None => { - // We're trying to send an event while processing another one. This will - // cause general badness, so queue up that event instead of immediately - // processing it. - break - } - Some(ref mut browser) => { - let event = match message_queue.with(|ref r| r.borrow_mut().pop()) { - None => return, - Some(event) => event, - }; - browser.handle_event(event); - } - } - } - ServoCefGlobals::OffScreenGlobals(_, ref browser) => { - match browser.try_borrow_mut() { - None => { - // We're trying to send an event while processing another one. This will - // cause general badness, so queue up that event instead of immediately - // processing it. - break - } - Some(ref mut browser) => { - let event = match message_queue.with(|ref r| r.borrow_mut().pop()) { - None => return, - Some(event) => event, - }; - browser.handle_event(event); - } - } - } - } - } - } - }); -} - -macro_rules! browser_method_delegate( - ( $( fn $method:ident ( ) -> $return_type:ty ; )* ) => ( - $( - pub fn $method() -> $return_type { - globals.with(|ref r| { - match r.borrow_mut().as_mut() { - None => panic!("{}: no globals created", stringify!($method)), - Some(&ServoCefGlobals::OnScreenGlobals(_, ref browser)) => - browser.borrow_mut().$method(), - Some(&ServoCefGlobals::OffScreenGlobals(_, ref browser)) => - browser.borrow_mut().$method(), - } - }) - } - )* - ) -) - -browser_method_delegate! { - fn repaint_synchronously() -> (); - fn pinch_zoom_level() -> f32; - fn get_title_for_main_frame() -> (); -} - #[no_mangle] pub extern "C" fn cef_api_hash(entry: c_int) -> *const c_char { if entry == 0 { diff --git a/ports/cef/frame.rs b/ports/cef/frame.rs index 86651f93d64..b551e53a8e4 100644 --- a/ports/cef/frame.rs +++ b/ports/cef/frame.rs @@ -3,16 +3,19 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use eutil::Downcast; -use interfaces::{CefFrame, CefStringVisitor, cef_frame_t, cef_string_visitor_t}; +use interfaces::{CefBrowser, CefFrame, CefStringVisitor, cef_frame_t, cef_string_visitor_t}; use types::{cef_string_t, cef_string_userfree_t}; +use browser::ServoCefBrowserExtensions; -use core; use compositing::windowing::WindowEvent; use std::cell::RefCell; pub struct ServoCefFrame { pub title_visitor: RefCell>, pub url: RefCell, + + /// A reference to the browser. + pub browser: RefCell>, } impl ServoCefFrame { @@ -20,6 +23,7 @@ impl ServoCefFrame { ServoCefFrame { title_visitor: RefCell::new(None), url: RefCell::new(String::new()), + browser: RefCell::new(None), } } } @@ -29,7 +33,8 @@ cef_class_impl! { fn load_url(&this, url: *const cef_string_t) -> () { let this = this.downcast(); *this.url.borrow_mut() = String::from_utf16(url).unwrap(); - core::send_window_event(WindowEvent::LoadUrl(String::from_utf16(url).unwrap())); + let event = WindowEvent::LoadUrl(String::from_utf16(url).unwrap()); + this.browser.borrow_mut().as_mut().unwrap().send_window_event(event); } fn get_url(&this) -> cef_string_userfree_t { let this = this.downcast(); @@ -38,8 +43,17 @@ cef_class_impl! { fn get_text(&this, visitor: *mut cef_string_visitor_t) -> () { let this = this.downcast(); *this.title_visitor.borrow_mut() = Some(visitor); - core::get_title_for_main_frame(); + this.browser.borrow().as_ref().unwrap().get_title_for_main_frame(); } } } +pub trait ServoCefFrameExtensions { + fn set_browser(&self, browser: CefBrowser); +} + +impl ServoCefFrameExtensions for CefFrame { + fn set_browser(&self, browser: CefBrowser) { + *self.downcast().browser.borrow_mut() = Some(browser) + } +} \ No newline at end of file