diff --git a/Cargo.lock b/Cargo.lock index c72223c0385..1e4e2bd7e6c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -182,6 +182,7 @@ dependencies = [ "bluetooth_traits 0.0.1", "compositing 0.0.1", "device 0.0.1 (git+https://github.com/servo/devices)", + "embedder_traits 0.0.1", "ipc-channel 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "servo_config 0.0.1", @@ -419,6 +420,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "compositing" version = "0.0.1" dependencies = [ + "embedder_traits 0.0.1", "euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_traits 0.0.1", "gleam 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -770,7 +772,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "embedder_traits" version = "0.0.1" dependencies = [ + "ipc-channel 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "msg 0.0.1", + "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "servo_url 0.0.1", + "style_traits 0.0.1", + "webrender_api 0.57.2 (git+https://github.com/servo/webrender)", ] [[package]] @@ -1850,7 +1859,6 @@ version = "0.0.1" dependencies = [ "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "brotli 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "compositing 0.0.1", "cookie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "devtools_traits 0.0.1", "embedder_traits 0.0.1", @@ -2601,6 +2609,7 @@ dependencies = [ "canvas_traits 0.0.1", "cookie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "devtools_traits 0.0.1", + "embedder_traits 0.0.1", "euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_traits 0.0.1", "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/bluetooth/Cargo.toml b/components/bluetooth/Cargo.toml index bc172342977..114772a7f99 100644 --- a/components/bluetooth/Cargo.toml +++ b/components/bluetooth/Cargo.toml @@ -14,8 +14,12 @@ bitflags = "1.0" bluetooth_traits = {path = "../bluetooth_traits"} compositing = {path = "../compositing"} device = {git = "https://github.com/servo/devices", features = ["bluetooth-test"]} +embedder_traits = {path = "../embedder_traits"} ipc-channel = "0.10" log = "0.4" servo_config = {path = "../config"} servo_rand = {path = "../rand"} uuid = {version = "0.6", features = ["v4"]} + +[dev-dependencies] +embedder_traits = { path = "../embedder_traits", features = ["tests"]} diff --git a/components/bluetooth/lib.rs b/components/bluetooth/lib.rs index 3df295b56e9..5da42bddc65 100644 --- a/components/bluetooth/lib.rs +++ b/components/bluetooth/lib.rs @@ -5,8 +5,8 @@ #[macro_use] extern crate bitflags; extern crate bluetooth_traits; -extern crate compositing; extern crate device; +extern crate embedder_traits; extern crate ipc_channel; #[macro_use] extern crate log; @@ -21,9 +21,9 @@ use bluetooth_traits::{BluetoothDeviceMsg, BluetoothRequest, BluetoothResponse, use bluetooth_traits::{BluetoothError, BluetoothResponseResult, BluetoothResult}; use bluetooth_traits::blocklist::{uuid_is_blocklisted, Blocklist}; use bluetooth_traits::scanfilter::{BluetoothScanfilter, BluetoothScanfilterSequence, RequestDeviceoptions}; -use compositing::compositor_thread::{EmbedderMsg, EmbedderProxy}; use device::bluetooth::{BluetoothAdapter, BluetoothDevice, BluetoothGATTCharacteristic}; use device::bluetooth::{BluetoothGATTDescriptor, BluetoothGATTService}; +use embedder_traits::{EmbedderMsg, EmbedderProxy}; use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use servo_config::opts; use servo_config::prefs::PREFS; diff --git a/components/compositing/Cargo.toml b/components/compositing/Cargo.toml index 7715effd551..7dbd1e28688 100644 --- a/components/compositing/Cargo.toml +++ b/components/compositing/Cargo.toml @@ -14,6 +14,7 @@ path = "lib.rs" default = [] [dependencies] +embedder_traits = {path = "../embedder_traits"} euclid = "0.17" gfx_traits = {path = "../gfx_traits"} gleam = {version = "0.5", optional = true} @@ -36,3 +37,6 @@ webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} [build-dependencies] toml = "0.4.5" + +[dev-dependencies] +embedder_traits = { path = "../embedder_traits", features = ["tests"]} diff --git a/components/compositing/compositor_thread.rs b/components/compositing/compositor_thread.rs index 2e8dc7a66d6..76b3172b5dd 100644 --- a/components/compositing/compositor_thread.rs +++ b/components/compositing/compositor_thread.rs @@ -6,68 +6,21 @@ use SendableFrameTree; use compositor::CompositingReason; +use embedder_traits::EventLoopWaker; use gfx_traits::Epoch; use ipc_channel::ipc::IpcSender; -use msg::constellation_msg::{InputMethodType, Key, KeyModifiers, KeyState, PipelineId, TopLevelBrowsingContextId}; -use net_traits::filemanager_thread::FilterPattern; +use msg::constellation_msg::{PipelineId, TopLevelBrowsingContextId}; use net_traits::image::base::Image; use profile_traits::mem; use profile_traits::time; -use script_traits::{AnimationState, ConstellationMsg, EventResult, LoadData}; -use servo_url::ServoUrl; +use script_traits::{AnimationState, ConstellationMsg, EventResult}; use std::fmt::{Debug, Error, Formatter}; use std::sync::mpsc::{Receiver, Sender}; -use style_traits::cursor::CursorKind; use style_traits::viewport::ViewportConstraints; use webrender; use webrender_api::{self, DeviceIntPoint, DeviceUintSize}; -/// Used to wake up the event loop, provided by the servo port/embedder. -pub trait EventLoopWaker : 'static + Send { - fn clone(&self) -> Box; - fn wake(&self); -} - -/// Sends messages to the embedder. -pub struct EmbedderProxy { - pub sender: Sender, - pub event_loop_waker: Box, -} - -impl EmbedderProxy { - pub fn send(&self, msg: EmbedderMsg) { - // Send a message and kick the OS event loop awake. - if let Err(err) = self.sender.send(msg) { - warn!("Failed to send response ({}).", err); - } - self.event_loop_waker.wake(); - } -} - -impl Clone for EmbedderProxy { - fn clone(&self) -> EmbedderProxy { - EmbedderProxy { - sender: self.sender.clone(), - event_loop_waker: self.event_loop_waker.clone(), - } - } -} - -/// The port that the embedder receives messages on. -pub struct EmbedderReceiver { - pub receiver: Receiver -} - -impl EmbedderReceiver { - pub fn try_recv_embedder_msg(&mut self) -> Option { - self.receiver.try_recv().ok() - } - pub fn recv_embedder_msg(&mut self) -> EmbedderMsg { - self.receiver.recv().unwrap() - } -} - /// Sends messages to the compositor. pub struct CompositorProxy { pub sender: Sender, @@ -113,47 +66,6 @@ impl CompositorProxy { } } -pub enum EmbedderMsg { - /// A status message to be displayed by the browser chrome. - Status(TopLevelBrowsingContextId, Option), - /// Alerts the embedder that the current page has changed its title. - ChangePageTitle(TopLevelBrowsingContextId, Option), - /// Move the window to a point - MoveTo(TopLevelBrowsingContextId, DeviceIntPoint), - /// Resize the window to size - ResizeTo(TopLevelBrowsingContextId, DeviceUintSize), - /// Wether or not to follow a link - AllowNavigation(TopLevelBrowsingContextId, ServoUrl, IpcSender), - /// Sends an unconsumed key event back to the embedder. - KeyEvent(Option, Option, Key, KeyState, KeyModifiers), - /// Changes the cursor. - SetCursor(CursorKind), - /// A favicon was detected - NewFavicon(TopLevelBrowsingContextId, ServoUrl), - /// tag finished parsing - HeadParsed(TopLevelBrowsingContextId), - /// The history state has changed. - HistoryChanged(TopLevelBrowsingContextId, Vec, usize), - /// Enter or exit fullscreen - SetFullscreenState(TopLevelBrowsingContextId, bool), - /// The load of a page has begun - LoadStart(TopLevelBrowsingContextId), - /// The load of a page has completed - LoadComplete(TopLevelBrowsingContextId), - /// A pipeline panicked. First string is the reason, second one is the backtrace. - Panic(TopLevelBrowsingContextId, String, Option), - /// Open dialog to select bluetooth device. - GetSelectedBluetoothDevice(Vec, IpcSender>), - /// Open file dialog to select files. Set boolean flag to true allows to select multiple files. - SelectFiles(Vec, bool, IpcSender>>), - /// Request to present an IME to the user when an editable element is focused. - ShowIME(TopLevelBrowsingContextId, InputMethodType), - /// Request to hide the IME when the editable element is blurred. - HideIME(TopLevelBrowsingContextId), - /// Servo has shut down - Shutdown, -} - /// Messages from the painting thread and the constellation thread to the compositor thread. pub enum Msg { /// Requests that the compositor shut down. @@ -233,32 +145,6 @@ impl Debug for Msg { } } -impl Debug for EmbedderMsg { - fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { - match *self { - EmbedderMsg::Status(..) => write!(f, "Status"), - EmbedderMsg::ChangePageTitle(..) => write!(f, "ChangePageTitle"), - EmbedderMsg::MoveTo(..) => write!(f, "MoveTo"), - EmbedderMsg::ResizeTo(..) => write!(f, "ResizeTo"), - EmbedderMsg::AllowNavigation(..) => write!(f, "AllowNavigation"), - EmbedderMsg::KeyEvent(..) => write!(f, "KeyEvent"), - EmbedderMsg::SetCursor(..) => write!(f, "SetCursor"), - EmbedderMsg::NewFavicon(..) => write!(f, "NewFavicon"), - EmbedderMsg::HeadParsed(..) => write!(f, "HeadParsed"), - EmbedderMsg::HistoryChanged(..) => write!(f, "HistoryChanged"), - EmbedderMsg::SetFullscreenState(..) => write!(f, "SetFullscreenState"), - EmbedderMsg::LoadStart(..) => write!(f, "LoadStart"), - EmbedderMsg::LoadComplete(..) => write!(f, "LoadComplete"), - EmbedderMsg::Panic(..) => write!(f, "Panic"), - EmbedderMsg::GetSelectedBluetoothDevice(..) => write!(f, "GetSelectedBluetoothDevice"), - EmbedderMsg::SelectFiles(..) => write!(f, "SelectFiles"), - EmbedderMsg::ShowIME(..) => write!(f, "ShowIME"), - EmbedderMsg::HideIME(..) => write!(f, "HideIME"), - EmbedderMsg::Shutdown => write!(f, "Shutdown"), - } - } -} - /// Data used to construct a compositor. pub struct InitialCompositorState { /// A channel to the compositor. diff --git a/components/compositing/lib.rs b/components/compositing/lib.rs index f19230ebcdd..59c7600fcfd 100644 --- a/components/compositing/lib.rs +++ b/components/compositing/lib.rs @@ -4,6 +4,7 @@ #![deny(unsafe_code)] +extern crate embedder_traits; extern crate euclid; extern crate gfx_traits; #[cfg(feature = "gleam")] diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index 11143e5eaa9..b81b1e3ebc7 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -4,7 +4,7 @@ //! Abstract windowing methods. The concrete implementations of these can be found in `platform/`. -use compositor_thread::EventLoopWaker; +use embedder_traits::EventLoopWaker; use euclid::TypedScale; #[cfg(feature = "gleam")] use gleam::gl; @@ -78,6 +78,8 @@ pub enum WindowEvent { NewBrowser(ServoUrl, IpcSender), /// Close a top level browsing context CloseBrowser(TopLevelBrowsingContextId), + /// Panic a top level browsing context. + SendError(Option, String), /// Make a top level browsing context visible, hiding the previous /// visible one. SelectBrowser(TopLevelBrowsingContextId), @@ -106,6 +108,7 @@ impl Debug for WindowEvent { WindowEvent::Quit => write!(f, "Quit"), WindowEvent::Reload(..) => write!(f, "Reload"), WindowEvent::NewBrowser(..) => write!(f, "NewBrowser"), + WindowEvent::SendError(..) => write!(f, "SendError"), WindowEvent::CloseBrowser(..) => write!(f, "CloseBrowser"), WindowEvent::SelectBrowser(..) => write!(f, "SelectBrowser"), WindowEvent::ToggleWebRenderDebug(..) => write!(f, "ToggleWebRenderDebug"), diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 970073cafbf..4f5e0612f44 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -98,10 +98,11 @@ use canvas_traits::canvas::CanvasId; use canvas_traits::canvas::CanvasMsg; use clipboard::{ClipboardContext, ClipboardProvider}; use compositing::SendableFrameTree; -use compositing::compositor_thread::{CompositorProxy, EmbedderMsg, EmbedderProxy}; +use compositing::compositor_thread::CompositorProxy; use compositing::compositor_thread::Msg as ToCompositorMsg; use debugger; use devtools_traits::{ChromeToDevtoolsControlMsg, DevtoolsControlMsg}; +use embedder_traits::{EmbedderMsg, EmbedderProxy}; use euclid::{Size2D, TypedSize2D, TypedScale}; use event_loop::EventLoop; use gfx::font_cache_thread::FontCacheThread; @@ -969,6 +970,15 @@ impl Constellation FromCompositorMsg::CloseBrowser(top_level_browsing_context_id) => { self.handle_close_top_level_browsing_context(top_level_browsing_context_id); } + // Panic a top level browsing context. + FromCompositorMsg::SendError(top_level_browsing_context_id, error) => { + debug!("constellation got SendError message"); + if let Some(id) = top_level_browsing_context_id { + self.handle_panic(id, error, None); + } else { + warn!("constellation got a SendError message without top level id"); + } + } // Send frame tree to WebRender. Make it visible. FromCompositorMsg::SelectBrowser(top_level_browsing_context_id) => { self.send_frame_tree(top_level_browsing_context_id); @@ -1014,12 +1024,10 @@ impl Constellation Some(ctx) => ctx, }; - let source_is_top_level_pipeline = self.browsing_contexts - .get(&BrowsingContextId::from(source_top_ctx_id)) - .map(|ctx| ctx.pipeline_id == source_pipeline_id) - .unwrap_or(false); - match content { + FromScriptMsg::ForwardToEmbedder(embedder_msg) => { + self.embedder_proxy.send(embedder_msg); + } FromScriptMsg::PipelineExited => { self.handle_pipeline_exited(source_pipeline_id); } @@ -1119,34 +1127,12 @@ impl Constellation warn!("Error replying to remove iframe ({})", e); } } - FromScriptMsg::NewFavicon(url) => { - if source_is_top_level_pipeline { - self.embedder_proxy.send(EmbedderMsg::NewFavicon(source_top_ctx_id, url)); - } - } - FromScriptMsg::HeadParsed => { - if source_is_top_level_pipeline { - self.embedder_proxy.send(EmbedderMsg::HeadParsed(source_top_ctx_id)); - } - } FromScriptMsg::CreateCanvasPaintThread(size, sender) => { self.handle_create_canvas_paint_thread_msg(&size, sender) } - FromScriptMsg::NodeStatus(message) => { - self.embedder_proxy.send(EmbedderMsg::Status(source_top_ctx_id, message)); - } FromScriptMsg::SetDocumentState(state) => { self.document_states.insert(source_pipeline_id, state); } - FromScriptMsg::Alert(message, sender) => { - self.handle_alert(source_top_ctx_id, message, sender); - } - FromScriptMsg::MoveTo(point) => { - self.embedder_proxy.send(EmbedderMsg::MoveTo(source_top_ctx_id, point)); - } - FromScriptMsg::ResizeTo(size) => { - self.embedder_proxy.send(EmbedderMsg::ResizeTo(source_top_ctx_id, size)); - } FromScriptMsg::GetClientWindow(send) => { self.compositor_proxy.send(ToCompositorMsg::GetClientWindow(send)); } @@ -1162,15 +1148,6 @@ impl Constellation FromScriptMsg::LogEntry(thread_name, entry) => { self.handle_log_entry(Some(source_top_ctx_id), thread_name, entry); } - FromScriptMsg::SetTitle(title) => { - if source_is_top_level_pipeline { - self.embedder_proxy.send(EmbedderMsg::ChangePageTitle(source_top_ctx_id, title)) - } - } - FromScriptMsg::SendKeyEvent(ch, key, key_state, key_modifiers) => { - let event = EmbedderMsg::KeyEvent(Some(source_top_ctx_id), ch, key, key_state, key_modifiers); - self.embedder_proxy.send(event); - } FromScriptMsg::TouchEventProcessed(result) => { self.compositor_proxy.send(ToCompositorMsg::TouchEventProcessed(result)) } @@ -1208,15 +1185,6 @@ impl Constellation FromScriptMsg::BroadcastStorageEvent(storage, url, key, old_value, new_value) => { self.handle_broadcast_storage_event(source_pipeline_id, storage, url, key, old_value, new_value); } - FromScriptMsg::SetFullscreenState(state) => { - self.embedder_proxy.send(EmbedderMsg::SetFullscreenState(source_top_ctx_id, state)); - } - FromScriptMsg::ShowIME(kind) => { - self.embedder_proxy.send(EmbedderMsg::ShowIME(source_top_ctx_id, kind)); - } - FromScriptMsg::HideIME => { - self.embedder_proxy.send(EmbedderMsg::HideIME(source_top_ctx_id)); - } } } @@ -1727,23 +1695,6 @@ impl Constellation } } - fn handle_alert(&mut self, - top_level_browsing_context_id: TopLevelBrowsingContextId, - _message: String, - sender: IpcSender) { - // FIXME: forward alert event to embedder - // https://github.com/servo/servo/issues/19992 - let result = sender.send(true); - if let Err(e) = result { - let ctx_id = BrowsingContextId::from(top_level_browsing_context_id); - let pipeline_id = match self.browsing_contexts.get(&ctx_id) { - Some(ctx) => ctx.pipeline_id, - None => return warn!("Alert sent for unknown browsing context."), - }; - self.handle_send_error(pipeline_id, e); - } - } - fn handle_load_url_msg(&mut self, top_level_browsing_context_id: TopLevelBrowsingContextId, source_id: PipelineId, load_data: LoadData, replace: bool) { self.load_url(top_level_browsing_context_id, source_id, load_data, replace); @@ -2451,8 +2402,8 @@ impl Constellation entries.extend(session_history.future.iter().rev() .scan(current_load_data.clone(), &resolve_load_data_future)); - - let msg = EmbedderMsg::HistoryChanged(top_level_browsing_context_id, entries, current_index); + let urls = entries.iter().map(|entry| entry.url.clone()).collect(); + let msg = EmbedderMsg::HistoryChanged(top_level_browsing_context_id, urls, current_index); self.embedder_proxy.send(msg); } diff --git a/components/constellation/lib.rs b/components/constellation/lib.rs index 5ae86080300..1fd6662d405 100644 --- a/components/constellation/lib.rs +++ b/components/constellation/lib.rs @@ -14,7 +14,7 @@ extern crate clipboard; extern crate compositing; extern crate debugger; extern crate devtools_traits; -#[cfg(all(not(target_os = "windows"), not(target_os = "ios")))] +#[cfg(not(target_os = "ios"))] extern crate embedder_traits; extern crate euclid; #[cfg(all(not(target_os = "windows"), not(target_os = "ios")))] diff --git a/components/embedder_traits/Cargo.toml b/components/embedder_traits/Cargo.toml index 9146893b13d..eb8bc420db6 100644 --- a/components/embedder_traits/Cargo.toml +++ b/components/embedder_traits/Cargo.toml @@ -13,4 +13,11 @@ path = "lib.rs" tests = [] [dependencies] +ipc-channel = "0.10" lazy_static = "1" +log = "0.4" +msg = {path = "../msg"} +serde = "1.0" +servo_url = {path = "../url"} +style_traits = {path = "../style_traits"} +webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} diff --git a/components/embedder_traits/lib.rs b/components/embedder_traits/lib.rs index aa8a3c0e111..6650c553946 100644 --- a/components/embedder_traits/lib.rs +++ b/components/embedder_traits/lib.rs @@ -2,6 +2,146 @@ * 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/. */ -#[macro_use] extern crate lazy_static; +extern crate ipc_channel; +#[macro_use] +extern crate lazy_static; +#[macro_use] +extern crate log; +extern crate msg; +#[macro_use] +extern crate serde; +extern crate servo_url; +extern crate style_traits; +extern crate webrender_api; pub mod resources; + +use ipc_channel::ipc::IpcSender; +use msg::constellation_msg::{InputMethodType, Key, KeyModifiers, KeyState, TopLevelBrowsingContextId}; +use servo_url::ServoUrl; +use std::fmt::{Debug, Error, Formatter}; +use std::sync::mpsc::{Receiver, Sender}; +use style_traits::cursor::CursorKind; +use webrender_api::{DeviceIntPoint, DeviceUintSize}; + + +/// Used to wake up the event loop, provided by the servo port/embedder. +pub trait EventLoopWaker : 'static + Send { + fn clone(&self) -> Box; + fn wake(&self); +} + +/// Sends messages to the embedder. +pub struct EmbedderProxy { + pub sender: Sender, + pub event_loop_waker: Box, +} + +impl EmbedderProxy { + pub fn send(&self, msg: EmbedderMsg) { + // Send a message and kick the OS event loop awake. + if let Err(err) = self.sender.send(msg) { + warn!("Failed to send response ({}).", err); + } + self.event_loop_waker.wake(); + } +} + +impl Clone for EmbedderProxy { + fn clone(&self) -> EmbedderProxy { + EmbedderProxy { + sender: self.sender.clone(), + event_loop_waker: self.event_loop_waker.clone(), + } + } +} + +/// The port that the embedder receives messages on. +pub struct EmbedderReceiver { + pub receiver: Receiver +} + +impl EmbedderReceiver { + pub fn try_recv_embedder_msg(&mut self) -> Option { + self.receiver.try_recv().ok() + } + pub fn recv_embedder_msg(&mut self) -> EmbedderMsg { + self.receiver.recv().unwrap() + } +} + +#[derive(Deserialize, Serialize)] +pub enum EmbedderMsg { + /// A status message to be displayed by the browser chrome. + Status(TopLevelBrowsingContextId, Option), + /// Alerts the embedder that the current page has changed its title. + ChangePageTitle(TopLevelBrowsingContextId, Option), + /// Move the window to a point + MoveTo(TopLevelBrowsingContextId, DeviceIntPoint), + /// Resize the window to size + ResizeTo(TopLevelBrowsingContextId, DeviceUintSize), + // Show an alert message. + Alert(TopLevelBrowsingContextId, String, IpcSender<()>), + /// Wether or not to follow a link + AllowNavigation(TopLevelBrowsingContextId, ServoUrl, IpcSender), + /// Sends an unconsumed key event back to the embedder. + KeyEvent(Option, Option, Key, KeyState, KeyModifiers), + /// Changes the cursor. + SetCursor(CursorKind), + /// A favicon was detected + NewFavicon(TopLevelBrowsingContextId, ServoUrl), + /// tag finished parsing + HeadParsed(TopLevelBrowsingContextId), + /// The history state has changed. + HistoryChanged(TopLevelBrowsingContextId, Vec, usize), + /// Enter or exit fullscreen + SetFullscreenState(TopLevelBrowsingContextId, bool), + /// The load of a page has begun + LoadStart(TopLevelBrowsingContextId), + /// The load of a page has completed + LoadComplete(TopLevelBrowsingContextId), + /// A pipeline panicked. First string is the reason, second one is the backtrace. + Panic(TopLevelBrowsingContextId, String, Option), + /// Open dialog to select bluetooth device. + GetSelectedBluetoothDevice(Vec, IpcSender>), + /// Open file dialog to select files. Set boolean flag to true allows to select multiple files. + SelectFiles(Vec, bool, IpcSender>>), + /// Request to present an IME to the user when an editable element is focused. + ShowIME(TopLevelBrowsingContextId, InputMethodType), + /// Request to hide the IME when the editable element is blurred. + HideIME(TopLevelBrowsingContextId), + /// Servo has shut down + Shutdown, +} + +impl Debug for EmbedderMsg { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + match *self { + EmbedderMsg::Status(..) => write!(f, "Status"), + EmbedderMsg::ChangePageTitle(..) => write!(f, "ChangePageTitle"), + EmbedderMsg::MoveTo(..) => write!(f, "MoveTo"), + EmbedderMsg::ResizeTo(..) => write!(f, "ResizeTo"), + EmbedderMsg::Alert(..) => write!(f, "Alert"), + EmbedderMsg::AllowNavigation(..) => write!(f, "AllowNavigation"), + EmbedderMsg::KeyEvent(..) => write!(f, "KeyEvent"), + EmbedderMsg::SetCursor(..) => write!(f, "SetCursor"), + EmbedderMsg::NewFavicon(..) => write!(f, "NewFavicon"), + EmbedderMsg::HeadParsed(..) => write!(f, "HeadParsed"), + EmbedderMsg::HistoryChanged(..) => write!(f, "HistoryChanged"), + EmbedderMsg::SetFullscreenState(..) => write!(f, "SetFullscreenState"), + EmbedderMsg::LoadStart(..) => write!(f, "LoadStart"), + EmbedderMsg::LoadComplete(..) => write!(f, "LoadComplete"), + EmbedderMsg::Panic(..) => write!(f, "Panic"), + EmbedderMsg::GetSelectedBluetoothDevice(..) => write!(f, "GetSelectedBluetoothDevice"), + EmbedderMsg::SelectFiles(..) => write!(f, "SelectFiles"), + EmbedderMsg::ShowIME(..) => write!(f, "ShowIME"), + EmbedderMsg::HideIME(..) => write!(f, "HideIME"), + EmbedderMsg::Shutdown => write!(f, "Shutdown"), + } + } +} + +/// Filter for file selection; +/// the `String` content is expected to be extension (e.g, "doc", without the prefixing ".") +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct FilterPattern(pub String); diff --git a/components/net/Cargo.toml b/components/net/Cargo.toml index 9ef3654f902..43c8b22c4c0 100644 --- a/components/net/Cargo.toml +++ b/components/net/Cargo.toml @@ -16,7 +16,6 @@ doctest = false base64 = "0.6" brotli = "1.0.6" cookie = "0.10" -compositing = {path = "../compositing"} devtools_traits = {path = "../devtools_traits"} embedder_traits = { path = "../embedder_traits" } flate2 = "1" diff --git a/components/net/filemanager_thread.rs b/components/net/filemanager_thread.rs index 6926412d104..ab1afef374d 100644 --- a/components/net/filemanager_thread.rs +++ b/components/net/filemanager_thread.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 compositing::compositor_thread::{EmbedderMsg, EmbedderProxy}; +use embedder_traits::{EmbedderMsg, EmbedderProxy, FilterPattern}; use ipc_channel::ipc::{self, IpcSender}; use mime_guess::guess_mime_type_opt; use net_traits::blob_url_store::{BlobBuf, BlobURLStoreError}; -use net_traits::filemanager_thread::{FileManagerResult, FileManagerThreadMsg, FileOrigin, FilterPattern}; +use net_traits::filemanager_thread::{FileManagerResult, FileManagerThreadMsg, FileOrigin}; use net_traits::filemanager_thread::{FileManagerThreadError, ReadFileProgress, RelativePos, SelectedFile}; use servo_config::prefs::PREFS; use std::collections::HashMap; diff --git a/components/net/lib.rs b/components/net/lib.rs index a8d802ae49f..cdeb7d54595 100644 --- a/components/net/lib.rs +++ b/components/net/lib.rs @@ -6,7 +6,6 @@ extern crate base64; extern crate brotli; -extern crate compositing; extern crate cookie as cookie_rs; extern crate devtools_traits; extern crate embedder_traits; diff --git a/components/net/resource_thread.rs b/components/net/resource_thread.rs index d00c0323f38..ffcdccebfe9 100644 --- a/components/net/resource_thread.rs +++ b/components/net/resource_thread.rs @@ -3,12 +3,12 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ //! A thread that takes a URL and streams back the binary data. -use compositing::compositor_thread::EmbedderProxy; use connector::{create_http_connector, create_ssl_client}; use cookie; use cookie_rs; use cookie_storage::CookieStorage; use devtools_traits::DevtoolsControlMsg; +use embedder_traits::EmbedderProxy; use embedder_traits::resources::{self, Resource}; use fetch::cors_cache::CorsCache; use fetch::methods::{CancellationListener, FetchContext, fetch}; diff --git a/components/net/tests/filemanager_thread.rs b/components/net/tests/filemanager_thread.rs index d71c9f30187..8612bdae672 100644 --- a/components/net/tests/filemanager_thread.rs +++ b/components/net/tests/filemanager_thread.rs @@ -3,10 +3,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use create_embedder_proxy; +use embedder_traits::FilterPattern; use ipc_channel::ipc; use net::filemanager_thread::FileManager; use net_traits::blob_url_store::BlobURLStoreError; -use net_traits::filemanager_thread::{FilterPattern, FileManagerThreadMsg, FileManagerThreadError, ReadFileProgress}; +use net_traits::filemanager_thread::{FileManagerThreadMsg, FileManagerThreadError, ReadFileProgress}; use servo_config::prefs::{PrefValue, PREFS}; use std::fs::File; use std::io::Read; diff --git a/components/net/tests/main.rs b/components/net/tests/main.rs index a644a6a2fd4..1a7d5c462a5 100644 --- a/components/net/tests/main.rs +++ b/components/net/tests/main.rs @@ -4,7 +4,6 @@ #![cfg(test)] -extern crate compositing; extern crate cookie as cookie_rs; extern crate devtools_traits; extern crate embedder_traits; @@ -35,8 +34,8 @@ mod mime_classifier; mod resource_thread; mod subresource_integrity; -use compositing::compositor_thread::{EmbedderProxy, EventLoopWaker}; use devtools_traits::DevtoolsControlMsg; +use embedder_traits::{EmbedderProxy, EventLoopWaker}; use embedder_traits::resources::{self, Resource}; use hyper::server::{Handler, Listening, Server}; use net::connector::create_ssl_client; diff --git a/components/net_traits/filemanager_thread.rs b/components/net_traits/filemanager_thread.rs index a9cb76bf98a..fa0ac23d8f5 100644 --- a/components/net_traits/filemanager_thread.rs +++ b/components/net_traits/filemanager_thread.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use blob_url_store::{BlobBuf, BlobURLStoreError}; +use embedder_traits::FilterPattern; use ipc_channel::ipc::IpcSender; use num_traits::ToPrimitive; use std::cmp::{max, min}; @@ -110,11 +111,6 @@ pub struct SelectedFile { pub type_string: String, } -/// Filter for file selection; -/// the `String` content is expected to be extension (e.g, "doc", without the prefixing ".") -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct FilterPattern(pub String); - #[derive(Deserialize, Serialize)] pub enum FileManagerThreadMsg { /// Select a single file. Last field is pre-selected file path for testing diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 3b6b92246f1..74f495b8867 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -88,6 +88,7 @@ use dom::webglcontextevent::WebGLContextEvent; use dom::window::{ReflowReason, Window}; use dom::windowproxy::WindowProxy; use dom_struct::dom_struct; +use embedder_traits::EmbedderMsg; use encoding_rs::{Encoding, UTF_8}; use euclid::Point2D; use fetch::FetchCanceller; @@ -855,7 +856,8 @@ impl Document { // Notify the embedder to hide the input method. if elem.input_method_type().is_some() { - self.send_to_constellation(ScriptMsg::HideIME); + let top_level_browsing_context_id = self.window().top_level_browsing_context_id(); + self.send_to_embedder(EmbedderMsg::HideIME(top_level_browsing_context_id)); } } @@ -869,12 +871,13 @@ impl Document { // Update the focus state for all elements in the focus chain. // https://html.spec.whatwg.org/multipage/#focus-chain if focus_type == FocusType::Element { - self.send_to_constellation(ScriptMsg::Focus); + self.window().send_to_constellation(ScriptMsg::Focus); } // Notify the embedder to display an input method. if let Some(kind) = elem.input_method_type() { - self.send_to_constellation(ScriptMsg::ShowIME(kind)); + let top_level_browsing_context_id = self.window().top_level_browsing_context_id(); + self.send_to_embedder(EmbedderMsg::ShowIME(top_level_browsing_context_id, kind)); } } } @@ -882,14 +885,23 @@ impl Document { /// Handles any updates when the document's title has changed. pub fn title_changed(&self) { if self.browsing_context().is_some() { - self.send_title_to_constellation(); + self.send_title_to_embedder(); } } /// Sends this document's title to the constellation. - pub fn send_title_to_constellation(&self) { - let title = Some(String::from(self.Title())); - self.send_to_constellation(ScriptMsg::SetTitle(title)); + pub fn send_title_to_embedder(&self) { + let window = self.window(); + if window.is_top_level() { + let title = Some(String::from(self.Title())); + let top_level_browsing_context_id = window.top_level_browsing_context_id(); + self.send_to_embedder(EmbedderMsg::ChangePageTitle(top_level_browsing_context_id, title)); + } + } + + fn send_to_embedder(&self, msg: EmbedderMsg) { + let window = self.window(); + window.send_to_embedder(msg); } pub fn dirty_all_nodes(&self) { @@ -1352,8 +1364,9 @@ impl Document { } if cancel_state == EventDefault::Allowed { - let msg = ScriptMsg::SendKeyEvent(ch, key, state, modifiers); - self.send_to_constellation(msg); + let top_level_browsing_context_id = self.window().top_level_browsing_context_id(); + let msg = EmbedderMsg::KeyEvent(Some(top_level_browsing_context_id), ch, key, state, modifiers); + self.send_to_embedder(msg); // This behavior is unspecced // We are supposed to dispatch synthetic click activation for Space and/or Return, @@ -1488,7 +1501,7 @@ impl Document { // repeated rAF. let event = ScriptMsg::ChangeRunningAnimationsState(AnimationState::AnimationCallbacksPresent); - self.send_to_constellation(event); + self.window().send_to_constellation(event); } ident @@ -1559,7 +1572,7 @@ impl Document { ); } let event = ScriptMsg::ChangeRunningAnimationsState(AnimationState::NoAnimationCallbacksPresent); - self.send_to_constellation(event); + self.window().send_to_constellation(event); } // Update the counter of spurious animation frames. @@ -2009,7 +2022,7 @@ impl Document { } pub fn notify_constellation_load(&self) { - self.send_to_constellation(ScriptMsg::LoadComplete); + self.window().send_to_constellation(ScriptMsg::LoadComplete); } pub fn set_current_parser(&self, script: Option<&ServoParser>) { @@ -2167,11 +2180,6 @@ impl Document { registry.lookup_definition(local_name, is) } - fn send_to_constellation(&self, msg: ScriptMsg) { - let global_scope = self.window.upcast::(); - global_scope.script_to_constellation_chan().send(msg).unwrap(); - } - pub fn increment_throw_on_dynamic_markup_insertion_counter(&self) { let counter = self.throw_on_dynamic_markup_insertion_counter.get(); self.throw_on_dynamic_markup_insertion_counter.set(counter + 1); @@ -2787,8 +2795,9 @@ impl Document { let window = self.window(); // Step 6 if !error { - let event = ScriptMsg::SetFullscreenState(true); - self.send_to_constellation(event); + let top_level_browsing_context_id = self.window().top_level_browsing_context_id(); + let event = EmbedderMsg::SetFullscreenState(top_level_browsing_context_id, true); + self.send_to_embedder(event); } let pipeline_id = self.window().pipeline_id(); @@ -2822,8 +2831,9 @@ impl Document { let window = self.window(); // Step 8 - let event = ScriptMsg::SetFullscreenState(false); - self.send_to_constellation(event); + let top_level_browsing_context_id = self.window().top_level_browsing_context_id(); + let event = EmbedderMsg::SetFullscreenState(top_level_browsing_context_id, true); + self.send_to_embedder(event); // Step 9 let trusted_element = Trusted::new(element.r()); diff --git a/components/script/dom/htmlbodyelement.rs b/components/script/dom/htmlbodyelement.rs index c3ac339e33c..51ed2fcd0ea 100644 --- a/components/script/dom/htmlbodyelement.rs +++ b/components/script/dom/htmlbodyelement.rs @@ -12,13 +12,12 @@ use dom::bindings::str::DOMString; use dom::document::Document; use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers}; use dom::eventtarget::EventTarget; -use dom::globalscope::GlobalScope; use dom::htmlelement::HTMLElement; use dom::node::{Node, document_from_node, window_from_node}; use dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; +use embedder_traits::EmbedderMsg; use html5ever::{LocalName, Prefix}; -use script_traits::ScriptMsg; use servo_url::ServoUrl; use style::attr::AttrValue; use time; @@ -151,8 +150,11 @@ impl VirtualMethods for HTMLBodyElement { let window = window_from_node(self); let document = window.Document(); document.set_reflow_timeout(time::precise_time_ns() + INITIAL_REFLOW_DELAY); - let event = ScriptMsg::HeadParsed; - window.upcast::().script_to_constellation_chan().send(event).unwrap(); + if window.is_top_level() { + let top_level_browsing_context_id = window.top_level_browsing_context_id(); + let msg = EmbedderMsg::HeadParsed(top_level_browsing_context_id); + window.send_to_embedder(msg); + } } fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue { diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index ab7d55d5b9a..f2d83fa4d54 100755 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -38,12 +38,13 @@ use dom::validation::Validatable; use dom::validitystate::ValidationFlags; use dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; +use embedder_traits::FilterPattern; use html5ever::{LocalName, Prefix}; use mime_guess; use msg::constellation_msg::InputMethodType; use net_traits::{CoreResourceMsg, IpcSend}; use net_traits::blob_url_store::get_blob_origin; -use net_traits::filemanager_thread::{FileManagerThreadMsg, FilterPattern}; +use net_traits::filemanager_thread::FileManagerThreadMsg; use profile_traits::ipc; use script_layout_interface::rpc::TextIndexResponse; use script_traits::ScriptToConstellationChan; diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index f3f82cb5ce1..c05bd0ee0f6 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -16,15 +16,14 @@ use dom::document::Document; use dom::domtokenlist::DOMTokenList; use dom::element::{AttributeMutation, Element, ElementCreator}; use dom::element::{cors_setting_for_element, reflect_cross_origin_attribute, set_cross_origin_attribute}; -use dom::globalscope::GlobalScope; use dom::htmlelement::HTMLElement; use dom::node::{Node, UnbindContext, document_from_node, window_from_node}; use dom::stylesheet::StyleSheet as DOMStyleSheet; use dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; +use embedder_traits::EmbedderMsg; use html5ever::{LocalName, Prefix}; use net_traits::ReferrerPolicy; -use script_traits::ScriptMsg; use servo_arc::Arc; use std::borrow::ToOwned; use std::cell::Cell; @@ -306,8 +305,13 @@ impl HTMLLinkElement { let document = document_from_node(self); match document.base_url().join(href) { Ok(url) => { - let event = ScriptMsg::NewFavicon(url.clone()); - document.window().upcast::().script_to_constellation_chan().send(event).unwrap(); + let window = document.window(); + if window.is_top_level() { + let top_level_browsing_context_id = window.top_level_browsing_context_id(); + let msg = EmbedderMsg::NewFavicon(top_level_browsing_context_id, url.clone()); + window.send_to_embedder(msg); + } + } Err(e) => debug!("Parsing url {} failed: {}", href, e) } diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 00f65b60611..b80a87b7627 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -48,6 +48,7 @@ use dom::windowproxy::WindowProxy; use dom::worklet::Worklet; use dom::workletglobalscope::WorkletGlobalScopeType; use dom_struct::dom_struct; +use embedder_traits::EmbedderMsg; use euclid::{Point2D, Vector2D, Rect, Size2D, TypedPoint2D, TypedScale, TypedSize2D}; use fetch; use ipc_channel::ipc::IpcSender; @@ -58,7 +59,7 @@ use js::jsval::UndefinedValue; use js::rust::HandleValue; use layout_image::fetch_image_for_layout; use microtask::MicrotaskQueue; -use msg::constellation_msg::PipelineId; +use msg::constellation_msg::{PipelineId, TopLevelBrowsingContextId}; use net_traits::{ResourceThreads, ReferrerPolicy}; use net_traits::image_cache::{ImageCache, ImageResponder, ImageResponse}; use net_traits::image_cache::{PendingImageId, PendingImageResponse}; @@ -114,8 +115,6 @@ use task_source::performance_timeline::PerformanceTimelineTaskSource; use task_source::user_interaction::UserInteractionTaskSource; use time; use timers::{IsInterval, TimerCallback}; -#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] -use tinyfiledialogs::{self, MessageBoxIcon}; use url::Position; use webdriver_handlers::jsval_to_webdriver; use webrender_api::{ExternalScrollId, DeviceIntPoint, DeviceUintSize, DocumentId}; @@ -356,6 +355,11 @@ impl Window { self.parent_info } + pub fn top_level_browsing_context_id(&self) -> TopLevelBrowsingContextId { + let window_proxy = self.window_proxy.get().unwrap(); + window_proxy.top_level_browsing_context_id() + } + pub fn new_script_pair(&self) -> (Box, Box) { let (tx, rx) = channel(); (Box::new(SendableMainThreadScriptChan(tx)), Box::new(rx)) @@ -444,18 +448,6 @@ impl Window { } } -#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] -fn display_alert_dialog(message: &str) { - if !opts::get().headless { - tinyfiledialogs::message_box_ok("Alert!", message, MessageBoxIcon::Warning); - } -} - -#[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))] -fn display_alert_dialog(_message: &str) { - // tinyfiledialogs not supported on Android -} - // https://html.spec.whatwg.org/multipage/#atob pub fn base64_btoa(input: DOMString) -> Fallible { // "The btoa() method must throw an InvalidCharacterError exception if @@ -541,14 +533,12 @@ impl WindowMethods for Window { stdout.flush().unwrap(); stderr.flush().unwrap(); } - let (sender, receiver) = ProfiledIpc::channel(self.global().time_profiler_chan().clone()).unwrap(); - self.send_to_constellation(ScriptMsg::Alert(s.to_string(), sender)); - - let should_display_alert_dialog = receiver.recv().unwrap(); - if should_display_alert_dialog { - display_alert_dialog(&s); - } + let window_proxy = self.window_proxy.get().unwrap(); + let top_level_browsing_context_id = window_proxy.top_level_browsing_context_id(); + let msg = EmbedderMsg::Alert(top_level_browsing_context_id, s.to_string(), sender); + self.send_to_embedder(msg); + receiver.recv().unwrap(); } // https://html.spec.whatwg.org/multipage/#dom-window-closed @@ -937,7 +927,8 @@ impl WindowMethods for Window { //TODO determine if this operation is allowed let dpr = self.device_pixel_ratio(); let size = TypedSize2D::new(width, height).to_f32() * dpr; - self.send_to_constellation(ScriptMsg::ResizeTo(size.to_u32())); + let top_level_browsing_context_id = self.top_level_browsing_context_id(); + self.send_to_embedder(EmbedderMsg::ResizeTo(top_level_browsing_context_id, size.to_u32())); } // https://drafts.csswg.org/cssom-view/#dom-window-resizeby @@ -953,7 +944,10 @@ impl WindowMethods for Window { //TODO determine if this operation is allowed let dpr = self.device_pixel_ratio(); let point = TypedPoint2D::new(x, y).to_f32() * dpr; - self.send_to_constellation(ScriptMsg::MoveTo(point.to_i32())); + let window_proxy = self.window_proxy.get().unwrap(); + let top_level_browsing_context_id = window_proxy.top_level_browsing_context_id(); + let msg = EmbedderMsg::MoveTo(top_level_browsing_context_id, point.to_i32()); + self.send_to_embedder(msg); } // https://drafts.csswg.org/cssom-view/#dom-window-moveby @@ -1742,7 +1736,11 @@ impl Window { self.navigation_start_precise.set(time::precise_time_ns()); } - fn send_to_constellation(&self, msg: ScriptMsg) { + pub fn send_to_embedder(&self, msg: EmbedderMsg) { + self.send_to_constellation(ScriptMsg::ForwardToEmbedder(msg)); + } + + pub fn send_to_constellation(&self, msg: ScriptMsg) { self.upcast::() .script_to_constellation_chan() .send(msg) diff --git a/components/script/lib.rs b/components/script/lib.rs index bee088aa5e0..cf020ab9ac6 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -93,7 +93,7 @@ extern crate style; extern crate style_traits; extern crate swapper; extern crate time; -#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] +#[cfg(target_os = "linux")] extern crate tinyfiledialogs; extern crate unicode_segmentation; extern crate url; diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 613918f6a76..a118562a234 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -62,6 +62,7 @@ use dom::windowproxy::WindowProxy; use dom::worker::TrustedWorkerAddress; use dom::worklet::WorkletThreadPool; use dom::workletglobalscope::WorkletGlobalScopeInit; +use embedder_traits::EmbedderMsg; use euclid::{Point2D, Vector2D, Rect}; use fetch::FetchCanceller; use hyper::header::{ContentType, HttpDate, Headers, LastModified}; @@ -1822,7 +1823,7 @@ impl ScriptThread { Some(document) => document, None => return warn!("Message sent to closed pipeline {}.", pipeline_id), }; - document.send_title_to_constellation(); + document.send_title_to_embedder(); } /// Handles a request to exit a pipeline and shut down layout. @@ -2282,6 +2283,8 @@ impl ScriptThread { Some(document) => document, None => return warn!("Message sent to closed pipeline {}.", pipeline_id), }; + let window = document.window(); + let top_level_browsing_context_id = window.top_level_browsing_context_id(); // Get the previous target temporarily let prev_mouse_over_target = self.topmost_mouse_over_target.get(); @@ -2310,9 +2313,8 @@ impl ScriptThread { let url = document.url(); url.join(&value).map(|url| url.to_string()).ok() }); - - let event = ScriptMsg::NodeStatus(status); - self.script_sender.send((pipeline_id, event)).unwrap(); + let event = EmbedderMsg::Status(top_level_browsing_context_id, status); + window.send_to_embedder(event); state_already_changed = true; } @@ -2325,8 +2327,8 @@ impl ScriptThread { .inclusive_ancestors() .filter_map(DomRoot::downcast::) .next() { - let event = ScriptMsg::NodeStatus(None); - self.script_sender.send((pipeline_id, event)).unwrap(); + let event = EmbedderMsg::Status(top_level_browsing_context_id, None); + window.send_to_embedder(event); } } } diff --git a/components/script_traits/Cargo.toml b/components/script_traits/Cargo.toml index 2d3c47c14b7..a5ae8cf0d7e 100644 --- a/components/script_traits/Cargo.toml +++ b/components/script_traits/Cargo.toml @@ -14,6 +14,7 @@ bluetooth_traits = {path = "../bluetooth_traits"} canvas_traits = {path = "../canvas_traits"} cookie = "0.10" devtools_traits = {path = "../devtools_traits"} +embedder_traits = {path = "../embedder_traits"} euclid = "0.17" gfx_traits = {path = "../gfx_traits"} hyper = "0.10" @@ -34,3 +35,6 @@ time = "0.1.12" url = "1.2" webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} webvr_traits = {path = "../webvr_traits"} + +[dev-dependencies] +embedder_traits = { path = "../embedder_traits", features = ["tests"]} diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 9ecda6625d6..6075cc6fc43 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -13,6 +13,7 @@ extern crate bluetooth_traits; extern crate canvas_traits; extern crate cookie as cookie_rs; extern crate devtools_traits; +extern crate embedder_traits; extern crate euclid; extern crate gfx_traits; extern crate hyper; @@ -702,6 +703,8 @@ pub enum ConstellationMsg { NewBrowser(ServoUrl, IpcSender), /// Close a top level browsing context. CloseBrowser(TopLevelBrowsingContextId), + /// Panic a top level browsing context. + SendError(Option, String), /// Make browser visible. SelectBrowser(TopLevelBrowsingContextId), /// Forward an event to the script task of the given pipeline. @@ -730,6 +733,7 @@ impl fmt::Debug for ConstellationMsg { WebVREvents(..) => "WebVREvents", NewBrowser(..) => "NewBrowser", CloseBrowser(..) => "CloseBrowser", + SendError(..) => "SendError", SelectBrowser(..) => "SelectBrowser", ForwardEvent(..) => "ForwardEvent", SetCursor(..) => "SetCursor", diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs index ad437b09d8d..c9cb879f1c2 100644 --- a/components/script_traits/script_msg.rs +++ b/components/script_traits/script_msg.rs @@ -12,11 +12,11 @@ use WorkerGlobalScopeInit; use WorkerScriptLoadOrigin; use canvas_traits::canvas::{CanvasMsg, CanvasId}; use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId}; +use embedder_traits::EmbedderMsg; use euclid::{Size2D, TypedSize2D}; use gfx_traits::Epoch; use ipc_channel::ipc::{IpcReceiver, IpcSender}; use msg::constellation_msg::{BrowsingContextId, HistoryStateId, PipelineId, TraversalDirection}; -use msg::constellation_msg::{InputMethodType, Key, KeyModifiers, KeyState}; use net_traits::CoreResourceMsg; use net_traits::request::RequestInit; use net_traits::storage_thread::StorageType; @@ -83,6 +83,8 @@ pub enum LogEntry { /// Messages from the script to the constellation. #[derive(Deserialize, Serialize)] pub enum ScriptMsg { + /// Forward a message to the embedder. + ForwardToEmbedder(EmbedderMsg), /// Requests are sent to constellation and fetches are checked manually /// for cross-origin loads InitiateNavigateRequest(RequestInit, /* cancellation_chan */ IpcReceiver<()>), @@ -104,8 +106,6 @@ pub enum ScriptMsg { GetParentInfo(PipelineId, IpcSender>), /// Get the nth child browsing context ID for a given browsing context, sorted in tree order. GetChildBrowsingContextId(BrowsingContextId, usize, IpcSender>), - /// tag finished parsing - HeadParsed, /// All pending loads are complete, and the `load` event for this pipeline /// has been dispatched. LoadComplete, @@ -124,10 +124,6 @@ pub enum ScriptMsg { ReplaceHistoryState(HistoryStateId, ServoUrl), /// Gets the length of the joint session history from the constellation. JointSessionHistoryLength(IpcSender), - /// Favicon detected - NewFavicon(ServoUrl), - /// Status message to be displayed in the chrome, eg. a link URL on mouseover. - NodeStatus(Option), /// Notification that this iframe should be removed. /// Returns a list of pipelines which were closed. RemoveIFrame(BrowsingContextId, IpcSender>), @@ -147,17 +143,6 @@ pub enum ScriptMsg { SetDocumentState(DocumentState), /// Update the pipeline Url, which can change after redirections. SetFinalUrl(ServoUrl), - /// Check if an alert dialog box should be presented - Alert(String, IpcSender), - /// Set title of current page - /// - SetTitle(Option), - /// Send a key event - SendKeyEvent(Option, Key, KeyState, KeyModifiers), - /// Move the window to a point - MoveTo(DeviceIntPoint), - /// Resize the window to size - ResizeTo(DeviceUintSize), /// Script has handled a touch event, and either prevented or allowed default actions. TouchEventProcessed(EventResult), /// A log entry, with the top-level browsing context id and thread name @@ -171,18 +156,12 @@ pub enum ScriptMsg { ForwardDOMMessage(DOMMessage, ServoUrl), /// Store the data required to activate a service worker for the given scope RegisterServiceWorker(ScopeThings, ServoUrl), - /// Enter or exit fullscreen - SetFullscreenState(bool), /// Get Window Informations size and position GetClientWindow(IpcSender<(DeviceUintSize, DeviceIntPoint)>), /// Get the screen size (pixel) GetScreenSize(IpcSender<(DeviceUintSize)>), /// Get the available screen size (pixel) GetScreenAvailSize(IpcSender<(DeviceUintSize)>), - /// Request to present an IME to the user when an editable element is focused. - ShowIME(InputMethodType), - /// Request to hide the IME when the editable element is blurred. - HideIME, /// Requests that the compositor shut down. Exit, } @@ -191,6 +170,7 @@ impl fmt::Debug for ScriptMsg { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { use self::ScriptMsg::*; let variant = match *self { + ForwardToEmbedder(..) => "ForwardToEmbedder", InitiateNavigateRequest(..) => "InitiateNavigateRequest", BroadcastStorageEvent(..) => "BroadcastStorageEvent", ChangeRunningAnimationsState(..) => "ChangeRunningAnimationsState", @@ -200,7 +180,6 @@ impl fmt::Debug for ScriptMsg { GetBrowsingContextId(..) => "GetBrowsingContextId", GetParentInfo(..) => "GetParentInfo", GetChildBrowsingContextId(..) => "GetChildBrowsingContextId", - HeadParsed => "HeadParsed", LoadComplete => "LoadComplete", LoadUrl(..) => "LoadUrl", AbortLoadUrl => "AbortLoadUrl", @@ -209,8 +188,6 @@ impl fmt::Debug for ScriptMsg { PushHistoryState(..) => "PushHistoryState", ReplaceHistoryState(..) => "ReplaceHistoryState", JointSessionHistoryLength(..) => "JointSessionHistoryLength", - NewFavicon(..) => "NewFavicon", - NodeStatus(..) => "NodeStatus", RemoveIFrame(..) => "RemoveIFrame", SetVisible(..) => "SetVisible", VisibilityChangeComplete(..) => "VisibilityChangeComplete", @@ -220,23 +197,15 @@ impl fmt::Debug for ScriptMsg { ActivateDocument => "ActivateDocument", SetDocumentState(..) => "SetDocumentState", SetFinalUrl(..) => "SetFinalUrl", - Alert(..) => "Alert", - SetTitle(..) => "SetTitle", - SendKeyEvent(..) => "SendKeyEvent", - MoveTo(..) => "MoveTo", - ResizeTo(..) => "ResizeTo", TouchEventProcessed(..) => "TouchEventProcessed", LogEntry(..) => "LogEntry", DiscardDocument => "DiscardDocument", PipelineExited => "PipelineExited", ForwardDOMMessage(..) => "ForwardDOMMessage", RegisterServiceWorker(..) => "RegisterServiceWorker", - SetFullscreenState(..) => "SetFullscreenState", GetClientWindow(..) => "GetClientWindow", GetScreenSize(..) => "GetScreenSize", GetScreenAvailSize(..) => "GetScreenAvailSize", - ShowIME(..) => "ShowIME", - HideIME => "HideIME", Exit => "Exit", }; write!(formatter, "ScriptMsg::{}", variant) diff --git a/components/servo/lib.rs b/components/servo/lib.rs index bc06dc84ca7..b532bd80b5f 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -73,13 +73,13 @@ use bluetooth_traits::BluetoothRequest; use canvas::gl_context::GLContextFactory; use canvas::webgl_thread::WebGLThreads; use compositing::{IOCompositor, ShutdownState, RenderNotifier}; -use compositing::compositor_thread::{self, CompositorProxy, CompositorReceiver, InitialCompositorState}; -use compositing::compositor_thread::{EmbedderMsg, EmbedderProxy, EmbedderReceiver}; +use compositing::compositor_thread::{CompositorProxy, CompositorReceiver, InitialCompositorState}; use compositing::windowing::{WindowEvent, WindowMethods}; use constellation::{Constellation, InitialConstellationState, UnprivilegedPipelineContent}; use constellation::{FromCompositorLogger, FromScriptLogger}; #[cfg(all(not(target_os = "windows"), not(target_os = "ios")))] use constellation::content_process_sandbox_profile; +use embedder_traits::{EmbedderMsg, EmbedderProxy, EmbedderReceiver, EventLoopWaker}; use env_logger::Builder as EnvLoggerBuilder; use euclid::Length; #[cfg(all(not(target_os = "windows"), not(target_os = "ios")))] @@ -346,6 +346,13 @@ impl Servo where Window: WindowMethods + 'static { warn!("Sending CloseBrowser message to constellation failed ({}).", e); } } + + WindowEvent::SendError(ctx, e) => { + let msg = ConstellationMsg::SendError(ctx, e); + if let Err(e) = self.constellation_chan.send(msg) { + warn!("Sending CloseBrowser message to constellation failed ({}).", e); + } + } } } @@ -417,7 +424,7 @@ impl Servo where Window: WindowMethods + 'static { } } -fn create_embedder_channel(event_loop_waker: Box) +fn create_embedder_channel(event_loop_waker: Box) -> (EmbedderProxy, EmbedderReceiver) { let (sender, receiver) = channel(); (EmbedderProxy { @@ -429,7 +436,7 @@ fn create_embedder_channel(event_loop_waker: Box) +fn create_compositor_channel(event_loop_waker: Box) -> (CompositorProxy, CompositorReceiver) { let (sender, receiver) = channel(); (CompositorProxy { diff --git a/ports/servo/browser.rs b/ports/servo/browser.rs index 6d83c59153d..a64ba44e088 100644 --- a/ports/servo/browser.rs +++ b/ports/servo/browser.rs @@ -5,12 +5,10 @@ use euclid::{TypedPoint2D, TypedVector2D}; use glutin_app::keyutils::{CMD_OR_CONTROL, CMD_OR_ALT}; use glutin_app::window::{Window, LINE_HEIGHT}; -use servo::compositing::compositor_thread::EmbedderMsg; use servo::compositing::windowing::{WebRenderDebugOption, WindowEvent}; -use servo::ipc_channel::ipc::IpcSender; +use servo::embedder_traits::{EmbedderMsg, FilterPattern}; use servo::msg::constellation_msg::{Key, TopLevelBrowsingContextId as BrowserId}; use servo::msg::constellation_msg::{KeyModifiers, KeyState, TraversalDirection}; -use servo::net_traits::filemanager_thread::FilterPattern; use servo::net_traits::pub_domains::is_reg_domain; use servo::script_traits::TouchEventType; use servo::servo_config::opts; @@ -21,7 +19,8 @@ use std::mem; use std::rc::Rc; #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] use std::thread; -use tinyfiledialogs; +#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] +use tinyfiledialogs::{self, MessageBoxIcon}; pub struct Browser { current_url: Option, @@ -260,6 +259,13 @@ impl Browser { EmbedderMsg::ResizeTo(_browser_id, size) => { self.window.set_inner_size(size); } + EmbedderMsg::Alert(browser_id, message, sender) => { + display_alert_dialog(message.to_owned()); + if let Err(e) = sender.send(()) { + let reason = format!("Failed to send Alert response: {}", e); + self.event_queue.push(WindowEvent::SendError(Some(browser_id), reason)); + } + } EmbedderMsg::AllowNavigation(_browser_id, _url, response_chan) => { if let Err(e) = response_chan.send(true) { warn!("Failed to send allow_navigation() response: {}", e); @@ -277,8 +283,8 @@ impl Browser { EmbedderMsg::HeadParsed(_browser_id, ) => { self.loading_state = Some(LoadingState::Loading); } - EmbedderMsg::HistoryChanged(_browser_id, entries, current) => { - self.current_url = Some(entries[current].url.clone()); + EmbedderMsg::HistoryChanged(_browser_id, urls, current) => { + self.current_url = Some(urls[current].clone()); } EmbedderMsg::SetFullscreenState(_browser_id, state) => { self.window.set_fullscreen(state); @@ -295,13 +301,22 @@ impl Browser { EmbedderMsg::Panic(_browser_id, _reason, _backtrace) => { }, EmbedderMsg::GetSelectedBluetoothDevice(devices, sender) => { - platform_get_selected_devices(devices, sender); + let selected = platform_get_selected_devices(devices); + if let Err(e) = sender.send(selected) { + let reason = format!("Failed to send GetSelectedBluetoothDevice response: {}", e); + self.event_queue.push(WindowEvent::SendError(None, reason)); + }; }, EmbedderMsg::SelectFiles(patterns, multiple_files, sender) => { - if opts::get().headless { - let _ = sender.send(None); - } - platform_get_selected_files(patterns, multiple_files, sender); + let res = match (opts::get().headless, + platform_get_selected_files(patterns, multiple_files)) { + (true, _) | (false, None) => sender.send(None), + (false, Some(files)) => sender.send(Some(files)) + }; + if let Err(e) = res { + let reason = format!("Failed to send SelectFiles response: {}", e); + self.event_queue.push(WindowEvent::SendError(None, reason)); + }; } EmbedderMsg::ShowIME(_browser_id, _kind) => { debug!("ShowIME received"); @@ -315,8 +330,22 @@ impl Browser { } +#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] +fn display_alert_dialog(message: String) { + if !opts::get().headless { + let _ = thread::Builder::new().name("display alert dialog".to_owned()).spawn(move || { + tinyfiledialogs::message_box_ok("Alert!", &message, MessageBoxIcon::Warning); + }).unwrap().join().expect("Thread spawning failed"); + } +} + +#[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))] +fn display_alert_dialog(_message: String) { + // tinyfiledialogs not supported on Android +} + #[cfg(target_os = "linux")] -fn platform_get_selected_devices(devices: Vec, sender: IpcSender>) { +fn platform_get_selected_devices(devices: Vec) -> Option { let picker_name = "Choose a device"; thread::Builder::new().name(picker_name.to_owned()).spawn(move || { @@ -328,58 +357,54 @@ fn platform_get_selected_devices(devices: Vec, sender: IpcSender { // The device string format will be "Address|Name". We need the first part of it. - let address = device.split("|").next().map(|s| s.to_string()); - let _ = sender.send(address); + device.split("|").next().map(|s| s.to_string()) }, None => { - let _ = sender.send(None); + None } } - }).expect("Thread spawning failed"); + }).unwrap().join().expect("Thread spawning failed") } #[cfg(not(target_os = "linux"))] -fn platform_get_selected_devices(devices: Vec, sender: IpcSender>) { +fn platform_get_selected_devices(devices: Vec) -> Option { for device in devices { if let Some(address) = device.split("|").next().map(|s| s.to_string()) { - let _ = sender.send(Some(address)); + return Some(address) } } - let _ = sender.send(None); + None } #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] fn platform_get_selected_files(patterns: Vec, - multiple_files: bool, - sender: IpcSender>>) { + multiple_files: bool) + -> Option> { let picker_name = if multiple_files { "Pick files" } else { "Pick a file" }; - thread::Builder::new().name(picker_name.to_owned()).spawn(move || { - let mut filter = vec![]; + let mut filters = vec![]; for p in patterns { let s = "*.".to_string() + &p.0; - filter.push(s) + filters.push(s) } - - let filter_ref = &(filter.iter().map(|s| s.as_str()).collect::>()[..]); - let filter_opt = if filter.len() > 0 { Some((filter_ref, "")) } else { None }; + let filter_ref = &(filters.iter().map(|s| s.as_str()).collect::>()[..]); + let filter_opt = if filters.len() > 0 { Some((filter_ref, "")) } else { None }; if multiple_files { - let files = tinyfiledialogs::open_file_dialog_multi(picker_name, "", filter_opt); - let _ = sender.send(files); + tinyfiledialogs::open_file_dialog_multi(picker_name, "", filter_opt) } else { let file = tinyfiledialogs::open_file_dialog(picker_name, "", filter_opt); - let _ = sender.send(file.map(|x| vec![x])); + file.map(|x| vec![x]) } - }).expect("Thread spawning failed"); + }).unwrap().join().expect("Thread spawning failed") } #[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))] fn platform_get_selected_files(_patterns: Vec, - _multiple_files: bool, - sender: IpcSender>>) { + _multiple_files: bool) + -> Option> { warn!("File picker not implemented"); - let _ = sender.send(None); + None } fn sanitize_url(request: &str) -> Option { diff --git a/ports/servo/glutin_app/window.rs b/ports/servo/glutin_app/window.rs index 436f7518eee..2324ea37ab0 100644 --- a/ports/servo/glutin_app/window.rs +++ b/ports/servo/glutin_app/window.rs @@ -11,9 +11,9 @@ use gleam::gl; use glutin::{Api, ContextBuilder, GlContext, GlRequest, GlWindow}; #[cfg(any(target_os = "linux", target_os = "macos"))] use osmesa_sys; -use servo::compositing::compositor_thread::EventLoopWaker; use servo::compositing::windowing::{AnimationState, MouseWindowEvent, WindowEvent}; use servo::compositing::windowing::{EmbedderCoordinates, WindowMethods}; +use servo::embedder_traits::EventLoopWaker; use servo::msg::constellation_msg::{Key, KeyState}; use servo::script_traits::TouchEventType; use servo::servo_config::opts;