move msg to embedder_traits, use in script, handle send error in embedder

This commit is contained in:
Gregory Terzian 2018-04-28 22:48:14 +08:00
parent a297e8f288
commit d438240772
31 changed files with 362 additions and 337 deletions

11
Cargo.lock generated
View file

@ -182,6 +182,7 @@ dependencies = [
"bluetooth_traits 0.0.1", "bluetooth_traits 0.0.1",
"compositing 0.0.1", "compositing 0.0.1",
"device 0.0.1 (git+https://github.com/servo/devices)", "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)", "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)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"servo_config 0.0.1", "servo_config 0.0.1",
@ -419,6 +420,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "compositing" name = "compositing"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"embedder_traits 0.0.1",
"euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx_traits 0.0.1", "gfx_traits 0.0.1",
"gleam 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "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" name = "embedder_traits"
version = "0.0.1" version = "0.0.1"
dependencies = [ 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)", "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]] [[package]]
@ -1850,7 +1859,6 @@ version = "0.0.1"
dependencies = [ dependencies = [
"base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "cookie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"devtools_traits 0.0.1", "devtools_traits 0.0.1",
"embedder_traits 0.0.1", "embedder_traits 0.0.1",
@ -2601,6 +2609,7 @@ dependencies = [
"canvas_traits 0.0.1", "canvas_traits 0.0.1",
"cookie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "cookie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"devtools_traits 0.0.1", "devtools_traits 0.0.1",
"embedder_traits 0.0.1",
"euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx_traits 0.0.1", "gfx_traits 0.0.1",
"hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -14,8 +14,12 @@ bitflags = "1.0"
bluetooth_traits = {path = "../bluetooth_traits"} bluetooth_traits = {path = "../bluetooth_traits"}
compositing = {path = "../compositing"} compositing = {path = "../compositing"}
device = {git = "https://github.com/servo/devices", features = ["bluetooth-test"]} device = {git = "https://github.com/servo/devices", features = ["bluetooth-test"]}
embedder_traits = {path = "../embedder_traits"}
ipc-channel = "0.10" ipc-channel = "0.10"
log = "0.4" log = "0.4"
servo_config = {path = "../config"} servo_config = {path = "../config"}
servo_rand = {path = "../rand"} servo_rand = {path = "../rand"}
uuid = {version = "0.6", features = ["v4"]} uuid = {version = "0.6", features = ["v4"]}
[dev-dependencies]
embedder_traits = { path = "../embedder_traits", features = ["tests"]}

View file

@ -5,8 +5,8 @@
#[macro_use] #[macro_use]
extern crate bitflags; extern crate bitflags;
extern crate bluetooth_traits; extern crate bluetooth_traits;
extern crate compositing;
extern crate device; extern crate device;
extern crate embedder_traits;
extern crate ipc_channel; extern crate ipc_channel;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
@ -21,9 +21,9 @@ use bluetooth_traits::{BluetoothDeviceMsg, BluetoothRequest, BluetoothResponse,
use bluetooth_traits::{BluetoothError, BluetoothResponseResult, BluetoothResult}; use bluetooth_traits::{BluetoothError, BluetoothResponseResult, BluetoothResult};
use bluetooth_traits::blocklist::{uuid_is_blocklisted, Blocklist}; use bluetooth_traits::blocklist::{uuid_is_blocklisted, Blocklist};
use bluetooth_traits::scanfilter::{BluetoothScanfilter, BluetoothScanfilterSequence, RequestDeviceoptions}; use bluetooth_traits::scanfilter::{BluetoothScanfilter, BluetoothScanfilterSequence, RequestDeviceoptions};
use compositing::compositor_thread::{EmbedderMsg, EmbedderProxy};
use device::bluetooth::{BluetoothAdapter, BluetoothDevice, BluetoothGATTCharacteristic}; use device::bluetooth::{BluetoothAdapter, BluetoothDevice, BluetoothGATTCharacteristic};
use device::bluetooth::{BluetoothGATTDescriptor, BluetoothGATTService}; use device::bluetooth::{BluetoothGATTDescriptor, BluetoothGATTService};
use embedder_traits::{EmbedderMsg, EmbedderProxy};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use servo_config::opts; use servo_config::opts;
use servo_config::prefs::PREFS; use servo_config::prefs::PREFS;

View file

@ -14,6 +14,7 @@ path = "lib.rs"
default = [] default = []
[dependencies] [dependencies]
embedder_traits = {path = "../embedder_traits"}
euclid = "0.17" euclid = "0.17"
gfx_traits = {path = "../gfx_traits"} gfx_traits = {path = "../gfx_traits"}
gleam = {version = "0.5", optional = true} gleam = {version = "0.5", optional = true}
@ -36,3 +37,6 @@ webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]}
[build-dependencies] [build-dependencies]
toml = "0.4.5" toml = "0.4.5"
[dev-dependencies]
embedder_traits = { path = "../embedder_traits", features = ["tests"]}

View file

@ -6,68 +6,21 @@
use SendableFrameTree; use SendableFrameTree;
use compositor::CompositingReason; use compositor::CompositingReason;
use embedder_traits::EventLoopWaker;
use gfx_traits::Epoch; use gfx_traits::Epoch;
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::{InputMethodType, Key, KeyModifiers, KeyState, PipelineId, TopLevelBrowsingContextId}; use msg::constellation_msg::{PipelineId, TopLevelBrowsingContextId};
use net_traits::filemanager_thread::FilterPattern;
use net_traits::image::base::Image; use net_traits::image::base::Image;
use profile_traits::mem; use profile_traits::mem;
use profile_traits::time; use profile_traits::time;
use script_traits::{AnimationState, ConstellationMsg, EventResult, LoadData}; use script_traits::{AnimationState, ConstellationMsg, EventResult};
use servo_url::ServoUrl;
use std::fmt::{Debug, Error, Formatter}; use std::fmt::{Debug, Error, Formatter};
use std::sync::mpsc::{Receiver, Sender}; use std::sync::mpsc::{Receiver, Sender};
use style_traits::cursor::CursorKind;
use style_traits::viewport::ViewportConstraints; use style_traits::viewport::ViewportConstraints;
use webrender; use webrender;
use webrender_api::{self, DeviceIntPoint, DeviceUintSize}; 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<EventLoopWaker + Send>;
fn wake(&self);
}
/// Sends messages to the embedder.
pub struct EmbedderProxy {
pub sender: Sender<EmbedderMsg>,
pub event_loop_waker: Box<EventLoopWaker>,
}
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<EmbedderMsg>
}
impl EmbedderReceiver {
pub fn try_recv_embedder_msg(&mut self) -> Option<EmbedderMsg> {
self.receiver.try_recv().ok()
}
pub fn recv_embedder_msg(&mut self) -> EmbedderMsg {
self.receiver.recv().unwrap()
}
}
/// Sends messages to the compositor. /// Sends messages to the compositor.
pub struct CompositorProxy { pub struct CompositorProxy {
pub sender: Sender<Msg>, pub sender: Sender<Msg>,
@ -113,47 +66,6 @@ impl CompositorProxy {
} }
} }
pub enum EmbedderMsg {
/// A status message to be displayed by the browser chrome.
Status(TopLevelBrowsingContextId, Option<String>),
/// Alerts the embedder that the current page has changed its title.
ChangePageTitle(TopLevelBrowsingContextId, Option<String>),
/// 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<bool>),
/// Sends an unconsumed key event back to the embedder.
KeyEvent(Option<TopLevelBrowsingContextId>, Option<char>, Key, KeyState, KeyModifiers),
/// Changes the cursor.
SetCursor(CursorKind),
/// A favicon was detected
NewFavicon(TopLevelBrowsingContextId, ServoUrl),
/// <head> tag finished parsing
HeadParsed(TopLevelBrowsingContextId),
/// The history state has changed.
HistoryChanged(TopLevelBrowsingContextId, Vec<LoadData>, 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<String>),
/// Open dialog to select bluetooth device.
GetSelectedBluetoothDevice(Vec<String>, IpcSender<Option<String>>),
/// Open file dialog to select files. Set boolean flag to true allows to select multiple files.
SelectFiles(Vec<FilterPattern>, bool, IpcSender<Option<Vec<String>>>),
/// 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. /// Messages from the painting thread and the constellation thread to the compositor thread.
pub enum Msg { pub enum Msg {
/// Requests that the compositor shut down. /// 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. /// Data used to construct a compositor.
pub struct InitialCompositorState { pub struct InitialCompositorState {
/// A channel to the compositor. /// A channel to the compositor.

View file

@ -4,6 +4,7 @@
#![deny(unsafe_code)] #![deny(unsafe_code)]
extern crate embedder_traits;
extern crate euclid; extern crate euclid;
extern crate gfx_traits; extern crate gfx_traits;
#[cfg(feature = "gleam")] #[cfg(feature = "gleam")]

View file

@ -4,7 +4,7 @@
//! Abstract windowing methods. The concrete implementations of these can be found in `platform/`. //! Abstract windowing methods. The concrete implementations of these can be found in `platform/`.
use compositor_thread::EventLoopWaker; use embedder_traits::EventLoopWaker;
use euclid::TypedScale; use euclid::TypedScale;
#[cfg(feature = "gleam")] #[cfg(feature = "gleam")]
use gleam::gl; use gleam::gl;
@ -78,6 +78,8 @@ pub enum WindowEvent {
NewBrowser(ServoUrl, IpcSender<TopLevelBrowsingContextId>), NewBrowser(ServoUrl, IpcSender<TopLevelBrowsingContextId>),
/// Close a top level browsing context /// Close a top level browsing context
CloseBrowser(TopLevelBrowsingContextId), CloseBrowser(TopLevelBrowsingContextId),
/// Panic a top level browsing context.
SendError(Option<TopLevelBrowsingContextId>, String),
/// Make a top level browsing context visible, hiding the previous /// Make a top level browsing context visible, hiding the previous
/// visible one. /// visible one.
SelectBrowser(TopLevelBrowsingContextId), SelectBrowser(TopLevelBrowsingContextId),
@ -106,6 +108,7 @@ impl Debug for WindowEvent {
WindowEvent::Quit => write!(f, "Quit"), WindowEvent::Quit => write!(f, "Quit"),
WindowEvent::Reload(..) => write!(f, "Reload"), WindowEvent::Reload(..) => write!(f, "Reload"),
WindowEvent::NewBrowser(..) => write!(f, "NewBrowser"), WindowEvent::NewBrowser(..) => write!(f, "NewBrowser"),
WindowEvent::SendError(..) => write!(f, "SendError"),
WindowEvent::CloseBrowser(..) => write!(f, "CloseBrowser"), WindowEvent::CloseBrowser(..) => write!(f, "CloseBrowser"),
WindowEvent::SelectBrowser(..) => write!(f, "SelectBrowser"), WindowEvent::SelectBrowser(..) => write!(f, "SelectBrowser"),
WindowEvent::ToggleWebRenderDebug(..) => write!(f, "ToggleWebRenderDebug"), WindowEvent::ToggleWebRenderDebug(..) => write!(f, "ToggleWebRenderDebug"),

View file

@ -98,10 +98,11 @@ use canvas_traits::canvas::CanvasId;
use canvas_traits::canvas::CanvasMsg; use canvas_traits::canvas::CanvasMsg;
use clipboard::{ClipboardContext, ClipboardProvider}; use clipboard::{ClipboardContext, ClipboardProvider};
use compositing::SendableFrameTree; use compositing::SendableFrameTree;
use compositing::compositor_thread::{CompositorProxy, EmbedderMsg, EmbedderProxy}; use compositing::compositor_thread::CompositorProxy;
use compositing::compositor_thread::Msg as ToCompositorMsg; use compositing::compositor_thread::Msg as ToCompositorMsg;
use debugger; use debugger;
use devtools_traits::{ChromeToDevtoolsControlMsg, DevtoolsControlMsg}; use devtools_traits::{ChromeToDevtoolsControlMsg, DevtoolsControlMsg};
use embedder_traits::{EmbedderMsg, EmbedderProxy};
use euclid::{Size2D, TypedSize2D, TypedScale}; use euclid::{Size2D, TypedSize2D, TypedScale};
use event_loop::EventLoop; use event_loop::EventLoop;
use gfx::font_cache_thread::FontCacheThread; use gfx::font_cache_thread::FontCacheThread;
@ -969,6 +970,15 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
FromCompositorMsg::CloseBrowser(top_level_browsing_context_id) => { FromCompositorMsg::CloseBrowser(top_level_browsing_context_id) => {
self.handle_close_top_level_browsing_context(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. // Send frame tree to WebRender. Make it visible.
FromCompositorMsg::SelectBrowser(top_level_browsing_context_id) => { FromCompositorMsg::SelectBrowser(top_level_browsing_context_id) => {
self.send_frame_tree(top_level_browsing_context_id); self.send_frame_tree(top_level_browsing_context_id);
@ -1014,12 +1024,10 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
Some(ctx) => ctx, 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 { match content {
FromScriptMsg::ForwardToEmbedder(embedder_msg) => {
self.embedder_proxy.send(embedder_msg);
}
FromScriptMsg::PipelineExited => { FromScriptMsg::PipelineExited => {
self.handle_pipeline_exited(source_pipeline_id); self.handle_pipeline_exited(source_pipeline_id);
} }
@ -1119,34 +1127,12 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
warn!("Error replying to remove iframe ({})", e); 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) => { FromScriptMsg::CreateCanvasPaintThread(size, sender) => {
self.handle_create_canvas_paint_thread_msg(&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) => { FromScriptMsg::SetDocumentState(state) => {
self.document_states.insert(source_pipeline_id, 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) => { FromScriptMsg::GetClientWindow(send) => {
self.compositor_proxy.send(ToCompositorMsg::GetClientWindow(send)); self.compositor_proxy.send(ToCompositorMsg::GetClientWindow(send));
} }
@ -1162,15 +1148,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
FromScriptMsg::LogEntry(thread_name, entry) => { FromScriptMsg::LogEntry(thread_name, entry) => {
self.handle_log_entry(Some(source_top_ctx_id), 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) => { FromScriptMsg::TouchEventProcessed(result) => {
self.compositor_proxy.send(ToCompositorMsg::TouchEventProcessed(result)) self.compositor_proxy.send(ToCompositorMsg::TouchEventProcessed(result))
} }
@ -1208,15 +1185,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
FromScriptMsg::BroadcastStorageEvent(storage, url, key, old_value, new_value) => { FromScriptMsg::BroadcastStorageEvent(storage, url, key, old_value, new_value) => {
self.handle_broadcast_storage_event(source_pipeline_id, 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<Message, LTF, STF> Constellation<Message, LTF, STF>
} }
} }
fn handle_alert(&mut self,
top_level_browsing_context_id: TopLevelBrowsingContextId,
_message: String,
sender: IpcSender<bool>) {
// 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, fn handle_load_url_msg(&mut self, top_level_browsing_context_id: TopLevelBrowsingContextId, source_id: PipelineId,
load_data: LoadData, replace: bool) { load_data: LoadData, replace: bool) {
self.load_url(top_level_browsing_context_id, source_id, load_data, replace); self.load_url(top_level_browsing_context_id, source_id, load_data, replace);
@ -2451,8 +2402,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
entries.extend(session_history.future.iter().rev() entries.extend(session_history.future.iter().rev()
.scan(current_load_data.clone(), &resolve_load_data_future)); .scan(current_load_data.clone(), &resolve_load_data_future));
let urls = entries.iter().map(|entry| entry.url.clone()).collect();
let msg = EmbedderMsg::HistoryChanged(top_level_browsing_context_id, entries, current_index); let msg = EmbedderMsg::HistoryChanged(top_level_browsing_context_id, urls, current_index);
self.embedder_proxy.send(msg); self.embedder_proxy.send(msg);
} }

View file

@ -14,7 +14,7 @@ extern crate clipboard;
extern crate compositing; extern crate compositing;
extern crate debugger; extern crate debugger;
extern crate devtools_traits; 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 embedder_traits;
extern crate euclid; extern crate euclid;
#[cfg(all(not(target_os = "windows"), not(target_os = "ios")))] #[cfg(all(not(target_os = "windows"), not(target_os = "ios")))]

View file

@ -13,4 +13,11 @@ path = "lib.rs"
tests = [] tests = []
[dependencies] [dependencies]
ipc-channel = "0.10"
lazy_static = "1" 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"]}

View file

@ -2,6 +2,146 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * 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; 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<EventLoopWaker + Send>;
fn wake(&self);
}
/// Sends messages to the embedder.
pub struct EmbedderProxy {
pub sender: Sender<EmbedderMsg>,
pub event_loop_waker: Box<EventLoopWaker>,
}
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<EmbedderMsg>
}
impl EmbedderReceiver {
pub fn try_recv_embedder_msg(&mut self) -> Option<EmbedderMsg> {
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<String>),
/// Alerts the embedder that the current page has changed its title.
ChangePageTitle(TopLevelBrowsingContextId, Option<String>),
/// 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<bool>),
/// Sends an unconsumed key event back to the embedder.
KeyEvent(Option<TopLevelBrowsingContextId>, Option<char>, Key, KeyState, KeyModifiers),
/// Changes the cursor.
SetCursor(CursorKind),
/// A favicon was detected
NewFavicon(TopLevelBrowsingContextId, ServoUrl),
/// <head> tag finished parsing
HeadParsed(TopLevelBrowsingContextId),
/// The history state has changed.
HistoryChanged(TopLevelBrowsingContextId, Vec<ServoUrl>, 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<String>),
/// Open dialog to select bluetooth device.
GetSelectedBluetoothDevice(Vec<String>, IpcSender<Option<String>>),
/// Open file dialog to select files. Set boolean flag to true allows to select multiple files.
SelectFiles(Vec<FilterPattern>, bool, IpcSender<Option<Vec<String>>>),
/// 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);

View file

@ -16,7 +16,6 @@ doctest = false
base64 = "0.6" base64 = "0.6"
brotli = "1.0.6" brotli = "1.0.6"
cookie = "0.10" cookie = "0.10"
compositing = {path = "../compositing"}
devtools_traits = {path = "../devtools_traits"} devtools_traits = {path = "../devtools_traits"}
embedder_traits = { path = "../embedder_traits" } embedder_traits = { path = "../embedder_traits" }
flate2 = "1" flate2 = "1"

View file

@ -2,11 +2,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * 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 ipc_channel::ipc::{self, IpcSender};
use mime_guess::guess_mime_type_opt; use mime_guess::guess_mime_type_opt;
use net_traits::blob_url_store::{BlobBuf, BlobURLStoreError}; 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 net_traits::filemanager_thread::{FileManagerThreadError, ReadFileProgress, RelativePos, SelectedFile};
use servo_config::prefs::PREFS; use servo_config::prefs::PREFS;
use std::collections::HashMap; use std::collections::HashMap;

View file

@ -6,7 +6,6 @@
extern crate base64; extern crate base64;
extern crate brotli; extern crate brotli;
extern crate compositing;
extern crate cookie as cookie_rs; extern crate cookie as cookie_rs;
extern crate devtools_traits; extern crate devtools_traits;
extern crate embedder_traits; extern crate embedder_traits;

View file

@ -3,12 +3,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! A thread that takes a URL and streams back the binary data. //! 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 connector::{create_http_connector, create_ssl_client};
use cookie; use cookie;
use cookie_rs; use cookie_rs;
use cookie_storage::CookieStorage; use cookie_storage::CookieStorage;
use devtools_traits::DevtoolsControlMsg; use devtools_traits::DevtoolsControlMsg;
use embedder_traits::EmbedderProxy;
use embedder_traits::resources::{self, Resource}; use embedder_traits::resources::{self, Resource};
use fetch::cors_cache::CorsCache; use fetch::cors_cache::CorsCache;
use fetch::methods::{CancellationListener, FetchContext, fetch}; use fetch::methods::{CancellationListener, FetchContext, fetch};

View file

@ -3,10 +3,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use create_embedder_proxy; use create_embedder_proxy;
use embedder_traits::FilterPattern;
use ipc_channel::ipc; use ipc_channel::ipc;
use net::filemanager_thread::FileManager; use net::filemanager_thread::FileManager;
use net_traits::blob_url_store::BlobURLStoreError; 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 servo_config::prefs::{PrefValue, PREFS};
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::Read;

View file

@ -4,7 +4,6 @@
#![cfg(test)] #![cfg(test)]
extern crate compositing;
extern crate cookie as cookie_rs; extern crate cookie as cookie_rs;
extern crate devtools_traits; extern crate devtools_traits;
extern crate embedder_traits; extern crate embedder_traits;
@ -35,8 +34,8 @@ mod mime_classifier;
mod resource_thread; mod resource_thread;
mod subresource_integrity; mod subresource_integrity;
use compositing::compositor_thread::{EmbedderProxy, EventLoopWaker};
use devtools_traits::DevtoolsControlMsg; use devtools_traits::DevtoolsControlMsg;
use embedder_traits::{EmbedderProxy, EventLoopWaker};
use embedder_traits::resources::{self, Resource}; use embedder_traits::resources::{self, Resource};
use hyper::server::{Handler, Listening, Server}; use hyper::server::{Handler, Listening, Server};
use net::connector::create_ssl_client; use net::connector::create_ssl_client;

View file

@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use blob_url_store::{BlobBuf, BlobURLStoreError}; use blob_url_store::{BlobBuf, BlobURLStoreError};
use embedder_traits::FilterPattern;
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
use num_traits::ToPrimitive; use num_traits::ToPrimitive;
use std::cmp::{max, min}; use std::cmp::{max, min};
@ -110,11 +111,6 @@ pub struct SelectedFile {
pub type_string: String, 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)] #[derive(Deserialize, Serialize)]
pub enum FileManagerThreadMsg { pub enum FileManagerThreadMsg {
/// Select a single file. Last field is pre-selected file path for testing /// Select a single file. Last field is pre-selected file path for testing

View file

@ -88,6 +88,7 @@ use dom::webglcontextevent::WebGLContextEvent;
use dom::window::{ReflowReason, Window}; use dom::window::{ReflowReason, Window};
use dom::windowproxy::WindowProxy; use dom::windowproxy::WindowProxy;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use embedder_traits::EmbedderMsg;
use encoding_rs::{Encoding, UTF_8}; use encoding_rs::{Encoding, UTF_8};
use euclid::Point2D; use euclid::Point2D;
use fetch::FetchCanceller; use fetch::FetchCanceller;
@ -855,7 +856,8 @@ impl Document {
// Notify the embedder to hide the input method. // Notify the embedder to hide the input method.
if elem.input_method_type().is_some() { 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. // Update the focus state for all elements in the focus chain.
// https://html.spec.whatwg.org/multipage/#focus-chain // https://html.spec.whatwg.org/multipage/#focus-chain
if focus_type == FocusType::Element { 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. // Notify the embedder to display an input method.
if let Some(kind) = elem.input_method_type() { 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. /// Handles any updates when the document's title has changed.
pub fn title_changed(&self) { pub fn title_changed(&self) {
if self.browsing_context().is_some() { if self.browsing_context().is_some() {
self.send_title_to_constellation(); self.send_title_to_embedder();
} }
} }
/// Sends this document's title to the constellation. /// Sends this document's title to the constellation.
pub fn send_title_to_constellation(&self) { pub fn send_title_to_embedder(&self) {
let title = Some(String::from(self.Title())); let window = self.window();
self.send_to_constellation(ScriptMsg::SetTitle(title)); 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) { pub fn dirty_all_nodes(&self) {
@ -1352,8 +1364,9 @@ impl Document {
} }
if cancel_state == EventDefault::Allowed { if cancel_state == EventDefault::Allowed {
let msg = ScriptMsg::SendKeyEvent(ch, key, state, modifiers); let top_level_browsing_context_id = self.window().top_level_browsing_context_id();
self.send_to_constellation(msg); let msg = EmbedderMsg::KeyEvent(Some(top_level_browsing_context_id), ch, key, state, modifiers);
self.send_to_embedder(msg);
// This behavior is unspecced // This behavior is unspecced
// We are supposed to dispatch synthetic click activation for Space and/or Return, // We are supposed to dispatch synthetic click activation for Space and/or Return,
@ -1488,7 +1501,7 @@ impl Document {
// repeated rAF. // repeated rAF.
let event = ScriptMsg::ChangeRunningAnimationsState(AnimationState::AnimationCallbacksPresent); let event = ScriptMsg::ChangeRunningAnimationsState(AnimationState::AnimationCallbacksPresent);
self.send_to_constellation(event); self.window().send_to_constellation(event);
} }
ident ident
@ -1559,7 +1572,7 @@ impl Document {
); );
} }
let event = ScriptMsg::ChangeRunningAnimationsState(AnimationState::NoAnimationCallbacksPresent); let event = ScriptMsg::ChangeRunningAnimationsState(AnimationState::NoAnimationCallbacksPresent);
self.send_to_constellation(event); self.window().send_to_constellation(event);
} }
// Update the counter of spurious animation frames. // Update the counter of spurious animation frames.
@ -2009,7 +2022,7 @@ impl Document {
} }
pub fn notify_constellation_load(&self) { 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>) { pub fn set_current_parser(&self, script: Option<&ServoParser>) {
@ -2167,11 +2180,6 @@ impl Document {
registry.lookup_definition(local_name, is) registry.lookup_definition(local_name, is)
} }
fn send_to_constellation(&self, msg: ScriptMsg) {
let global_scope = self.window.upcast::<GlobalScope>();
global_scope.script_to_constellation_chan().send(msg).unwrap();
}
pub fn increment_throw_on_dynamic_markup_insertion_counter(&self) { pub fn increment_throw_on_dynamic_markup_insertion_counter(&self) {
let counter = self.throw_on_dynamic_markup_insertion_counter.get(); let counter = self.throw_on_dynamic_markup_insertion_counter.get();
self.throw_on_dynamic_markup_insertion_counter.set(counter + 1); self.throw_on_dynamic_markup_insertion_counter.set(counter + 1);
@ -2787,8 +2795,9 @@ impl Document {
let window = self.window(); let window = self.window();
// Step 6 // Step 6
if !error { if !error {
let event = ScriptMsg::SetFullscreenState(true); let top_level_browsing_context_id = self.window().top_level_browsing_context_id();
self.send_to_constellation(event); let event = EmbedderMsg::SetFullscreenState(top_level_browsing_context_id, true);
self.send_to_embedder(event);
} }
let pipeline_id = self.window().pipeline_id(); let pipeline_id = self.window().pipeline_id();
@ -2822,8 +2831,9 @@ impl Document {
let window = self.window(); let window = self.window();
// Step 8 // Step 8
let event = ScriptMsg::SetFullscreenState(false); let top_level_browsing_context_id = self.window().top_level_browsing_context_id();
self.send_to_constellation(event); let event = EmbedderMsg::SetFullscreenState(top_level_browsing_context_id, true);
self.send_to_embedder(event);
// Step 9 // Step 9
let trusted_element = Trusted::new(element.r()); let trusted_element = Trusted::new(element.r());

View file

@ -12,13 +12,12 @@ use dom::bindings::str::DOMString;
use dom::document::Document; use dom::document::Document;
use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers}; use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers};
use dom::eventtarget::EventTarget; use dom::eventtarget::EventTarget;
use dom::globalscope::GlobalScope;
use dom::htmlelement::HTMLElement; use dom::htmlelement::HTMLElement;
use dom::node::{Node, document_from_node, window_from_node}; use dom::node::{Node, document_from_node, window_from_node};
use dom::virtualmethods::VirtualMethods; use dom::virtualmethods::VirtualMethods;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use embedder_traits::EmbedderMsg;
use html5ever::{LocalName, Prefix}; use html5ever::{LocalName, Prefix};
use script_traits::ScriptMsg;
use servo_url::ServoUrl; use servo_url::ServoUrl;
use style::attr::AttrValue; use style::attr::AttrValue;
use time; use time;
@ -151,8 +150,11 @@ impl VirtualMethods for HTMLBodyElement {
let window = window_from_node(self); let window = window_from_node(self);
let document = window.Document(); let document = window.Document();
document.set_reflow_timeout(time::precise_time_ns() + INITIAL_REFLOW_DELAY); document.set_reflow_timeout(time::precise_time_ns() + INITIAL_REFLOW_DELAY);
let event = ScriptMsg::HeadParsed; if window.is_top_level() {
window.upcast::<GlobalScope>().script_to_constellation_chan().send(event).unwrap(); 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 { fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {

View file

@ -38,12 +38,13 @@ use dom::validation::Validatable;
use dom::validitystate::ValidationFlags; use dom::validitystate::ValidationFlags;
use dom::virtualmethods::VirtualMethods; use dom::virtualmethods::VirtualMethods;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use embedder_traits::FilterPattern;
use html5ever::{LocalName, Prefix}; use html5ever::{LocalName, Prefix};
use mime_guess; use mime_guess;
use msg::constellation_msg::InputMethodType; use msg::constellation_msg::InputMethodType;
use net_traits::{CoreResourceMsg, IpcSend}; use net_traits::{CoreResourceMsg, IpcSend};
use net_traits::blob_url_store::get_blob_origin; 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 profile_traits::ipc;
use script_layout_interface::rpc::TextIndexResponse; use script_layout_interface::rpc::TextIndexResponse;
use script_traits::ScriptToConstellationChan; use script_traits::ScriptToConstellationChan;

View file

@ -16,15 +16,14 @@ use dom::document::Document;
use dom::domtokenlist::DOMTokenList; use dom::domtokenlist::DOMTokenList;
use dom::element::{AttributeMutation, Element, ElementCreator}; use dom::element::{AttributeMutation, Element, ElementCreator};
use dom::element::{cors_setting_for_element, reflect_cross_origin_attribute, set_cross_origin_attribute}; 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::htmlelement::HTMLElement;
use dom::node::{Node, UnbindContext, document_from_node, window_from_node}; use dom::node::{Node, UnbindContext, document_from_node, window_from_node};
use dom::stylesheet::StyleSheet as DOMStyleSheet; use dom::stylesheet::StyleSheet as DOMStyleSheet;
use dom::virtualmethods::VirtualMethods; use dom::virtualmethods::VirtualMethods;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use embedder_traits::EmbedderMsg;
use html5ever::{LocalName, Prefix}; use html5ever::{LocalName, Prefix};
use net_traits::ReferrerPolicy; use net_traits::ReferrerPolicy;
use script_traits::ScriptMsg;
use servo_arc::Arc; use servo_arc::Arc;
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::cell::Cell; use std::cell::Cell;
@ -306,8 +305,13 @@ impl HTMLLinkElement {
let document = document_from_node(self); let document = document_from_node(self);
match document.base_url().join(href) { match document.base_url().join(href) {
Ok(url) => { Ok(url) => {
let event = ScriptMsg::NewFavicon(url.clone()); let window = document.window();
document.window().upcast::<GlobalScope>().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::NewFavicon(top_level_browsing_context_id, url.clone());
window.send_to_embedder(msg);
}
} }
Err(e) => debug!("Parsing url {} failed: {}", href, e) Err(e) => debug!("Parsing url {} failed: {}", href, e)
} }

View file

@ -48,6 +48,7 @@ use dom::windowproxy::WindowProxy;
use dom::worklet::Worklet; use dom::worklet::Worklet;
use dom::workletglobalscope::WorkletGlobalScopeType; use dom::workletglobalscope::WorkletGlobalScopeType;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use embedder_traits::EmbedderMsg;
use euclid::{Point2D, Vector2D, Rect, Size2D, TypedPoint2D, TypedScale, TypedSize2D}; use euclid::{Point2D, Vector2D, Rect, Size2D, TypedPoint2D, TypedScale, TypedSize2D};
use fetch; use fetch;
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
@ -58,7 +59,7 @@ use js::jsval::UndefinedValue;
use js::rust::HandleValue; use js::rust::HandleValue;
use layout_image::fetch_image_for_layout; use layout_image::fetch_image_for_layout;
use microtask::MicrotaskQueue; use microtask::MicrotaskQueue;
use msg::constellation_msg::PipelineId; use msg::constellation_msg::{PipelineId, TopLevelBrowsingContextId};
use net_traits::{ResourceThreads, ReferrerPolicy}; use net_traits::{ResourceThreads, ReferrerPolicy};
use net_traits::image_cache::{ImageCache, ImageResponder, ImageResponse}; use net_traits::image_cache::{ImageCache, ImageResponder, ImageResponse};
use net_traits::image_cache::{PendingImageId, PendingImageResponse}; use net_traits::image_cache::{PendingImageId, PendingImageResponse};
@ -114,8 +115,6 @@ use task_source::performance_timeline::PerformanceTimelineTaskSource;
use task_source::user_interaction::UserInteractionTaskSource; use task_source::user_interaction::UserInteractionTaskSource;
use time; use time;
use timers::{IsInterval, TimerCallback}; use timers::{IsInterval, TimerCallback};
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
use tinyfiledialogs::{self, MessageBoxIcon};
use url::Position; use url::Position;
use webdriver_handlers::jsval_to_webdriver; use webdriver_handlers::jsval_to_webdriver;
use webrender_api::{ExternalScrollId, DeviceIntPoint, DeviceUintSize, DocumentId}; use webrender_api::{ExternalScrollId, DeviceIntPoint, DeviceUintSize, DocumentId};
@ -356,6 +355,11 @@ impl Window {
self.parent_info 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<ScriptChan + Send>, Box<ScriptPort + Send>) { pub fn new_script_pair(&self) -> (Box<ScriptChan + Send>, Box<ScriptPort + Send>) {
let (tx, rx) = channel(); let (tx, rx) = channel();
(Box::new(SendableMainThreadScriptChan(tx)), Box::new(rx)) (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 // https://html.spec.whatwg.org/multipage/#atob
pub fn base64_btoa(input: DOMString) -> Fallible<DOMString> { pub fn base64_btoa(input: DOMString) -> Fallible<DOMString> {
// "The btoa() method must throw an InvalidCharacterError exception if // "The btoa() method must throw an InvalidCharacterError exception if
@ -541,14 +533,12 @@ impl WindowMethods for Window {
stdout.flush().unwrap(); stdout.flush().unwrap();
stderr.flush().unwrap(); stderr.flush().unwrap();
} }
let (sender, receiver) = ProfiledIpc::channel(self.global().time_profiler_chan().clone()).unwrap(); let (sender, receiver) = ProfiledIpc::channel(self.global().time_profiler_chan().clone()).unwrap();
self.send_to_constellation(ScriptMsg::Alert(s.to_string(), sender)); let window_proxy = self.window_proxy.get().unwrap();
let top_level_browsing_context_id = window_proxy.top_level_browsing_context_id();
let should_display_alert_dialog = receiver.recv().unwrap(); let msg = EmbedderMsg::Alert(top_level_browsing_context_id, s.to_string(), sender);
if should_display_alert_dialog { self.send_to_embedder(msg);
display_alert_dialog(&s); receiver.recv().unwrap();
}
} }
// https://html.spec.whatwg.org/multipage/#dom-window-closed // https://html.spec.whatwg.org/multipage/#dom-window-closed
@ -937,7 +927,8 @@ impl WindowMethods for Window {
//TODO determine if this operation is allowed //TODO determine if this operation is allowed
let dpr = self.device_pixel_ratio(); let dpr = self.device_pixel_ratio();
let size = TypedSize2D::new(width, height).to_f32() * dpr; 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 // https://drafts.csswg.org/cssom-view/#dom-window-resizeby
@ -953,7 +944,10 @@ impl WindowMethods for Window {
//TODO determine if this operation is allowed //TODO determine if this operation is allowed
let dpr = self.device_pixel_ratio(); let dpr = self.device_pixel_ratio();
let point = TypedPoint2D::new(x, y).to_f32() * dpr; 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 // https://drafts.csswg.org/cssom-view/#dom-window-moveby
@ -1742,7 +1736,11 @@ impl Window {
self.navigation_start_precise.set(time::precise_time_ns()); 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::<GlobalScope>() self.upcast::<GlobalScope>()
.script_to_constellation_chan() .script_to_constellation_chan()
.send(msg) .send(msg)

View file

@ -93,7 +93,7 @@ extern crate style;
extern crate style_traits; extern crate style_traits;
extern crate swapper; extern crate swapper;
extern crate time; extern crate time;
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] #[cfg(target_os = "linux")]
extern crate tinyfiledialogs; extern crate tinyfiledialogs;
extern crate unicode_segmentation; extern crate unicode_segmentation;
extern crate url; extern crate url;

View file

@ -62,6 +62,7 @@ use dom::windowproxy::WindowProxy;
use dom::worker::TrustedWorkerAddress; use dom::worker::TrustedWorkerAddress;
use dom::worklet::WorkletThreadPool; use dom::worklet::WorkletThreadPool;
use dom::workletglobalscope::WorkletGlobalScopeInit; use dom::workletglobalscope::WorkletGlobalScopeInit;
use embedder_traits::EmbedderMsg;
use euclid::{Point2D, Vector2D, Rect}; use euclid::{Point2D, Vector2D, Rect};
use fetch::FetchCanceller; use fetch::FetchCanceller;
use hyper::header::{ContentType, HttpDate, Headers, LastModified}; use hyper::header::{ContentType, HttpDate, Headers, LastModified};
@ -1822,7 +1823,7 @@ impl ScriptThread {
Some(document) => document, Some(document) => document,
None => return warn!("Message sent to closed pipeline {}.", pipeline_id), 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. /// Handles a request to exit a pipeline and shut down layout.
@ -2282,6 +2283,8 @@ impl ScriptThread {
Some(document) => document, Some(document) => document,
None => return warn!("Message sent to closed pipeline {}.", pipeline_id), 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 // Get the previous target temporarily
let prev_mouse_over_target = self.topmost_mouse_over_target.get(); let prev_mouse_over_target = self.topmost_mouse_over_target.get();
@ -2310,9 +2313,8 @@ impl ScriptThread {
let url = document.url(); let url = document.url();
url.join(&value).map(|url| url.to_string()).ok() url.join(&value).map(|url| url.to_string()).ok()
}); });
let event = EmbedderMsg::Status(top_level_browsing_context_id, status);
let event = ScriptMsg::NodeStatus(status); window.send_to_embedder(event);
self.script_sender.send((pipeline_id, event)).unwrap();
state_already_changed = true; state_already_changed = true;
} }
@ -2325,8 +2327,8 @@ impl ScriptThread {
.inclusive_ancestors() .inclusive_ancestors()
.filter_map(DomRoot::downcast::<HTMLAnchorElement>) .filter_map(DomRoot::downcast::<HTMLAnchorElement>)
.next() { .next() {
let event = ScriptMsg::NodeStatus(None); let event = EmbedderMsg::Status(top_level_browsing_context_id, None);
self.script_sender.send((pipeline_id, event)).unwrap(); window.send_to_embedder(event);
} }
} }
} }

View file

@ -14,6 +14,7 @@ bluetooth_traits = {path = "../bluetooth_traits"}
canvas_traits = {path = "../canvas_traits"} canvas_traits = {path = "../canvas_traits"}
cookie = "0.10" cookie = "0.10"
devtools_traits = {path = "../devtools_traits"} devtools_traits = {path = "../devtools_traits"}
embedder_traits = {path = "../embedder_traits"}
euclid = "0.17" euclid = "0.17"
gfx_traits = {path = "../gfx_traits"} gfx_traits = {path = "../gfx_traits"}
hyper = "0.10" hyper = "0.10"
@ -34,3 +35,6 @@ time = "0.1.12"
url = "1.2" url = "1.2"
webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]}
webvr_traits = {path = "../webvr_traits"} webvr_traits = {path = "../webvr_traits"}
[dev-dependencies]
embedder_traits = { path = "../embedder_traits", features = ["tests"]}

View file

@ -13,6 +13,7 @@ extern crate bluetooth_traits;
extern crate canvas_traits; extern crate canvas_traits;
extern crate cookie as cookie_rs; extern crate cookie as cookie_rs;
extern crate devtools_traits; extern crate devtools_traits;
extern crate embedder_traits;
extern crate euclid; extern crate euclid;
extern crate gfx_traits; extern crate gfx_traits;
extern crate hyper; extern crate hyper;
@ -702,6 +703,8 @@ pub enum ConstellationMsg {
NewBrowser(ServoUrl, IpcSender<TopLevelBrowsingContextId>), NewBrowser(ServoUrl, IpcSender<TopLevelBrowsingContextId>),
/// Close a top level browsing context. /// Close a top level browsing context.
CloseBrowser(TopLevelBrowsingContextId), CloseBrowser(TopLevelBrowsingContextId),
/// Panic a top level browsing context.
SendError(Option<TopLevelBrowsingContextId>, String),
/// Make browser visible. /// Make browser visible.
SelectBrowser(TopLevelBrowsingContextId), SelectBrowser(TopLevelBrowsingContextId),
/// Forward an event to the script task of the given pipeline. /// Forward an event to the script task of the given pipeline.
@ -730,6 +733,7 @@ impl fmt::Debug for ConstellationMsg {
WebVREvents(..) => "WebVREvents", WebVREvents(..) => "WebVREvents",
NewBrowser(..) => "NewBrowser", NewBrowser(..) => "NewBrowser",
CloseBrowser(..) => "CloseBrowser", CloseBrowser(..) => "CloseBrowser",
SendError(..) => "SendError",
SelectBrowser(..) => "SelectBrowser", SelectBrowser(..) => "SelectBrowser",
ForwardEvent(..) => "ForwardEvent", ForwardEvent(..) => "ForwardEvent",
SetCursor(..) => "SetCursor", SetCursor(..) => "SetCursor",

View file

@ -12,11 +12,11 @@ use WorkerGlobalScopeInit;
use WorkerScriptLoadOrigin; use WorkerScriptLoadOrigin;
use canvas_traits::canvas::{CanvasMsg, CanvasId}; use canvas_traits::canvas::{CanvasMsg, CanvasId};
use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId}; use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId};
use embedder_traits::EmbedderMsg;
use euclid::{Size2D, TypedSize2D}; use euclid::{Size2D, TypedSize2D};
use gfx_traits::Epoch; use gfx_traits::Epoch;
use ipc_channel::ipc::{IpcReceiver, IpcSender}; use ipc_channel::ipc::{IpcReceiver, IpcSender};
use msg::constellation_msg::{BrowsingContextId, HistoryStateId, PipelineId, TraversalDirection}; use msg::constellation_msg::{BrowsingContextId, HistoryStateId, PipelineId, TraversalDirection};
use msg::constellation_msg::{InputMethodType, Key, KeyModifiers, KeyState};
use net_traits::CoreResourceMsg; use net_traits::CoreResourceMsg;
use net_traits::request::RequestInit; use net_traits::request::RequestInit;
use net_traits::storage_thread::StorageType; use net_traits::storage_thread::StorageType;
@ -83,6 +83,8 @@ pub enum LogEntry {
/// Messages from the script to the constellation. /// Messages from the script to the constellation.
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub enum ScriptMsg { pub enum ScriptMsg {
/// Forward a message to the embedder.
ForwardToEmbedder(EmbedderMsg),
/// Requests are sent to constellation and fetches are checked manually /// Requests are sent to constellation and fetches are checked manually
/// for cross-origin loads /// for cross-origin loads
InitiateNavigateRequest(RequestInit, /* cancellation_chan */ IpcReceiver<()>), InitiateNavigateRequest(RequestInit, /* cancellation_chan */ IpcReceiver<()>),
@ -104,8 +106,6 @@ pub enum ScriptMsg {
GetParentInfo(PipelineId, IpcSender<Option<PipelineId>>), GetParentInfo(PipelineId, IpcSender<Option<PipelineId>>),
/// Get the nth child browsing context ID for a given browsing context, sorted in tree order. /// Get the nth child browsing context ID for a given browsing context, sorted in tree order.
GetChildBrowsingContextId(BrowsingContextId, usize, IpcSender<Option<BrowsingContextId>>), GetChildBrowsingContextId(BrowsingContextId, usize, IpcSender<Option<BrowsingContextId>>),
/// <head> tag finished parsing
HeadParsed,
/// All pending loads are complete, and the `load` event for this pipeline /// All pending loads are complete, and the `load` event for this pipeline
/// has been dispatched. /// has been dispatched.
LoadComplete, LoadComplete,
@ -124,10 +124,6 @@ pub enum ScriptMsg {
ReplaceHistoryState(HistoryStateId, ServoUrl), ReplaceHistoryState(HistoryStateId, ServoUrl),
/// Gets the length of the joint session history from the constellation. /// Gets the length of the joint session history from the constellation.
JointSessionHistoryLength(IpcSender<u32>), JointSessionHistoryLength(IpcSender<u32>),
/// Favicon detected
NewFavicon(ServoUrl),
/// Status message to be displayed in the chrome, eg. a link URL on mouseover.
NodeStatus(Option<String>),
/// Notification that this iframe should be removed. /// Notification that this iframe should be removed.
/// Returns a list of pipelines which were closed. /// Returns a list of pipelines which were closed.
RemoveIFrame(BrowsingContextId, IpcSender<Vec<PipelineId>>), RemoveIFrame(BrowsingContextId, IpcSender<Vec<PipelineId>>),
@ -147,17 +143,6 @@ pub enum ScriptMsg {
SetDocumentState(DocumentState), SetDocumentState(DocumentState),
/// Update the pipeline Url, which can change after redirections. /// Update the pipeline Url, which can change after redirections.
SetFinalUrl(ServoUrl), SetFinalUrl(ServoUrl),
/// Check if an alert dialog box should be presented
Alert(String, IpcSender<bool>),
/// Set title of current page
/// <https://html.spec.whatwg.org/multipage/#document.title>
SetTitle(Option<String>),
/// Send a key event
SendKeyEvent(Option<char>, 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. /// Script has handled a touch event, and either prevented or allowed default actions.
TouchEventProcessed(EventResult), TouchEventProcessed(EventResult),
/// A log entry, with the top-level browsing context id and thread name /// A log entry, with the top-level browsing context id and thread name
@ -171,18 +156,12 @@ pub enum ScriptMsg {
ForwardDOMMessage(DOMMessage, ServoUrl), ForwardDOMMessage(DOMMessage, ServoUrl),
/// Store the data required to activate a service worker for the given scope /// Store the data required to activate a service worker for the given scope
RegisterServiceWorker(ScopeThings, ServoUrl), RegisterServiceWorker(ScopeThings, ServoUrl),
/// Enter or exit fullscreen
SetFullscreenState(bool),
/// Get Window Informations size and position /// Get Window Informations size and position
GetClientWindow(IpcSender<(DeviceUintSize, DeviceIntPoint)>), GetClientWindow(IpcSender<(DeviceUintSize, DeviceIntPoint)>),
/// Get the screen size (pixel) /// Get the screen size (pixel)
GetScreenSize(IpcSender<(DeviceUintSize)>), GetScreenSize(IpcSender<(DeviceUintSize)>),
/// Get the available screen size (pixel) /// Get the available screen size (pixel)
GetScreenAvailSize(IpcSender<(DeviceUintSize)>), 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. /// Requests that the compositor shut down.
Exit, Exit,
} }
@ -191,6 +170,7 @@ impl fmt::Debug for ScriptMsg {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
use self::ScriptMsg::*; use self::ScriptMsg::*;
let variant = match *self { let variant = match *self {
ForwardToEmbedder(..) => "ForwardToEmbedder",
InitiateNavigateRequest(..) => "InitiateNavigateRequest", InitiateNavigateRequest(..) => "InitiateNavigateRequest",
BroadcastStorageEvent(..) => "BroadcastStorageEvent", BroadcastStorageEvent(..) => "BroadcastStorageEvent",
ChangeRunningAnimationsState(..) => "ChangeRunningAnimationsState", ChangeRunningAnimationsState(..) => "ChangeRunningAnimationsState",
@ -200,7 +180,6 @@ impl fmt::Debug for ScriptMsg {
GetBrowsingContextId(..) => "GetBrowsingContextId", GetBrowsingContextId(..) => "GetBrowsingContextId",
GetParentInfo(..) => "GetParentInfo", GetParentInfo(..) => "GetParentInfo",
GetChildBrowsingContextId(..) => "GetChildBrowsingContextId", GetChildBrowsingContextId(..) => "GetChildBrowsingContextId",
HeadParsed => "HeadParsed",
LoadComplete => "LoadComplete", LoadComplete => "LoadComplete",
LoadUrl(..) => "LoadUrl", LoadUrl(..) => "LoadUrl",
AbortLoadUrl => "AbortLoadUrl", AbortLoadUrl => "AbortLoadUrl",
@ -209,8 +188,6 @@ impl fmt::Debug for ScriptMsg {
PushHistoryState(..) => "PushHistoryState", PushHistoryState(..) => "PushHistoryState",
ReplaceHistoryState(..) => "ReplaceHistoryState", ReplaceHistoryState(..) => "ReplaceHistoryState",
JointSessionHistoryLength(..) => "JointSessionHistoryLength", JointSessionHistoryLength(..) => "JointSessionHistoryLength",
NewFavicon(..) => "NewFavicon",
NodeStatus(..) => "NodeStatus",
RemoveIFrame(..) => "RemoveIFrame", RemoveIFrame(..) => "RemoveIFrame",
SetVisible(..) => "SetVisible", SetVisible(..) => "SetVisible",
VisibilityChangeComplete(..) => "VisibilityChangeComplete", VisibilityChangeComplete(..) => "VisibilityChangeComplete",
@ -220,23 +197,15 @@ impl fmt::Debug for ScriptMsg {
ActivateDocument => "ActivateDocument", ActivateDocument => "ActivateDocument",
SetDocumentState(..) => "SetDocumentState", SetDocumentState(..) => "SetDocumentState",
SetFinalUrl(..) => "SetFinalUrl", SetFinalUrl(..) => "SetFinalUrl",
Alert(..) => "Alert",
SetTitle(..) => "SetTitle",
SendKeyEvent(..) => "SendKeyEvent",
MoveTo(..) => "MoveTo",
ResizeTo(..) => "ResizeTo",
TouchEventProcessed(..) => "TouchEventProcessed", TouchEventProcessed(..) => "TouchEventProcessed",
LogEntry(..) => "LogEntry", LogEntry(..) => "LogEntry",
DiscardDocument => "DiscardDocument", DiscardDocument => "DiscardDocument",
PipelineExited => "PipelineExited", PipelineExited => "PipelineExited",
ForwardDOMMessage(..) => "ForwardDOMMessage", ForwardDOMMessage(..) => "ForwardDOMMessage",
RegisterServiceWorker(..) => "RegisterServiceWorker", RegisterServiceWorker(..) => "RegisterServiceWorker",
SetFullscreenState(..) => "SetFullscreenState",
GetClientWindow(..) => "GetClientWindow", GetClientWindow(..) => "GetClientWindow",
GetScreenSize(..) => "GetScreenSize", GetScreenSize(..) => "GetScreenSize",
GetScreenAvailSize(..) => "GetScreenAvailSize", GetScreenAvailSize(..) => "GetScreenAvailSize",
ShowIME(..) => "ShowIME",
HideIME => "HideIME",
Exit => "Exit", Exit => "Exit",
}; };
write!(formatter, "ScriptMsg::{}", variant) write!(formatter, "ScriptMsg::{}", variant)

View file

@ -73,13 +73,13 @@ use bluetooth_traits::BluetoothRequest;
use canvas::gl_context::GLContextFactory; use canvas::gl_context::GLContextFactory;
use canvas::webgl_thread::WebGLThreads; use canvas::webgl_thread::WebGLThreads;
use compositing::{IOCompositor, ShutdownState, RenderNotifier}; use compositing::{IOCompositor, ShutdownState, RenderNotifier};
use compositing::compositor_thread::{self, CompositorProxy, CompositorReceiver, InitialCompositorState}; use compositing::compositor_thread::{CompositorProxy, CompositorReceiver, InitialCompositorState};
use compositing::compositor_thread::{EmbedderMsg, EmbedderProxy, EmbedderReceiver};
use compositing::windowing::{WindowEvent, WindowMethods}; use compositing::windowing::{WindowEvent, WindowMethods};
use constellation::{Constellation, InitialConstellationState, UnprivilegedPipelineContent}; use constellation::{Constellation, InitialConstellationState, UnprivilegedPipelineContent};
use constellation::{FromCompositorLogger, FromScriptLogger}; use constellation::{FromCompositorLogger, FromScriptLogger};
#[cfg(all(not(target_os = "windows"), not(target_os = "ios")))] #[cfg(all(not(target_os = "windows"), not(target_os = "ios")))]
use constellation::content_process_sandbox_profile; use constellation::content_process_sandbox_profile;
use embedder_traits::{EmbedderMsg, EmbedderProxy, EmbedderReceiver, EventLoopWaker};
use env_logger::Builder as EnvLoggerBuilder; use env_logger::Builder as EnvLoggerBuilder;
use euclid::Length; use euclid::Length;
#[cfg(all(not(target_os = "windows"), not(target_os = "ios")))] #[cfg(all(not(target_os = "windows"), not(target_os = "ios")))]
@ -346,6 +346,13 @@ impl<Window> Servo<Window> where Window: WindowMethods + 'static {
warn!("Sending CloseBrowser message to constellation failed ({}).", e); 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<Window> Servo<Window> where Window: WindowMethods + 'static {
} }
} }
fn create_embedder_channel(event_loop_waker: Box<compositor_thread::EventLoopWaker>) fn create_embedder_channel(event_loop_waker: Box<EventLoopWaker>)
-> (EmbedderProxy, EmbedderReceiver) { -> (EmbedderProxy, EmbedderReceiver) {
let (sender, receiver) = channel(); let (sender, receiver) = channel();
(EmbedderProxy { (EmbedderProxy {
@ -429,7 +436,7 @@ fn create_embedder_channel(event_loop_waker: Box<compositor_thread::EventLoopWak
}) })
} }
fn create_compositor_channel(event_loop_waker: Box<compositor_thread::EventLoopWaker>) fn create_compositor_channel(event_loop_waker: Box<EventLoopWaker>)
-> (CompositorProxy, CompositorReceiver) { -> (CompositorProxy, CompositorReceiver) {
let (sender, receiver) = channel(); let (sender, receiver) = channel();
(CompositorProxy { (CompositorProxy {

View file

@ -5,12 +5,10 @@
use euclid::{TypedPoint2D, TypedVector2D}; use euclid::{TypedPoint2D, TypedVector2D};
use glutin_app::keyutils::{CMD_OR_CONTROL, CMD_OR_ALT}; use glutin_app::keyutils::{CMD_OR_CONTROL, CMD_OR_ALT};
use glutin_app::window::{Window, LINE_HEIGHT}; use glutin_app::window::{Window, LINE_HEIGHT};
use servo::compositing::compositor_thread::EmbedderMsg;
use servo::compositing::windowing::{WebRenderDebugOption, WindowEvent}; 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::{Key, TopLevelBrowsingContextId as BrowserId};
use servo::msg::constellation_msg::{KeyModifiers, KeyState, TraversalDirection}; 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::net_traits::pub_domains::is_reg_domain;
use servo::script_traits::TouchEventType; use servo::script_traits::TouchEventType;
use servo::servo_config::opts; use servo::servo_config::opts;
@ -21,7 +19,8 @@ use std::mem;
use std::rc::Rc; use std::rc::Rc;
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))] #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
use std::thread; use std::thread;
use tinyfiledialogs; #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
use tinyfiledialogs::{self, MessageBoxIcon};
pub struct Browser { pub struct Browser {
current_url: Option<ServoUrl>, current_url: Option<ServoUrl>,
@ -260,6 +259,13 @@ impl Browser {
EmbedderMsg::ResizeTo(_browser_id, size) => { EmbedderMsg::ResizeTo(_browser_id, size) => {
self.window.set_inner_size(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) => { EmbedderMsg::AllowNavigation(_browser_id, _url, response_chan) => {
if let Err(e) = response_chan.send(true) { if let Err(e) = response_chan.send(true) {
warn!("Failed to send allow_navigation() response: {}", e); warn!("Failed to send allow_navigation() response: {}", e);
@ -277,8 +283,8 @@ impl Browser {
EmbedderMsg::HeadParsed(_browser_id, ) => { EmbedderMsg::HeadParsed(_browser_id, ) => {
self.loading_state = Some(LoadingState::Loading); self.loading_state = Some(LoadingState::Loading);
} }
EmbedderMsg::HistoryChanged(_browser_id, entries, current) => { EmbedderMsg::HistoryChanged(_browser_id, urls, current) => {
self.current_url = Some(entries[current].url.clone()); self.current_url = Some(urls[current].clone());
} }
EmbedderMsg::SetFullscreenState(_browser_id, state) => { EmbedderMsg::SetFullscreenState(_browser_id, state) => {
self.window.set_fullscreen(state); self.window.set_fullscreen(state);
@ -295,13 +301,22 @@ impl Browser {
EmbedderMsg::Panic(_browser_id, _reason, _backtrace) => { EmbedderMsg::Panic(_browser_id, _reason, _backtrace) => {
}, },
EmbedderMsg::GetSelectedBluetoothDevice(devices, sender) => { 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) => { EmbedderMsg::SelectFiles(patterns, multiple_files, sender) => {
if opts::get().headless { let res = match (opts::get().headless,
let _ = sender.send(None); platform_get_selected_files(patterns, multiple_files)) {
} (true, _) | (false, None) => sender.send(None),
platform_get_selected_files(patterns, multiple_files, sender); (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) => { EmbedderMsg::ShowIME(_browser_id, _kind) => {
debug!("ShowIME received"); 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")] #[cfg(target_os = "linux")]
fn platform_get_selected_devices(devices: Vec<String>, sender: IpcSender<Option<String>>) { fn platform_get_selected_devices(devices: Vec<String>) -> Option<String> {
let picker_name = "Choose a device"; let picker_name = "Choose a device";
thread::Builder::new().name(picker_name.to_owned()).spawn(move || { thread::Builder::new().name(picker_name.to_owned()).spawn(move || {
@ -328,58 +357,54 @@ fn platform_get_selected_devices(devices: Vec<String>, sender: IpcSender<Option<
match tinyfiledialogs::list_dialog("Choose a device", &["Id", "Name"], dialog_rows) { match tinyfiledialogs::list_dialog("Choose a device", &["Id", "Name"], dialog_rows) {
Some(device) => { Some(device) => {
// The device string format will be "Address|Name". We need the first part of it. // 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()); device.split("|").next().map(|s| s.to_string())
let _ = sender.send(address);
}, },
None => { None => {
let _ = sender.send(None); None
} }
} }
}).expect("Thread spawning failed"); }).unwrap().join().expect("Thread spawning failed")
} }
#[cfg(not(target_os = "linux"))] #[cfg(not(target_os = "linux"))]
fn platform_get_selected_devices(devices: Vec<String>, sender: IpcSender<Option<String>>) { fn platform_get_selected_devices(devices: Vec<String>) -> Option<String> {
for device in devices { for device in devices {
if let Some(address) = device.split("|").next().map(|s| s.to_string()) { 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"))] #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
fn platform_get_selected_files(patterns: Vec<FilterPattern>, fn platform_get_selected_files(patterns: Vec<FilterPattern>,
multiple_files: bool, multiple_files: bool)
sender: IpcSender<Option<Vec<String>>>) { -> Option<Vec<String>> {
let picker_name = if multiple_files { "Pick files" } else { "Pick a file" }; let picker_name = if multiple_files { "Pick files" } else { "Pick a file" };
thread::Builder::new().name(picker_name.to_owned()).spawn(move || { thread::Builder::new().name(picker_name.to_owned()).spawn(move || {
let mut filter = vec![]; let mut filters = vec![];
for p in patterns { for p in patterns {
let s = "*.".to_string() + &p.0; let s = "*.".to_string() + &p.0;
filter.push(s) filters.push(s)
} }
let filter_ref = &(filters.iter().map(|s| s.as_str()).collect::<Vec<&str>>()[..]);
let filter_ref = &(filter.iter().map(|s| s.as_str()).collect::<Vec<&str>>()[..]); let filter_opt = if filters.len() > 0 { Some((filter_ref, "")) } else { None };
let filter_opt = if filter.len() > 0 { Some((filter_ref, "")) } else { None };
if multiple_files { if multiple_files {
let files = tinyfiledialogs::open_file_dialog_multi(picker_name, "", filter_opt); tinyfiledialogs::open_file_dialog_multi(picker_name, "", filter_opt)
let _ = sender.send(files);
} else { } else {
let file = tinyfiledialogs::open_file_dialog(picker_name, "", filter_opt); 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")))] #[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))]
fn platform_get_selected_files(_patterns: Vec<FilterPattern>, fn platform_get_selected_files(_patterns: Vec<FilterPattern>,
_multiple_files: bool, _multiple_files: bool)
sender: IpcSender<Option<Vec<String>>>) { -> Option<Vec<String>> {
warn!("File picker not implemented"); warn!("File picker not implemented");
let _ = sender.send(None); None
} }
fn sanitize_url(request: &str) -> Option<ServoUrl> { fn sanitize_url(request: &str) -> Option<ServoUrl> {

View file

@ -11,9 +11,9 @@ use gleam::gl;
use glutin::{Api, ContextBuilder, GlContext, GlRequest, GlWindow}; use glutin::{Api, ContextBuilder, GlContext, GlRequest, GlWindow};
#[cfg(any(target_os = "linux", target_os = "macos"))] #[cfg(any(target_os = "linux", target_os = "macos"))]
use osmesa_sys; use osmesa_sys;
use servo::compositing::compositor_thread::EventLoopWaker;
use servo::compositing::windowing::{AnimationState, MouseWindowEvent, WindowEvent}; use servo::compositing::windowing::{AnimationState, MouseWindowEvent, WindowEvent};
use servo::compositing::windowing::{EmbedderCoordinates, WindowMethods}; use servo::compositing::windowing::{EmbedderCoordinates, WindowMethods};
use servo::embedder_traits::EventLoopWaker;
use servo::msg::constellation_msg::{Key, KeyState}; use servo::msg::constellation_msg::{Key, KeyState};
use servo::script_traits::TouchEventType; use servo::script_traits::TouchEventType;
use servo::servo_config::opts; use servo::servo_config::opts;