diff options
33 files changed, 625 insertions, 517 deletions
diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 35ea1e2c508..99273256d52 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -11,19 +11,17 @@ use gfx_traits::Epoch; use gleam::gl; use image::{DynamicImage, ImageFormat, RgbImage}; use ipc_channel::ipc::{self, IpcSharedMemory}; -use msg::constellation_msg::{Key, KeyModifiers, KeyState}; -use msg::constellation_msg::{PipelineId, PipelineIndex, PipelineNamespaceId, TraversalDirection}; +use msg::constellation_msg::{KeyState, PipelineId, PipelineIndex, PipelineNamespaceId}; use net_traits::image::base::{Image, PixelFormat}; use profile_traits::time::{self, ProfilerCategory, profile}; use script_traits::{AnimationState, AnimationTickType, ConstellationControlMsg}; -use script_traits::{ConstellationMsg, LayoutControlMsg, LoadData, MouseButton}; +use script_traits::{ConstellationMsg, LayoutControlMsg, MouseButton}; use script_traits::{MouseEventType, ScrollState}; use script_traits::{TouchpadPressurePhase, TouchEventType, TouchId, WindowSizeData, WindowSizeType}; use script_traits::CompositorEvent::{self, MouseMoveEvent, MouseButtonEvent, TouchEvent, TouchpadPressureEvent}; use servo_config::opts; use servo_config::prefs::PREFS; use servo_geometry::DeviceIndependentPixel; -use servo_url::ServoUrl; use std::collections::HashMap; use std::fs::File; use std::rc::Rc; @@ -460,8 +458,8 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.change_running_animations_state(pipeline_id, animation_state); } - (Msg::ChangePageTitle(pipeline_id, title), ShutdownState::NotShuttingDown) => { - self.change_page_title(pipeline_id, title); + (Msg::ChangePageTitle(top_level_browsing_context, title), ShutdownState::NotShuttingDown) => { + self.window.set_page_title(top_level_browsing_context, title); } (Msg::SetFrameTree(frame_tree), @@ -475,55 +473,56 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.scroll_fragment_to_point(scroll_root_id, point); } - (Msg::MoveTo(point), + (Msg::MoveTo(top_level_browsing_context_id, point), ShutdownState::NotShuttingDown) => { - self.window.set_position(point); + self.window.set_position(top_level_browsing_context_id, point); } - (Msg::ResizeTo(size), + (Msg::ResizeTo(top_level_browsing_context_id, size), ShutdownState::NotShuttingDown) => { - self.window.set_inner_size(size); + self.window.set_inner_size(top_level_browsing_context_id, size); } - (Msg::GetClientWindow(send), + (Msg::GetClientWindow(top_level_browsing_context_id, send), ShutdownState::NotShuttingDown) => { - let rect = self.window.client_window(); + let rect = self.window.client_window(top_level_browsing_context_id); if let Err(e) = send.send(rect) { warn!("Sending response to get client window failed ({}).", e); } } - (Msg::Status(message), ShutdownState::NotShuttingDown) => { - self.window.status(message); + (Msg::Status(top_level_browsing_context_id, message), + ShutdownState::NotShuttingDown) => { + self.window.status(top_level_browsing_context_id, message); } - (Msg::LoadStart, ShutdownState::NotShuttingDown) => { - self.window.load_start(); + (Msg::LoadStart(top_level_browsing_context_id), ShutdownState::NotShuttingDown) => { + self.window.load_start(top_level_browsing_context_id); } - (Msg::LoadComplete, ShutdownState::NotShuttingDown) => { + (Msg::LoadComplete(top_level_browsing_context_id), ShutdownState::NotShuttingDown) => { // If we're painting in headless mode, schedule a recomposite. if opts::get().output_file.is_some() || opts::get().exit_after_load { self.composite_if_necessary(CompositingReason::Headless); } // Inform the embedder that the load has finished. - // - // TODO(pcwalton): Specify which frame's load completed. - self.window.load_end(); + self.window.load_end(top_level_browsing_context_id); } - (Msg::AllowNavigation(url, response_chan), ShutdownState::NotShuttingDown) => { - self.window.allow_navigation(url, response_chan); + (Msg::AllowNavigation(top_level_browsing_context_id, url, response_chan), + ShutdownState::NotShuttingDown) => { + self.window.allow_navigation(top_level_browsing_context_id, url, response_chan); } (Msg::Recomposite(reason), ShutdownState::NotShuttingDown) => { self.composition_request = CompositionRequest::CompositeNow(reason) } - (Msg::KeyEvent(ch, key, state, modified), ShutdownState::NotShuttingDown) => { + (Msg::KeyEvent(top_level_browsing_context_id, ch, key, state, modified), + ShutdownState::NotShuttingDown) => { if state == KeyState::Pressed { - self.window.handle_key(ch, key, modified); + self.window.handle_key(top_level_browsing_context_id, ch, key, modified); } } @@ -567,16 +566,16 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.composite_if_necessary(CompositingReason::Headless); } - (Msg::NewFavicon(url), ShutdownState::NotShuttingDown) => { - self.window.set_favicon(url); + (Msg::NewFavicon(top_level_browsing_context_id, url), ShutdownState::NotShuttingDown) => { + self.window.set_favicon(top_level_browsing_context_id, url); } - (Msg::HeadParsed, ShutdownState::NotShuttingDown) => { - self.window.head_parsed(); + (Msg::HeadParsed(top_level_browsing_context_id), ShutdownState::NotShuttingDown) => { + self.window.head_parsed(top_level_browsing_context_id); } - (Msg::HistoryChanged(entries, current), ShutdownState::NotShuttingDown) => { - self.window.history_changed(entries, current); + (Msg::HistoryChanged(top_level_browsing_context_id, entries, current), ShutdownState::NotShuttingDown) => { + self.window.history_changed(top_level_browsing_context_id, entries, current); } (Msg::PipelineVisibilityChanged(pipeline_id, visible), ShutdownState::NotShuttingDown) => { @@ -606,8 +605,8 @@ impl<Window: WindowMethods> IOCompositor<Window> { func(); } - (Msg::SetFullscreenState(state), ShutdownState::NotShuttingDown) => { - self.window.set_fullscreen_state(state); + (Msg::SetFullscreenState(top_level_browsing_context_id, state), ShutdownState::NotShuttingDown) => { + self.window.set_fullscreen_state(top_level_browsing_context_id, state); } // When we are shutting_down, we need to avoid performing operations @@ -665,15 +664,6 @@ impl<Window: WindowMethods> IOCompositor<Window> { } } - fn change_page_title(&mut self, pipeline_id: PipelineId, title: Option<String>) { - let set_title = self.root_pipeline.as_ref().map_or(false, |root_pipeline| { - root_pipeline.id == pipeline_id - }); - if set_title { - self.window.set_page_title(title); - } - } - fn set_frame_tree(&mut self, frame_tree: &SendableFrameTree) { debug!("Setting the frame tree for pipeline {}", frame_tree.pipeline.id); @@ -743,8 +733,11 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.on_resize_window_event(size); } - WindowEvent::LoadUrl(url_string) => { - self.on_load_url_window_event(url_string); + WindowEvent::LoadUrl(top_level_browsing_context_id, url) => { + let msg = ConstellationMsg::LoadUrl(top_level_browsing_context_id, url); + if let Err(e) = self.constellation_chan.send(msg) { + warn!("Sending load url to constellation failed ({}).", e); + } } WindowEvent::MouseWindowEventClass(mouse_window_event) => { @@ -788,8 +781,11 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.on_pinch_zoom_window_event(magnification); } - WindowEvent::Navigation(direction) => { - self.on_navigation_window_event(direction); + WindowEvent::Navigation(top_level_browsing_context_id, direction) => { + let msg = ConstellationMsg::TraverseHistory(top_level_browsing_context_id, direction); + if let Err(e) = self.constellation_chan.send(msg) { + warn!("Sending navigation to constellation failed ({}).", e); + } } WindowEvent::TouchpadPressure(cursor, pressure, stage) => { @@ -797,7 +793,10 @@ impl<Window: WindowMethods> IOCompositor<Window> { } WindowEvent::KeyEvent(ch, key, state, modifiers) => { - self.on_key_event(ch, key, state, modifiers); + let msg = ConstellationMsg::KeyEvent(ch, key, state, modifiers); + if let Err(e) = self.constellation_chan.send(msg) { + warn!("Sending key event to constellation failed ({}).", e); + } } WindowEvent::Quit => { @@ -807,11 +806,7 @@ impl<Window: WindowMethods> IOCompositor<Window> { } } - WindowEvent::Reload => { - let top_level_browsing_context_id = match self.root_pipeline { - Some(ref pipeline) => pipeline.top_level_browsing_context_id, - None => return warn!("Window reload without root pipeline."), - }; + WindowEvent::Reload(top_level_browsing_context_id) => { let msg = ConstellationMsg::Reload(top_level_browsing_context_id); if let Err(e) = self.constellation_chan.send(msg) { warn!("Sending reload to constellation failed ({}).", e); @@ -824,6 +819,20 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.webrender.set_debug_flags(flags); self.webrender_api.generate_frame(self.webrender_document, None); } + + WindowEvent::NewBrowser(url, response_chan) => { + let msg = ConstellationMsg::NewBrowser(url, response_chan); + if let Err(e) = self.constellation_chan.send(msg) { + warn!("Sending NewBrowser message to constellation failed ({}).", e); + } + } + + WindowEvent::SelectBrowser(ctx) => { + let msg = ConstellationMsg::SelectBrowser(ctx); + if let Err(e) = self.constellation_chan.send(msg) { + warn!("Sending SelectBrowser message to constellation failed ({}).", e); + } + } } } @@ -851,23 +860,6 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.send_window_size(WindowSizeType::Resize); } - fn on_load_url_window_event(&mut self, url_string: String) { - debug!("osmain: loading URL `{}`", url_string); - match ServoUrl::parse(&url_string) { - Ok(url) => { - let msg = match self.root_pipeline { - Some(ref pipeline) => - ConstellationMsg::LoadUrl(pipeline.id, LoadData::new(url, Some(pipeline.id), None, None)), - None => ConstellationMsg::InitLoadUrl(url) - }; - if let Err(e) = self.constellation_chan.send(msg) { - warn!("Sending load url to constellation failed ({}).", e); - } - }, - Err(e) => warn!("Parsing URL {} failed ({}).", url_string, e), - } - } - fn on_mouse_window_event_class(&mut self, mouse_window_event: MouseWindowEvent) { if opts::get().convert_mouse_to_touch { match mouse_window_event { @@ -1292,28 +1284,6 @@ impl<Window: WindowMethods> IOCompositor<Window> { }); } - fn on_navigation_window_event(&self, direction: TraversalDirection) { - let top_level_browsing_context_id = match self.root_pipeline { - Some(ref pipeline) => pipeline.top_level_browsing_context_id, - None => return warn!("Sending navigation to constellation with no root pipeline."), - }; - let msg = ConstellationMsg::TraverseHistory(top_level_browsing_context_id, direction); - if let Err(e) = self.constellation_chan.send(msg) { - warn!("Sending navigation to constellation failed ({}).", e); - } - } - - fn on_key_event(&mut self, - ch: Option<char>, - key: Key, - state: KeyState, - modifiers: KeyModifiers) { - let msg = ConstellationMsg::KeyEvent(ch, key, state, modifiers); - if let Err(e) = self.constellation_chan.send(msg) { - warn!("Sending key event to constellation failed ({}).", e); - } - } - fn send_viewport_rects(&self) { let mut scroll_states_per_pipeline = HashMap::new(); for scroll_layer_state in self.webrender_api.get_scroll_node_state(self.webrender_document) { diff --git a/components/compositing/compositor_thread.rs b/components/compositing/compositor_thread.rs index 8ca12300676..ddba55cbf55 100644 --- a/components/compositing/compositor_thread.rs +++ b/components/compositing/compositor_thread.rs @@ -8,7 +8,7 @@ use SendableFrameTree; use compositor::CompositingReason; use euclid::{Point2D, Size2D}; use ipc_channel::ipc::IpcSender; -use msg::constellation_msg::{Key, KeyModifiers, KeyState, PipelineId}; +use msg::constellation_msg::{Key, KeyModifiers, KeyState, PipelineId, TopLevelBrowsingContextId}; use net_traits::image::base::Image; use profile_traits::mem; use profile_traits::time; @@ -87,23 +87,23 @@ pub enum Msg { /// Scroll a page in a window ScrollFragmentPoint(webrender_api::ClipId, Point2D<f32>, bool), /// Alerts the compositor that the current page has changed its title. - ChangePageTitle(PipelineId, Option<String>), + ChangePageTitle(TopLevelBrowsingContextId, Option<String>), /// Alerts the compositor that the given pipeline has changed whether it is running animations. ChangeRunningAnimationsState(PipelineId, AnimationState), /// Replaces the current frame tree, typically called during main frame navigation. SetFrameTree(SendableFrameTree), /// The load of a page has begun - LoadStart, + LoadStart(TopLevelBrowsingContextId), /// The load of a page has completed - LoadComplete, + LoadComplete(TopLevelBrowsingContextId), /// The history state has changed. - HistoryChanged(Vec<LoadData>, usize), + HistoryChanged(TopLevelBrowsingContextId, Vec<LoadData>, usize), /// Wether or not to follow a link - AllowNavigation(ServoUrl, IpcSender<bool>), + AllowNavigation(TopLevelBrowsingContextId, ServoUrl, IpcSender<bool>), /// Composite. Recomposite(CompositingReason), /// Sends an unconsumed key event back to the compositor. - KeyEvent(Option<char>, Key, KeyState, KeyModifiers), + KeyEvent(Option<TopLevelBrowsingContextId>, Option<char>, Key, KeyState, KeyModifiers), /// Script has handled a touch event, and either prevented or allowed default actions. TouchEventProcessed(EventResult), /// Changes the cursor. @@ -115,17 +115,17 @@ pub enum Msg { /// A reply to the compositor asking if the output image is stable. IsReadyToSaveImageReply(bool), /// A favicon was detected - NewFavicon(ServoUrl), + NewFavicon(TopLevelBrowsingContextId, ServoUrl), /// <head> tag finished parsing - HeadParsed, + HeadParsed(TopLevelBrowsingContextId), /// A status message to be displayed by the browser chrome. - Status(Option<String>), + Status(TopLevelBrowsingContextId, Option<String>), /// Get Window Informations size and position - GetClientWindow(IpcSender<(Size2D<u32>, Point2D<i32>)>), + GetClientWindow(TopLevelBrowsingContextId, IpcSender<(Size2D<u32>, Point2D<i32>)>), /// Move the window to a point - MoveTo(Point2D<i32>), + MoveTo(TopLevelBrowsingContextId, Point2D<i32>), /// Resize the window to size - ResizeTo(Size2D<u32>), + ResizeTo(TopLevelBrowsingContextId, Size2D<u32>), /// Pipeline visibility changed PipelineVisibilityChanged(PipelineId, bool), /// WebRender has successfully processed a scroll. The boolean specifies whether a composite is @@ -142,7 +142,7 @@ pub enum Msg { /// Required to allow WGL GLContext sharing in Windows. Dispatch(Box<Fn() + Send>), /// Enter or exit fullscreen - SetFullscreenState(bool), + SetFullscreenState(TopLevelBrowsingContextId, bool), } impl Debug for Msg { @@ -154,9 +154,9 @@ impl Debug for Msg { Msg::ChangeRunningAnimationsState(..) => write!(f, "ChangeRunningAnimationsState"), Msg::ChangePageTitle(..) => write!(f, "ChangePageTitle"), Msg::SetFrameTree(..) => write!(f, "SetFrameTree"), - Msg::LoadComplete => write!(f, "LoadComplete"), + Msg::LoadComplete(..) => write!(f, "LoadComplete"), Msg::AllowNavigation(..) => write!(f, "AllowNavigation"), - Msg::LoadStart => write!(f, "LoadStart"), + Msg::LoadStart(..) => write!(f, "LoadStart"), Msg::HistoryChanged(..) => write!(f, "HistoryChanged"), Msg::Recomposite(..) => write!(f, "Recomposite"), Msg::KeyEvent(..) => write!(f, "KeyEvent"), @@ -166,7 +166,7 @@ impl Debug for Msg { Msg::ViewportConstrained(..) => write!(f, "ViewportConstrained"), Msg::IsReadyToSaveImageReply(..) => write!(f, "IsReadyToSaveImageReply"), Msg::NewFavicon(..) => write!(f, "NewFavicon"), - Msg::HeadParsed => write!(f, "HeadParsed"), + Msg::HeadParsed(..) => write!(f, "HeadParsed"), Msg::Status(..) => write!(f, "Status"), Msg::GetClientWindow(..) => write!(f, "GetClientWindow"), Msg::MoveTo(..) => write!(f, "MoveTo"), diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index 4c018997645..cceaaf9fce8 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -9,7 +9,7 @@ use euclid::{Point2D, Size2D}; use euclid::{ScaleFactor, TypedPoint2D, TypedSize2D}; use gleam::gl; use ipc_channel::ipc::IpcSender; -use msg::constellation_msg::{Key, KeyModifiers, KeyState, TraversalDirection}; +use msg::constellation_msg::{Key, KeyModifiers, KeyState, TopLevelBrowsingContextId, TraversalDirection}; use net_traits::net_error_list::NetError; use script_traits::{LoadData, MouseButton, TouchEventType, TouchId, TouchpadPressurePhase}; use servo_geometry::DeviceIndependentPixel; @@ -45,7 +45,7 @@ pub enum WindowEvent { /// Touchpad Pressure TouchpadPressure(TypedPoint2D<f32, DevicePixel>, f32, TouchpadPressurePhase), /// Sent when a new URL is to be loaded. - LoadUrl(String), + LoadUrl(TopLevelBrowsingContextId, ServoUrl), /// Sent when a mouse hit test is to be performed. MouseWindowEventClass(MouseWindowEvent), /// Sent when a mouse move. @@ -62,15 +62,20 @@ pub enum WindowEvent { /// Sent when the user resets zoom to default. ResetZoom, /// Sent when the user uses chrome navigation (i.e. backspace or shift-backspace). - Navigation(TraversalDirection), + Navigation(TopLevelBrowsingContextId, TraversalDirection), /// Sent when the user quits the application Quit, /// Sent when a key input state changes KeyEvent(Option<char>, Key, KeyState, KeyModifiers), /// Sent when Ctr+R/Apple+R is called to reload the current page. - Reload, /// Toggles the Web renderer profiler on and off ToggleWebRenderProfiler, + Reload(TopLevelBrowsingContextId), + /// Create a new top level browsing context + NewBrowser(ServoUrl, IpcSender<TopLevelBrowsingContextId>), + /// Make a top level browsing context visible, hiding the previous + /// visible one. + SelectBrowser(TopLevelBrowsingContextId), } impl Debug for WindowEvent { @@ -91,8 +96,10 @@ impl Debug for WindowEvent { WindowEvent::ResetZoom => write!(f, "ResetZoom"), WindowEvent::Navigation(..) => write!(f, "Navigation"), WindowEvent::Quit => write!(f, "Quit"), - WindowEvent::Reload => write!(f, "Reload"), WindowEvent::ToggleWebRenderProfiler => write!(f, "ToggleWebRenderProfiler"), + WindowEvent::Reload(..) => write!(f, "Reload"), + WindowEvent::NewBrowser(..) => write!(f, "NewBrowser"), + WindowEvent::SelectBrowser(..) => write!(f, "SelectBrowser"), } } } @@ -114,30 +121,30 @@ pub trait WindowMethods { fn present(&self); /// Return the size of the window with head and borders and position of the window values - fn client_window(&self) -> (Size2D<u32>, Point2D<i32>); + fn client_window(&self, ctx: TopLevelBrowsingContextId) -> (Size2D<u32>, Point2D<i32>); /// Set the size inside of borders and head - fn set_inner_size(&self, size: Size2D<u32>); + fn set_inner_size(&self, ctx: TopLevelBrowsingContextId, size: Size2D<u32>); /// Set the window position - fn set_position(&self, point: Point2D<i32>); + fn set_position(&self, ctx: TopLevelBrowsingContextId, point: Point2D<i32>); /// Set fullscreen state - fn set_fullscreen_state(&self, state: bool); + fn set_fullscreen_state(&self, ctx: TopLevelBrowsingContextId, state: bool); /// Sets the page title for the current page. - fn set_page_title(&self, title: Option<String>); + fn set_page_title(&self, ctx: TopLevelBrowsingContextId, title: Option<String>); /// Called when the browser chrome should display a status message. - fn status(&self, Option<String>); + fn status(&self, ctx: TopLevelBrowsingContextId, Option<String>); /// Called when the browser has started loading a frame. - fn load_start(&self); + fn load_start(&self, ctx: TopLevelBrowsingContextId); /// Called when the browser is done loading a frame. - fn load_end(&self); + fn load_end(&self, ctx: TopLevelBrowsingContextId); /// Called when the browser encounters an error while loading a URL - fn load_error(&self, code: NetError, url: String); + fn load_error(&self, ctx: TopLevelBrowsingContextId, code: NetError, url: String); /// Wether or not to follow a link - fn allow_navigation(&self, url: ServoUrl, IpcSender<bool>); + fn allow_navigation(&self, ctx: TopLevelBrowsingContextId, url: ServoUrl, IpcSender<bool>); /// Called when the <head> tag has finished parsing - fn head_parsed(&self); + fn head_parsed(&self, ctx: TopLevelBrowsingContextId); /// Called when the history state has changed. - fn history_changed(&self, Vec<LoadData>, usize); + fn history_changed(&self, ctx: TopLevelBrowsingContextId, Vec<LoadData>, usize); /// Returns the scale factor of the system (device pixels / device independent pixels). fn hidpi_factor(&self) -> ScaleFactor<f32, DeviceIndependentPixel, DevicePixel>; @@ -154,13 +161,13 @@ pub trait WindowMethods { fn set_cursor(&self, cursor: Cursor); /// Process a key event. - fn handle_key(&self, ch: Option<char>, key: Key, mods: KeyModifiers); + fn handle_key(&self, ctx: Option<TopLevelBrowsingContextId>, ch: Option<char>, key: Key, mods: KeyModifiers); /// Does this window support a clipboard fn supports_clipboard(&self) -> bool; /// Add a favicon - fn set_favicon(&self, url: ServoUrl); + fn set_favicon(&self, ctx: TopLevelBrowsingContextId, url: ServoUrl); /// Return the GL function pointer trait. fn gl(&self) -> Rc<gl::Gl>; diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index bccc351becd..1685a32d8d2 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -105,7 +105,7 @@ use script_traits::{ConstellationControlMsg, ConstellationMsg as FromCompositorM use script_traits::{DocumentActivity, DocumentState, LayoutControlMsg, LoadData}; use script_traits::{IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState, TimerSchedulerMsg}; use script_traits::{LayoutMsg as FromLayoutMsg, ScriptMsg as FromScriptMsg, ScriptThreadFactory}; -use script_traits::{LogEntry, ServiceWorkerMsg, webdriver_msg}; +use script_traits::{LogEntry, ScriptToConstellationChan, ServiceWorkerMsg, webdriver_msg}; use script_traits::{MozBrowserErrorType, MozBrowserEvent, WebDriverCommandMsg, WindowSizeData}; use script_traits::{SWManagerMsg, ScopeThings, UpdatePipelineIdReason, WindowSizeType}; use serde::{Deserialize, Serialize}; @@ -147,11 +147,11 @@ use webvr_traits::{WebVREvent, WebVRMsg}; pub struct Constellation<Message, LTF, STF> { /// An IPC channel for script threads to send messages to the constellation. /// This is the script threads' view of `script_receiver`. - script_sender: IpcSender<FromScriptMsg>, + script_sender: IpcSender<(PipelineId, FromScriptMsg)>, /// A channel for the constellation to receive messages from script threads. /// This is the constellation's view of `script_sender`. - script_receiver: Receiver<Result<FromScriptMsg, IpcError>>, + script_receiver: Receiver<Result<(PipelineId, FromScriptMsg), IpcError>>, /// An IPC channel for layout threads to send messages to the constellation. /// This is the layout threads' view of `layout_receiver`. @@ -174,6 +174,9 @@ pub struct Constellation<Message, LTF, STF> { /// constellation to send messages to the compositor thread. compositor_proxy: CompositorProxy, + /// The last frame tree sent to WebRender. + active_browser_id: Option<TopLevelBrowsingContextId>, + /// Channels for the constellation to send messages to the public /// resource-related threads. There are two groups of resource /// threads: one for public browsing, and one for private @@ -385,14 +388,14 @@ enum ExitPipelineMode { #[derive(Clone)] pub struct FromScriptLogger { /// A channel to the constellation - pub constellation_chan: Arc<ReentrantMutex<IpcSender<FromScriptMsg>>>, + pub script_to_constellation_chan: Arc<ReentrantMutex<ScriptToConstellationChan>>, } impl FromScriptLogger { /// Create a new constellation logger. - pub fn new(constellation_chan: IpcSender<FromScriptMsg>) -> FromScriptLogger { + pub fn new(script_to_constellation_chan: ScriptToConstellationChan) -> FromScriptLogger { FromScriptLogger { - constellation_chan: Arc::new(ReentrantMutex::new(constellation_chan)) + script_to_constellation_chan: Arc::new(ReentrantMutex::new(script_to_constellation_chan)) } } @@ -410,10 +413,9 @@ impl Log for FromScriptLogger { fn log(&self, record: &LogRecord) { if let Some(entry) = log_entry(record) { debug!("Sending log entry {:?}.", entry); - let top_level_id = TopLevelBrowsingContextId::installed(); let thread_name = thread::current().name().map(ToOwned::to_owned); - let msg = FromScriptMsg::LogEntry(top_level_id, thread_name, entry); - let chan = self.constellation_chan.lock().unwrap_or_else(|err| err.into_inner()); + let msg = FromScriptMsg::LogEntry(thread_name, entry); + let chan = self.script_to_constellation_chan.lock().unwrap_or_else(|err| err.into_inner()); let _ = chan.send(msg); } } @@ -528,6 +530,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> network_listener_sender: network_listener_sender, network_listener_receiver: network_listener_receiver, compositor_proxy: state.compositor_proxy, + active_browser_id: None, debugger_chan: state.debugger_chan, devtools_chan: state.devtools_chan, bluetooth_thread: state.bluetooth_thread, @@ -674,7 +677,10 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> browsing_context_id, top_level_browsing_context_id, parent_info, - constellation_chan: self.script_sender.clone(), + script_to_constellation_chan: ScriptToConstellationChan { + sender: self.script_sender.clone(), + pipeline_id: pipeline_id, + }, layout_to_constellation_chan: self.layout_sender.clone(), scheduler_chan: self.scheduler_chan.clone(), compositor_proxy: self.compositor_proxy.clone_compositor_proxy(), @@ -807,9 +813,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } } - fn add_pending_change(&mut self, change: SessionHistoryChange) - { - self.handle_load_start_msg(change.new_pipeline_id); + fn add_pending_change(&mut self, change: SessionHistoryChange) { + self.handle_load_start_msg(change.top_level_browsing_context_id, change.new_pipeline_id); self.pending_changes.push(change); } @@ -817,7 +822,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> #[allow(unsafe_code)] fn handle_request(&mut self) { enum Request { - Script(FromScriptMsg), + Script((PipelineId, FromScriptMsg)), Compositor(FromCompositorMsg), Layout(FromLayoutMsg), NetworkListener((PipelineId, FetchResponseMsg)), @@ -934,9 +939,15 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // Load a new page from a typed url // If there is already a pending page (self.pending_changes), it will not be overridden; // However, if the id is not encompassed by another change, it will be. - FromCompositorMsg::LoadUrl(source_id, load_data) => { + FromCompositorMsg::LoadUrl(top_level_browsing_context_id, url) => { debug!("constellation got URL load message from compositor"); - self.handle_load_url_msg(source_id, load_data, false); + let load_data = LoadData::new(url, None, None, None); + 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!("LoadUrl for unknow browsing context: {:?}", top_level_browsing_context_id), + }; + self.handle_load_url_msg(top_level_browsing_context_id, pipeline_id, load_data, false); } FromCompositorMsg::IsReadyToSaveImage(pipeline_states) => { let is_ready = self.handle_is_ready_to_save_image(pipeline_states); @@ -950,10 +961,15 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> println!("sent response"); } } - // This should only be called once per constellation, and only by the browser - FromCompositorMsg::InitLoadUrl(url) => { + // Create a new top level browsing context. Will use response_chan to return + // the browsing context id. + FromCompositorMsg::NewBrowser(url, response_chan) => { debug!("constellation got init load URL message"); - self.handle_init_load(url); + self.handle_new_top_level_browsing_context(url, response_chan); + } + // Send frame tree to WebRender. Make it visible. + FromCompositorMsg::SelectBrowser(top_level_browsing_context_id) => { + self.send_frame_tree(top_level_browsing_context_id); } // Handle a forward or back request FromCompositorMsg::TraverseHistory(top_level_browsing_context_id, direction) => { @@ -989,14 +1005,26 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } } - fn handle_request_from_script(&mut self, message: FromScriptMsg) { - match message { - FromScriptMsg::PipelineExited(pipeline_id) => { - self.handle_pipeline_exited(pipeline_id); + fn handle_request_from_script(&mut self, message: (PipelineId, FromScriptMsg)) { + let (source_pipeline_id, content) = message; + let source_top_ctx_id = match self.pipelines.get(&source_pipeline_id) + .map(|pipeline| pipeline.top_level_browsing_context_id) { + None => return warn!("ScriptMsg from closed pipeline {:?}.", source_pipeline_id), + 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::PipelineExited => { + self.handle_pipeline_exited(source_pipeline_id); } - FromScriptMsg::InitiateNavigateRequest(req_init, pipeline_id) => { + FromScriptMsg::InitiateNavigateRequest(req_init) => { debug!("constellation got initiate navigate request message"); - self.handle_navigate_request(req_init, pipeline_id); + self.handle_navigate_request(source_pipeline_id, req_init); } FromScriptMsg::ScriptLoadedURLInIFrame(load_info) => { debug!("constellation got iframe URL load message {:?} {:?} {:?}", @@ -1011,40 +1039,40 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> load_info.new_pipeline_id); self.handle_script_new_iframe(load_info, layout_sender); } - FromScriptMsg::ChangeRunningAnimationsState(pipeline_id, animation_state) => { - self.handle_change_running_animations_state(pipeline_id, animation_state) + FromScriptMsg::ChangeRunningAnimationsState(animation_state) => { + self.handle_change_running_animations_state(source_pipeline_id, animation_state) } // Load a new page from a mouse click // If there is already a pending page (self.pending_changes), it will not be overridden; // However, if the id is not encompassed by another change, it will be. - FromScriptMsg::LoadUrl(source_id, load_data, replace) => { + FromScriptMsg::LoadUrl(load_data, replace) => { debug!("constellation got URL load message from script"); - self.handle_load_url_msg(source_id, load_data, replace); + self.handle_load_url_msg(source_top_ctx_id, source_pipeline_id, load_data, replace); } // A page loaded has completed all parsing, script, and reflow messages have been sent. - FromScriptMsg::LoadComplete(pipeline_id) => { + FromScriptMsg::LoadComplete => { debug!("constellation got load complete message"); - self.handle_load_complete_msg(pipeline_id) + self.handle_load_complete_msg(source_top_ctx_id, source_pipeline_id) } // Handle a forward or back request - FromScriptMsg::TraverseHistory(top_level_browsing_context_id, direction) => { + FromScriptMsg::TraverseHistory(direction) => { debug!("constellation got traverse history message from script"); - self.handle_traverse_history_msg(top_level_browsing_context_id, direction); + self.handle_traverse_history_msg(source_top_ctx_id, direction); } // Handle a joint session history length request. - FromScriptMsg::JointSessionHistoryLength(top_level_browsing_context_id, sender) => { + FromScriptMsg::JointSessionHistoryLength(sender) => { debug!("constellation got joint session history length message from script"); - self.handle_joint_session_history_length(top_level_browsing_context_id, sender); + self.handle_joint_session_history_length(source_top_ctx_id, sender); } // Notification that the new document is ready to become active - FromScriptMsg::ActivateDocument(pipeline_id) => { + FromScriptMsg::ActivateDocument => { debug!("constellation got activate document message"); - self.handle_activate_document_msg(pipeline_id); + self.handle_activate_document_msg(source_pipeline_id); } // Update pipeline url after redirections - FromScriptMsg::SetFinalUrl(pipeline_id, final_url) => { + FromScriptMsg::SetFinalUrl(final_url) => { // The script may have finished loading after we already started shutting down. - if let Some(ref mut pipeline) = self.pipelines.get_mut(&pipeline_id) { + if let Some(ref mut pipeline) = self.pipelines.get_mut(&source_pipeline_id) { debug!("constellation got set final url message"); pipeline.url = final_url; } else { @@ -1055,22 +1083,22 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> debug!("constellation got postMessage message"); self.handle_post_message_msg(browsing_context_id, origin, data); } - FromScriptMsg::MozBrowserEvent(pipeline_id, top_level_browsing_context_id, event) => { + FromScriptMsg::MozBrowserEvent(pipeline_id, event) => { debug!("constellation got mozbrowser event message"); - self.handle_mozbrowser_event_msg(pipeline_id, top_level_browsing_context_id, event); + self.handle_mozbrowser_event_msg(pipeline_id, source_top_ctx_id, event); } - FromScriptMsg::Focus(pipeline_id) => { + FromScriptMsg::Focus => { debug!("constellation got focus message"); - self.handle_focus_msg(pipeline_id); + self.handle_focus_msg(source_pipeline_id); } - FromScriptMsg::ForwardEvent(pipeline_id, event) => { - let msg = ConstellationControlMsg::SendEvent(pipeline_id, event); - let result = match self.pipelines.get(&pipeline_id) { - None => { debug!("Pipeline {:?} got event after closure.", pipeline_id); return; } + FromScriptMsg::ForwardEvent(dest_id, event) => { + let msg = ConstellationControlMsg::SendEvent(dest_id, event); + let result = match self.pipelines.get(&dest_id) { + None => { debug!("Pipeline {:?} got event after closure.", dest_id); return; } Some(pipeline) => pipeline.event_loop.send(msg), }; if let Err(e) = result { - self.handle_send_error(pipeline_id, e); + self.handle_send_error(dest_id, e); } } FromScriptMsg::GetClipboardContents(sender) => { @@ -1095,13 +1123,13 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } } } - FromScriptMsg::SetVisible(pipeline_id, visible) => { + FromScriptMsg::SetVisible(visible) => { debug!("constellation got set visible messsage"); - self.handle_set_visible_msg(pipeline_id, visible); + self.handle_set_visible_msg(source_pipeline_id, visible); } - FromScriptMsg::VisibilityChangeComplete(pipeline_id, visible) => { + FromScriptMsg::VisibilityChangeComplete(visible) => { debug!("constellation got set visibility change complete message"); - self.handle_visibility_change_complete(pipeline_id, visible); + self.handle_visibility_change_complete(source_pipeline_id, visible); } FromScriptMsg::RemoveIFrame(browsing_context_id, sender) => { debug!("constellation got remove iframe message"); @@ -1112,11 +1140,15 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } FromScriptMsg::NewFavicon(url) => { debug!("constellation got new favicon message"); - self.compositor_proxy.send(ToCompositorMsg::NewFavicon(url)); + if source_is_top_level_pipeline { + self.compositor_proxy.send(ToCompositorMsg::NewFavicon(source_top_ctx_id, url)); + } } FromScriptMsg::HeadParsed => { debug!("constellation got head parsed message"); - self.compositor_proxy.send(ToCompositorMsg::HeadParsed); + if source_is_top_level_pipeline { + self.compositor_proxy.send(ToCompositorMsg::HeadParsed(source_top_ctx_id)); + } } FromScriptMsg::CreateCanvasPaintThread(size, sender) => { debug!("constellation got create-canvas-paint-thread message"); @@ -1128,15 +1160,15 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } FromScriptMsg::NodeStatus(message) => { debug!("constellation got NodeStatus message"); - self.compositor_proxy.send(ToCompositorMsg::Status(message)); + self.compositor_proxy.send(ToCompositorMsg::Status(source_top_ctx_id, message)); } - FromScriptMsg::SetDocumentState(pipeline_id, state) => { + FromScriptMsg::SetDocumentState(state) => { debug!("constellation got SetDocumentState message"); - self.document_states.insert(pipeline_id, state); + self.document_states.insert(source_pipeline_id, state); } - FromScriptMsg::Alert(pipeline_id, message, sender) => { + FromScriptMsg::Alert(message, sender) => { debug!("constellation got Alert message"); - self.handle_alert(pipeline_id, message, sender); + self.handle_alert(source_top_ctx_id, message, sender); } FromScriptMsg::ScrollFragmentPoint(scroll_root_id, point, smooth) => { @@ -1146,30 +1178,33 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } FromScriptMsg::GetClientWindow(send) => { - self.compositor_proxy.send(ToCompositorMsg::GetClientWindow(send)); + self.compositor_proxy.send(ToCompositorMsg::GetClientWindow(source_top_ctx_id, send)); } FromScriptMsg::MoveTo(point) => { - self.compositor_proxy.send(ToCompositorMsg::MoveTo(point)); + self.compositor_proxy.send(ToCompositorMsg::MoveTo(source_top_ctx_id, point)); } FromScriptMsg::ResizeTo(size) => { - self.compositor_proxy.send(ToCompositorMsg::ResizeTo(size)); + self.compositor_proxy.send(ToCompositorMsg::ResizeTo(source_top_ctx_id, size)); } FromScriptMsg::Exit => { self.compositor_proxy.send(ToCompositorMsg::Exit); } - FromScriptMsg::LogEntry(top_level_browsing_context_id, thread_name, entry) => { - self.handle_log_entry(top_level_browsing_context_id, thread_name, entry); + FromScriptMsg::LogEntry(thread_name, entry) => { + self.handle_log_entry(Some(source_top_ctx_id), thread_name, entry); } - FromScriptMsg::SetTitle(pipeline_id, title) => { - self.compositor_proxy.send(ToCompositorMsg::ChangePageTitle(pipeline_id, title)) + FromScriptMsg::SetTitle(title) => { + if source_is_top_level_pipeline { + self.compositor_proxy.send(ToCompositorMsg::ChangePageTitle(source_top_ctx_id, title)) + } } FromScriptMsg::SendKeyEvent(ch, key, key_state, key_modifiers) => { - self.compositor_proxy.send(ToCompositorMsg::KeyEvent(ch, key, key_state, key_modifiers)) + let event = ToCompositorMsg::KeyEvent(Some(source_top_ctx_id), ch, key, key_state, key_modifiers); + self.compositor_proxy.send(event); } FromScriptMsg::TouchEventProcessed(result) => { @@ -1198,11 +1233,11 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> warn!("Unable to forward DOMMessage for postMessage call"); } } - FromScriptMsg::BroadcastStorageEvent(pipeline_id, storage, url, key, old_value, new_value) => { - self.handle_broadcast_storage_event(pipeline_id, 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); } FromScriptMsg::SetFullscreenState(state) => { - self.compositor_proxy.send(ToCompositorMsg::SetFullscreenState(state)); + self.compositor_proxy.send(ToCompositorMsg::SetFullscreenState(source_top_ctx_id, state)); } } } @@ -1468,14 +1503,19 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } } - fn handle_init_load(&mut self, url: ServoUrl) { + fn handle_new_top_level_browsing_context(&mut self, url: ServoUrl, reply: IpcSender<TopLevelBrowsingContextId>) { let window_size = self.window_size.initial_viewport; let pipeline_id = PipelineId::new(); let top_level_browsing_context_id = TopLevelBrowsingContextId::new(); + if let Err(e) = reply.send(top_level_browsing_context_id) { + warn!("Failed to send newly created top level browsing context ({}).", e); + } let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id); let load_data = LoadData::new(url.clone(), None, None, None); let sandbox = IFrameSandboxState::IFrameUnsandboxed; - self.focus_pipeline_id = Some(pipeline_id); + if self.focus_pipeline_id.is_none() { + self.focus_pipeline_id = Some(pipeline_id); + } self.new_pipeline(pipeline_id, browsing_context_id, top_level_browsing_context_id, @@ -1528,8 +1568,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } fn handle_navigate_request(&self, - req_init: RequestInit, - id: PipelineId) { + id: PipelineId, + req_init: RequestInit) { let listener = NetworkListener::new( req_init, id, @@ -1687,14 +1727,10 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } fn handle_alert(&mut self, - pipeline_id: PipelineId, + top_level_browsing_context_id: TopLevelBrowsingContextId, message: String, sender: IpcSender<bool>) { - let top_level_browsing_context_id = self.pipelines.get(&pipeline_id) - .map(|pipeline| pipeline.top_level_browsing_context_id); - let browser_pipeline_id = top_level_browsing_context_id - .map(BrowsingContextId::from) - .and_then(|browsing_context_id| self.browsing_contexts.get(&browsing_context_id)) + let browser_pipeline_id = self.browsing_contexts.get(&BrowsingContextId::from(top_level_browsing_context_id)) .and_then(|browsing_context| self.pipelines.get(&browsing_context.pipeline_id)) .and_then(|pipeline| pipeline.parent_info) .map(|(browser_pipeline_id, _)| browser_pipeline_id); @@ -1708,24 +1744,32 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> let event = MozBrowserEvent::ShowModalPrompt(prompt_type, title, message, return_value); match browser_pipeline_id.and_then(|id| self.pipelines.get(&id)) { None => warn!("Alert sent after browser pipeline closure."), - Some(pipeline) => pipeline.trigger_mozbrowser_event(top_level_browsing_context_id, event), + Some(pipeline) => pipeline.trigger_mozbrowser_event(Some(top_level_browsing_context_id), event), } } let result = sender.send(!mozbrowser_modal_prompt); 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, source_id: PipelineId, load_data: LoadData, replace: bool) { - self.load_url(source_id, load_data, replace); + 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); } - fn load_url(&mut self, source_id: PipelineId, load_data: LoadData, replace: bool) -> Option<PipelineId> { + fn load_url(&mut self, top_level_browsing_context_id: TopLevelBrowsingContextId, source_id: PipelineId, + load_data: LoadData, replace: bool) -> Option<PipelineId> { // Allow the embedder to handle the url itself let (chan, port) = ipc::channel().expect("Failed to create IPC channel!"); - self.compositor_proxy.send(ToCompositorMsg::AllowNavigation(load_data.url.clone(), chan)); + let msg = ToCompositorMsg::AllowNavigation(top_level_browsing_context_id, load_data.url.clone(), chan); + self.compositor_proxy.send(msg); if let Ok(false) = port.recv() { return None; } @@ -1815,11 +1859,16 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } } - fn handle_load_start_msg(&mut self, _pipeline_id: PipelineId) { - self.compositor_proxy.send(ToCompositorMsg::LoadStart); + fn handle_load_start_msg(&mut self, top_level_browsing_context_id: TopLevelBrowsingContextId, + pipeline_id: PipelineId) { + if self.pipelines.get(&pipeline_id).and_then(|p| p.parent_info).is_none() { + // Notify embedder top level document started loading. + self.compositor_proxy.send(ToCompositorMsg::LoadStart(top_level_browsing_context_id)); + } } - fn handle_load_complete_msg(&mut self, pipeline_id: PipelineId) { + fn handle_load_complete_msg(&mut self, top_level_browsing_context_id: TopLevelBrowsingContextId, + pipeline_id: PipelineId) { let mut webdriver_reset = false; if let Some((expected_pipeline_id, ref reply_chan)) = self.webdriver.load_channel { debug!("Sending load to WebDriver"); @@ -1831,7 +1880,25 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> if webdriver_reset { self.webdriver.load_channel = None; } - self.compositor_proxy.send(ToCompositorMsg::LoadComplete); + + // Notify the embedder that the TopLevelBrowsingContext current document + // has finished loading. + // We need to make sure the pipeline that has finished loading is the current + // pipeline and that no pending pipeline will replace the current one. + let pipeline_is_top_level_pipeline = self.browsing_contexts + .get(&BrowsingContextId::from(top_level_browsing_context_id)) + .map(|ctx| ctx.pipeline_id == pipeline_id) + .unwrap_or(false); + if pipeline_is_top_level_pipeline { + // Is there any pending pipeline that will replace the current top level pipeline + let current_top_level_pipeline_will_be_replaced = self.pending_changes.iter() + .any(|change| change.browsing_context_id == top_level_browsing_context_id); + + if !current_top_level_pipeline_will_be_replaced { + // Notify embedder top level document finished loading. + self.compositor_proxy.send(ToCompositorMsg::LoadComplete(top_level_browsing_context_id)); + } + } self.handle_subframe_loaded(pipeline_id); } @@ -1897,7 +1964,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } }, None => { - let event = ToCompositorMsg::KeyEvent(ch, key, state, mods); + let event = ToCompositorMsg::KeyEvent(None, ch, key, state, mods); self.compositor_proxy.clone_compositor_proxy().send(event); } } @@ -2088,9 +2155,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> WebDriverCommandMsg::GetWindowSize(_, reply) => { let _ = reply.send(self.window_size); }, - WebDriverCommandMsg::SetWindowSize(_, size, reply) => { + WebDriverCommandMsg::SetWindowSize(top_level_browsing_context_id, size, reply) => { self.webdriver.resize_channel = Some(reply); - self.compositor_proxy.send(ToCompositorMsg::ResizeTo(size)); + self.compositor_proxy.send(ToCompositorMsg::ResizeTo(top_level_browsing_context_id, size)); }, WebDriverCommandMsg::LoadUrl(top_level_browsing_context_id, load_data, reply) => { self.load_url_for_webdriver(top_level_browsing_context_id, load_data, reply, false); @@ -2247,7 +2314,11 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> self.notify_history_changed(top_level_id); // Set paint permissions correctly for the compositor layers. - self.send_frame_tree(top_level_id); + if let Some(id) = self.active_browser_id { + if id == top_level_id { + self.send_frame_tree(top_level_id); + } + } // Update the owning iframe to point to the new pipeline id. // This makes things like contentDocument work correctly. @@ -2324,7 +2395,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> .map(&keep_load_data_if_top_browsing_context) .scan(current_load_data.clone(), &resolve_load_data)); - self.compositor_proxy.send(ToCompositorMsg::HistoryChanged(entries, current_index)); + let msg = ToCompositorMsg::HistoryChanged(top_level_browsing_context_id, entries, current_index); + self.compositor_proxy.send(msg); } fn load_url_for_webdriver(&mut self, @@ -2338,7 +2410,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> Some(browsing_context) => browsing_context.pipeline_id, None => return warn!("Webdriver load for closed browsing context {}.", browsing_context_id), }; - if let Some(new_pipeline_id) = self.load_url(pipeline_id, load_data, replace) { + if let Some(new_pipeline_id) = self.load_url(top_level_browsing_context_id, pipeline_id, load_data, replace) { self.webdriver.load_channel = Some((new_pipeline_id, reply)); } } @@ -2405,7 +2477,11 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } // Build frame tree - self.send_frame_tree(change.top_level_browsing_context_id); + if let Some(id) = self.active_browser_id { + if id == change.top_level_browsing_context_id { + self.send_frame_tree(change.top_level_browsing_context_id ); + } + } } fn handle_activate_document_msg(&mut self, pipeline_id: PipelineId) { @@ -2842,6 +2918,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> fn send_frame_tree(&mut self, top_level_browsing_context_id: TopLevelBrowsingContextId) { // This might be a mozbrowser iframe, so we need to climb the parent hierarchy, // even though it's a top-level browsing context. + self.active_browser_id = Some(top_level_browsing_context_id); let mut browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id); let mut pipeline_id = match self.browsing_contexts.get(&browsing_context_id) { Some(browsing_context) => browsing_context.pipeline_id, diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index 74530cfa664..92a5fb041ef 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -21,10 +21,10 @@ use net_traits::{IpcSend, ResourceThreads}; use net_traits::image_cache::ImageCache; use profile_traits::mem as profile_mem; use profile_traits::time; -use script_traits::{ConstellationControlMsg, DiscardBrowsingContext}; +use script_traits::{ConstellationControlMsg, DiscardBrowsingContext, ScriptToConstellationChan}; use script_traits::{DocumentActivity, InitialScriptState}; use script_traits::{LayoutControlMsg, LayoutMsg, LoadData, MozBrowserEvent}; -use script_traits::{NewLayoutInfo, SWManagerMsg, SWManagerSenders, ScriptMsg}; +use script_traits::{NewLayoutInfo, SWManagerMsg, SWManagerSenders}; use script_traits::{ScriptThreadFactory, TimerSchedulerMsg, WindowSizeData}; use servo_config::opts::{self, Opts}; use servo_config::prefs::{PREFS, Pref}; @@ -112,7 +112,7 @@ pub struct InitialPipelineState { pub parent_info: Option<(PipelineId, FrameType)>, /// A channel to the associated constellation. - pub constellation_chan: IpcSender<ScriptMsg>, + pub script_to_constellation_chan: ScriptToConstellationChan, /// A channel for the layout thread to send messages to the constellation. pub layout_to_constellation_chan: IpcSender<LayoutMsg>, @@ -246,7 +246,7 @@ impl Pipeline { browsing_context_id: state.browsing_context_id, top_level_browsing_context_id: state.top_level_browsing_context_id, parent_info: state.parent_info, - constellation_chan: state.constellation_chan, + script_to_constellation_chan: state.script_to_constellation_chan.clone(), scheduler_chan: state.scheduler_chan, devtools_chan: script_to_devtools_chan, bluetooth_thread: state.bluetooth_thread, @@ -446,7 +446,7 @@ pub struct UnprivilegedPipelineContent { top_level_browsing_context_id: TopLevelBrowsingContextId, browsing_context_id: BrowsingContextId, parent_info: Option<(PipelineId, FrameType)>, - constellation_chan: IpcSender<ScriptMsg>, + script_to_constellation_chan: ScriptToConstellationChan, layout_to_constellation_chan: IpcSender<LayoutMsg>, scheduler_chan: IpcSender<TimerSchedulerMsg>, devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, @@ -487,7 +487,7 @@ impl UnprivilegedPipelineContent { parent_info: self.parent_info, control_chan: self.script_chan.clone(), control_port: self.script_port, - constellation_chan: self.constellation_chan, + script_to_constellation_chan: self.script_to_constellation_chan.clone(), layout_to_constellation_chan: self.layout_to_constellation_chan.clone(), scheduler_chan: self.scheduler_chan, bluetooth_thread: self.bluetooth_thread, @@ -595,8 +595,8 @@ impl UnprivilegedPipelineContent { } } - pub fn constellation_chan(&self) -> IpcSender<ScriptMsg> { - self.constellation_chan.clone() + pub fn script_to_constellation_chan(&self) -> &ScriptToConstellationChan { + &self.script_to_constellation_chan } pub fn opts(&self) -> Opts { diff --git a/components/script/clipboard_provider.rs b/components/script/clipboard_provider.rs index e8a9552277a..86e9139895a 100644 --- a/components/script/clipboard_provider.rs +++ b/components/script/clipboard_provider.rs @@ -2,8 +2,8 @@ * 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 ipc_channel::ipc::{self, IpcSender}; -use script_traits::ScriptMsg as ConstellationMsg; +use ipc_channel::ipc::channel; +use script_traits::{ScriptToConstellationChan, ScriptMsg}; use std::borrow::ToOwned; pub trait ClipboardProvider { @@ -13,14 +13,14 @@ pub trait ClipboardProvider { fn set_clipboard_contents(&mut self, String); } -impl ClipboardProvider for IpcSender<ConstellationMsg> { +impl ClipboardProvider for ScriptToConstellationChan { fn clipboard_contents(&mut self) -> String { - let (tx, rx) = ipc::channel().unwrap(); - self.send(ConstellationMsg::GetClipboardContents(tx)).unwrap(); + let (tx, rx) = channel().unwrap(); + self.send(ScriptMsg::GetClipboardContents(tx)).unwrap(); rx.recv().unwrap() } fn set_clipboard_contents(&mut self, s: String) { - self.send(ConstellationMsg::SetClipboardContents(s)).unwrap(); + self.send(ScriptMsg::SetClipboardContents(s)).unwrap(); } } diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index e16cd4dc571..81017cd344e 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -73,7 +73,7 @@ use profile_traits::time::ProfilerChan as TimeProfilerChan; use script_layout_interface::OpaqueStyleAndLayoutData; use script_layout_interface::reporter::CSSErrorReporter; use script_layout_interface::rpc::LayoutRPC; -use script_traits::{DocumentActivity, TimerEventId, TimerSource, TouchpadPressurePhase}; +use script_traits::{DocumentActivity, ScriptToConstellationChan, TimerEventId, TimerSource, TouchpadPressurePhase}; use script_traits::{UntrustedNodeAddress, WindowSizeData, WindowSizeType}; use script_traits::DrawAPaintImageResult; use selectors::matching::ElementSelectorFlags; @@ -400,6 +400,7 @@ unsafe_no_jsmanaged_fields!(WebGLTextureId); unsafe_no_jsmanaged_fields!(WebGLVertexArrayId); unsafe_no_jsmanaged_fields!(MediaList); unsafe_no_jsmanaged_fields!(WebVRGamepadHand); +unsafe_no_jsmanaged_fields!(ScriptToConstellationChan); unsafe impl<'a> JSTraceable for &'a str { #[inline] diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index f57df77cfa4..55d2ef3ceb4 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -42,7 +42,7 @@ use net_traits::image_cache::ImageResponse; use net_traits::image_cache::ImageState; use net_traits::image_cache::UsePlaceholder; use num_traits::ToPrimitive; -use script_traits::ScriptMsg as ConstellationMsg; +use script_traits::ScriptMsg; use servo_url::ServoUrl; use std::{cmp, fmt, mem}; use std::cell::Cell; @@ -130,9 +130,9 @@ impl CanvasRenderingContext2D { -> CanvasRenderingContext2D { debug!("Creating new canvas rendering context."); let (sender, receiver) = ipc::channel().unwrap(); - let constellation_chan = global.constellation_chan(); + let script_to_constellation_chan = global.script_to_constellation_chan(); debug!("Asking constellation to create new canvas thread."); - constellation_chan.send(ConstellationMsg::CreateCanvasPaintThread(size, sender)).unwrap(); + script_to_constellation_chan.send(ScriptMsg::CreateCanvasPaintThread(size, sender)).unwrap(); let ipc_renderer = receiver.recv().unwrap(); debug!("Done."); CanvasRenderingContext2D { diff --git a/components/script/dom/dissimilaroriginwindow.rs b/components/script/dom/dissimilaroriginwindow.rs index 6a106fab14c..a0eeb7d4a6e 100644 --- a/components/script/dom/dissimilaroriginwindow.rs +++ b/components/script/dom/dissimilaroriginwindow.rs @@ -17,7 +17,7 @@ use ipc_channel::ipc; use js::jsapi::{JSContext, HandleValue}; use js::jsval::{JSVal, UndefinedValue}; use msg::constellation_msg::PipelineId; -use script_traits::ScriptMsg as ConstellationMsg; +use script_traits::ScriptMsg; use servo_url::ImmutableOrigin; use servo_url::MutableOrigin; use servo_url::ServoUrl; @@ -54,7 +54,7 @@ impl DissimilarOriginWindow { global_to_clone_from.devtools_chan().cloned(), global_to_clone_from.mem_profiler_chan().clone(), global_to_clone_from.time_profiler_chan().clone(), - global_to_clone_from.constellation_chan().clone(), + global_to_clone_from.script_to_constellation_chan().clone(), global_to_clone_from.scheduler_chan().clone(), global_to_clone_from.resource_threads().clone(), timer_event_chan, @@ -184,9 +184,9 @@ impl DissimilarOriginWindowMethods for DissimilarOriginWindow { impl DissimilarOriginWindow { pub fn post_message(&self, origin: Option<ImmutableOrigin>, data: StructuredCloneData) { - let msg = ConstellationMsg::PostMessage(self.window_proxy.browsing_context_id(), + let msg = ScriptMsg::PostMessage(self.window_proxy.browsing_context_id(), origin, data.move_to_arraybuffer()); - let _ = self.upcast::<GlobalScope>().constellation_chan().send(msg); + let _ = self.upcast::<GlobalScope>().script_to_constellation_chan().send(msg); } } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 4f594f96357..4bc314fc7e4 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -115,7 +115,7 @@ use script_runtime::{CommonScriptMsg, ScriptThreadEventCategory}; use script_thread::{MainThreadScriptMsg, Runnable, ScriptThread}; use script_traits::{AnimationState, CompositorEvent, DocumentActivity}; use script_traits::{MouseButton, MouseEventType, MozBrowserEvent}; -use script_traits::{MsDuration, ScriptMsg as ConstellationMsg, TouchpadPressurePhase}; +use script_traits::{MsDuration, ScriptMsg, TouchpadPressurePhase}; use script_traits::{TouchEventType, TouchId}; use script_traits::UntrustedNodeAddress; use servo_arc::Arc; @@ -795,9 +795,7 @@ 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 { - let global_scope = self.window.upcast::<GlobalScope>(); - let event = ConstellationMsg::Focus(global_scope.pipeline_id()); - global_scope.constellation_chan().send(event).unwrap(); + self.send_to_constellation(ScriptMsg::Focus); } } } @@ -808,19 +806,14 @@ impl Document { // https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowsertitlechange self.trigger_mozbrowser_event(MozBrowserEvent::TitleChange(String::from(self.Title()))); - self.send_title_to_compositor(); + self.send_title_to_constellation(); } } - /// Sends this document's title to the compositor. - pub fn send_title_to_compositor(&self) { - let window = self.window(); - let global_scope = window.upcast::<GlobalScope>(); - global_scope - .constellation_chan() - .send(ConstellationMsg::SetTitle(global_scope.pipeline_id(), - Some(String::from(self.Title())))) - .unwrap(); + /// 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 dirty_all_nodes(&self) { @@ -872,8 +865,8 @@ impl Document { let child_point = client_point - child_origin; let event = CompositorEvent::MouseButtonEvent(mouse_event_type, button, child_point); - let event = ConstellationMsg::ForwardEvent(pipeline_id, event); - self.window.upcast::<GlobalScope>().constellation_chan().send(event).unwrap(); + let event = ScriptMsg::ForwardEvent(pipeline_id, event); + self.send_to_constellation(event); } return; } @@ -1029,8 +1022,8 @@ impl Document { let event = CompositorEvent::TouchpadPressureEvent(child_point, pressure, phase_now); - let event = ConstellationMsg::ForwardEvent(pipeline_id, event); - self.window.upcast::<GlobalScope>().constellation_chan().send(event).unwrap(); + let event = ScriptMsg::ForwardEvent(pipeline_id, event); + self.send_to_constellation(event); } return; } @@ -1131,8 +1124,8 @@ impl Document { let child_point = client_point - child_origin; let event = CompositorEvent::MouseMoveEvent(Some(child_point)); - let event = ConstellationMsg::ForwardEvent(pipeline_id, event); - self.window.upcast::<GlobalScope>().constellation_chan().send(event).unwrap(); + let event = ScriptMsg::ForwardEvent(pipeline_id, event); + self.send_to_constellation(event); } return; } @@ -1238,8 +1231,8 @@ impl Document { let child_point = point - child_origin; let event = CompositorEvent::TouchEvent(event_type, touch_id, child_point); - let event = ConstellationMsg::ForwardEvent(pipeline_id, event); - self.window.upcast::<GlobalScope>().constellation_chan().send(event).unwrap(); + let event = ScriptMsg::ForwardEvent(pipeline_id, event); + self.send_to_constellation(event); } return TouchEventResult::Forwarded; } @@ -1330,8 +1323,7 @@ impl Document { ch: Option<char>, key: Key, state: KeyState, - modifiers: KeyModifiers, - constellation: &IpcSender<ConstellationMsg>) { + modifiers: KeyModifiers) { let focused = self.get_focused_element(); let body = self.GetBody(); @@ -1407,7 +1399,8 @@ impl Document { } if cancel_state == EventDefault::Allowed { - constellation.send(ConstellationMsg::SendKeyEvent(ch, key, state, modifiers)).unwrap(); + let msg = ScriptMsg::SendKeyEvent(ch, key, state, modifiers); + self.send_to_constellation(msg); // This behavior is unspecced // We are supposed to dispatch synthetic click activation for Space and/or Return, @@ -1525,11 +1518,8 @@ impl Document { pub fn trigger_mozbrowser_event(&self, event: MozBrowserEvent) { if PREFS.is_mozbrowser_enabled() { if let Some((parent_pipeline_id, _)) = self.window.parent_info() { - let top_level_browsing_context_id = self.window.window_proxy().top_level_browsing_context_id(); - let event = ConstellationMsg::MozBrowserEvent(parent_pipeline_id, - top_level_browsing_context_id, - event); - self.window.upcast::<GlobalScope>().constellation_chan().send(event).unwrap(); + let event = ScriptMsg::MozBrowserEvent(parent_pipeline_id, event); + self.send_to_constellation(event); } } } @@ -1559,11 +1549,8 @@ impl Document { // This reduces CPU usage by avoiding needless thread wakeups in the common case of // repeated rAF. - let global_scope = self.window.upcast::<GlobalScope>(); - let event = ConstellationMsg::ChangeRunningAnimationsState( - global_scope.pipeline_id(), - AnimationState::AnimationCallbacksPresent); - global_scope.constellation_chan().send(event).unwrap(); + let event = ScriptMsg::ChangeRunningAnimationsState(AnimationState::AnimationCallbacksPresent); + self.send_to_constellation(event); } ident @@ -1629,11 +1616,8 @@ impl Document { (!was_faking_animation_frames && self.is_faking_animation_frames()) { mem::swap(&mut *self.animation_frame_list.borrow_mut(), &mut *animation_frame_list); - let global_scope = self.window.upcast::<GlobalScope>(); - let event = ConstellationMsg::ChangeRunningAnimationsState( - global_scope.pipeline_id(), - AnimationState::NoAnimationCallbacksPresent); - global_scope.constellation_chan().send(event).unwrap(); + let event = ScriptMsg::ChangeRunningAnimationsState(AnimationState::NoAnimationCallbacksPresent); + self.send_to_constellation(event); } // Update the counter of spurious animation frames. @@ -1896,10 +1880,7 @@ impl Document { } pub fn notify_constellation_load(&self) { - let global_scope = self.window.upcast::<GlobalScope>(); - let pipeline_id = global_scope.pipeline_id(); - let load_event = ConstellationMsg::LoadComplete(pipeline_id); - global_scope.constellation_chan().send(load_event).unwrap(); + self.send_to_constellation(ScriptMsg::LoadComplete); } pub fn set_current_parser(&self, script: Option<&ServoParser>) { @@ -2024,6 +2005,11 @@ impl Document { 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(); + } } #[derive(PartialEq, HeapSizeOf)] @@ -2525,8 +2511,8 @@ impl Document { let window = self.window(); // Step 6 if !error { - let event = ConstellationMsg::SetFullscreenState(true); - window.upcast::<GlobalScope>().constellation_chan().send(event).unwrap(); + let event = ScriptMsg::SetFullscreenState(true); + self.send_to_constellation(event); } // Step 7 @@ -2558,8 +2544,8 @@ impl Document { let window = self.window(); // Step 8 - let event = ConstellationMsg::SetFullscreenState(false); - window.upcast::<GlobalScope>().constellation_chan().send(event).unwrap(); + let event = ScriptMsg::SetFullscreenState(false); + self.send_to_constellation(event); // Step 9 let trusted_element = Trusted::new(element.r()); diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index 3a47298c53b..b90e4204c2e 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -37,7 +37,7 @@ use net_traits::{CoreResourceThread, ResourceThreads, IpcSend}; use profile_traits::{mem, time}; use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort}; use script_thread::{MainThreadScriptChan, RunnableWrapper, ScriptThread}; -use script_traits::{MsDuration, ScriptMsg as ConstellationMsg, TimerEvent}; +use script_traits::{MsDuration, ScriptToConstellationChan, TimerEvent}; use script_traits::{TimerEventId, TimerSchedulerMsg, TimerSource}; use servo_url::{MutableOrigin, ServoUrl}; use std::cell::Cell; @@ -80,7 +80,7 @@ pub struct GlobalScope { /// A handle for communicating messages to the constellation thread. #[ignore_heap_size_of = "channels are hard"] - constellation_chan: IpcSender<ConstellationMsg>, + script_to_constellation_chan: ScriptToConstellationChan, #[ignore_heap_size_of = "channels are hard"] scheduler_chan: IpcSender<TimerSchedulerMsg>, @@ -104,7 +104,7 @@ impl GlobalScope { devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, mem_profiler_chan: mem::ProfilerChan, time_profiler_chan: time::ProfilerChan, - constellation_chan: IpcSender<ConstellationMsg>, + script_to_constellation_chan: ScriptToConstellationChan, scheduler_chan: IpcSender<TimerSchedulerMsg>, resource_threads: ResourceThreads, timer_event_chan: IpcSender<TimerEvent>, @@ -120,7 +120,7 @@ impl GlobalScope { devtools_chan: devtools_chan, mem_profiler_chan: mem_profiler_chan, time_profiler_chan: time_profiler_chan, - constellation_chan: constellation_chan, + script_to_constellation_chan: script_to_constellation_chan, scheduler_chan: scheduler_chan.clone(), in_error_reporting_mode: Default::default(), resource_threads: resource_threads, @@ -231,8 +231,8 @@ impl GlobalScope { } /// Get a sender to the constellation thread. - pub fn constellation_chan(&self) -> &IpcSender<ConstellationMsg> { - &self.constellation_chan + pub fn script_to_constellation_chan(&self) -> &ScriptToConstellationChan { + &self.script_to_constellation_chan } pub fn scheduler_chan(&self) -> &IpcSender<TimerSchedulerMsg> { diff --git a/components/script/dom/history.rs b/components/script/dom/history.rs index b9601d2ca1c..9344f3f4b80 100644 --- a/components/script/dom/history.rs +++ b/components/script/dom/history.rs @@ -15,7 +15,7 @@ use dom::window::Window; use dom_struct::dom_struct; use ipc_channel::ipc; use msg::constellation_msg::TraversalDirection; -use script_traits::ScriptMsg as ConstellationMsg; +use script_traits::ScriptMsg; // https://html.spec.whatwg.org/multipage/#the-history-interface #[dom_struct] @@ -44,9 +44,8 @@ impl History { if !self.window.Document().is_fully_active() { return Err(Error::Security); } - let top_level_browsing_context_id = self.window.window_proxy().top_level_browsing_context_id(); - let msg = ConstellationMsg::TraverseHistory(top_level_browsing_context_id, direction); - let _ = self.window.upcast::<GlobalScope>().constellation_chan().send(msg); + let msg = ScriptMsg::TraverseHistory(direction); + let _ = self.window.upcast::<GlobalScope>().script_to_constellation_chan().send(msg); Ok(()) } } @@ -57,10 +56,9 @@ impl HistoryMethods for History { if !self.window.Document().is_fully_active() { return Err(Error::Security); } - let top_level_browsing_context_id = self.window.window_proxy().top_level_browsing_context_id(); let (sender, recv) = ipc::channel().expect("Failed to create channel to send jsh length."); - let msg = ConstellationMsg::JointSessionHistoryLength(top_level_browsing_context_id, sender); - let _ = self.window.upcast::<GlobalScope>().constellation_chan().send(msg); + let msg = ScriptMsg::JointSessionHistoryLength(sender); + let _ = self.window.upcast::<GlobalScope>().script_to_constellation_chan().send(msg); Ok(recv.recv().unwrap()) } diff --git a/components/script/dom/htmlbodyelement.rs b/components/script/dom/htmlbodyelement.rs index c5c03164a61..e1b0c86f5c0 100644 --- a/components/script/dom/htmlbodyelement.rs +++ b/components/script/dom/htmlbodyelement.rs @@ -19,7 +19,7 @@ use dom::node::{Node, document_from_node, window_from_node}; use dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; use html5ever::{LocalName, Prefix}; -use script_traits::ScriptMsg as ConstellationMsg; +use script_traits::ScriptMsg; use servo_url::ServoUrl; use style::attr::AttrValue; use time; @@ -138,8 +138,8 @@ 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 = ConstellationMsg::HeadParsed; - window.upcast::<GlobalScope>().constellation_chan().send(event).unwrap(); + let event = ScriptMsg::HeadParsed; + window.upcast::<GlobalScope>().script_to_constellation_chan().send(event).unwrap(); } fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue { diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index bde40d11a2b..47a1d2adfcb 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -45,7 +45,7 @@ use net_traits::response::HttpsState; use script_layout_interface::message::ReflowQueryType; use script_thread::{ScriptThread, Runnable}; use script_traits::{IFrameLoadInfo, IFrameLoadInfoWithData, LoadData, UpdatePipelineIdReason}; -use script_traits::{MozBrowserEvent, NewLayoutInfo, ScriptMsg as ConstellationMsg}; +use script_traits::{MozBrowserEvent, NewLayoutInfo, ScriptMsg}; use script_traits::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed}; use servo_atoms::Atom; use servo_config::prefs::PREFS; @@ -170,8 +170,8 @@ impl HTMLIFrameElement { let (pipeline_sender, pipeline_receiver) = ipc::channel().unwrap(); global_scope - .constellation_chan() - .send(ConstellationMsg::ScriptNewIFrame(load_info, pipeline_sender)) + .script_to_constellation_chan() + .send(ScriptMsg::ScriptNewIFrame(load_info, pipeline_sender)) .unwrap(); let new_layout_info = NewLayoutInfo { @@ -197,8 +197,8 @@ impl HTMLIFrameElement { sandbox: sandboxed, }; global_scope - .constellation_chan() - .send(ConstellationMsg::ScriptLoadedURLInIFrame(load_info)) + .script_to_constellation_chan() + .send(ScriptMsg::ScriptLoadedURLInIFrame(load_info)) .unwrap(); } } @@ -349,11 +349,9 @@ impl HTMLIFrameElement { } pub fn set_visible(&self, visible: bool) { - if let Some(pipeline_id) = self.pipeline_id.get() { - let window = window_from_node(self); - let msg = ConstellationMsg::SetVisible(pipeline_id, visible); - window.upcast::<GlobalScope>().constellation_chan().send(msg).unwrap(); - } + let msg = ScriptMsg::SetVisible(visible); + let window = window_from_node(self); + window.upcast::<GlobalScope>().script_to_constellation_chan().send(msg).unwrap(); } /// https://html.spec.whatwg.org/multipage/#iframe-load-event-steps steps 1-4 @@ -540,10 +538,10 @@ unsafe fn build_mozbrowser_event_detail(event: MozBrowserEvent, pub fn Navigate(iframe: &HTMLIFrameElement, direction: TraversalDirection) -> ErrorResult { if iframe.Mozbrowser() { - if let Some(top_level_browsing_context_id) = iframe.top_level_browsing_context_id() { + if let Some(_) = iframe.top_level_browsing_context_id() { let window = window_from_node(iframe); - let msg = ConstellationMsg::TraverseHistory(top_level_browsing_context_id, direction); - window.upcast::<GlobalScope>().constellation_chan().send(msg).unwrap(); + let msg = ScriptMsg::TraverseHistory(direction); + window.upcast::<GlobalScope>().script_to_constellation_chan().send(msg).unwrap(); return Ok(()); } } @@ -795,8 +793,8 @@ impl VirtualMethods for HTMLIFrameElement { }; debug!("Unbinding frame {}.", browsing_context_id); - let msg = ConstellationMsg::RemoveIFrame(browsing_context_id, sender); - window.upcast::<GlobalScope>().constellation_chan().send(msg).unwrap(); + let msg = ScriptMsg::RemoveIFrame(browsing_context_id, sender); + window.upcast::<GlobalScope>().script_to_constellation_chan().send(msg).unwrap(); let exited_pipeline_ids = receiver.recv().unwrap(); // The spec for discarding is synchronous, diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index fc20326b906..efd12589e82 100755 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -38,13 +38,13 @@ use dom::validitystate::ValidationFlags; use dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; use html5ever::{LocalName, Prefix}; -use ipc_channel::ipc::{self, IpcSender}; +use ipc_channel::ipc::channel; use mime_guess; use net_traits::{CoreResourceMsg, IpcSend}; use net_traits::blob_url_store::get_blob_origin; use net_traits::filemanager_thread::{FileManagerThreadMsg, FilterPattern}; use script_layout_interface::rpc::TextIndexResponse; -use script_traits::ScriptMsg as ConstellationMsg; +use script_traits::ScriptToConstellationChan; use servo_atoms::Atom; use std::borrow::ToOwned; use std::cell::Cell; @@ -94,7 +94,7 @@ pub struct HTMLInputElement { maxlength: Cell<i32>, minlength: Cell<i32>, #[ignore_heap_size_of = "#7193"] - textinput: DOMRefCell<TextInput<IpcSender<ConstellationMsg>>>, + textinput: DOMRefCell<TextInput<ScriptToConstellationChan>>, activation_state: DOMRefCell<InputActivationState>, // https://html.spec.whatwg.org/multipage/#concept-input-value-dirty-flag value_dirty: Cell<bool>, @@ -136,7 +136,7 @@ static DEFAULT_MIN_LENGTH: i32 = -1; impl HTMLInputElement { fn new_inherited(local_name: LocalName, prefix: Option<Prefix>, document: &Document) -> HTMLInputElement { - let chan = document.window().upcast::<GlobalScope>().constellation_chan().clone(); + let chan = document.window().upcast::<GlobalScope>().script_to_constellation_chan().clone(); HTMLInputElement { htmlelement: HTMLElement::new_inherited_with_state(IN_ENABLED_STATE | IN_READ_WRITE_STATE, @@ -814,7 +814,7 @@ impl HTMLInputElement { if self.Multiple() { let opt_test_paths = opt_test_paths.map(|paths| paths.iter().map(|p| p.to_string()).collect()); - let (chan, recv) = ipc::channel().expect("Error initializing channel"); + let (chan, recv) = channel().expect("Error initializing channel"); let msg = FileManagerThreadMsg::SelectFiles(filter, chan, origin, opt_test_paths); let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg)).unwrap(); @@ -838,7 +838,7 @@ impl HTMLInputElement { None => None, }; - let (chan, recv) = ipc::channel().expect("Error initializing channel"); + let (chan, recv) = channel().expect("Error initializing channel"); let msg = FileManagerThreadMsg::SelectFile(filter, chan, origin, opt_test_path); let _ = resource_threads.send(CoreResourceMsg::ToFileManager(msg)).unwrap(); diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index 8175da5c913..e30dbbc783d 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -25,7 +25,7 @@ use dom_struct::dom_struct; use html5ever::{LocalName, Prefix}; use net_traits::ReferrerPolicy; use script_layout_interface::message::Msg; -use script_traits::{MozBrowserEvent, ScriptMsg as ConstellationMsg}; +use script_traits::{MozBrowserEvent, ScriptMsg}; use servo_arc::Arc; use std::ascii::AsciiExt; use std::borrow::ToOwned; @@ -309,8 +309,8 @@ impl HTMLLinkElement { let document = document_from_node(self); match document.base_url().join(href) { Ok(url) => { - let event = ConstellationMsg::NewFavicon(url.clone()); - document.window().upcast::<GlobalScope>().constellation_chan().send(event).unwrap(); + let event = ScriptMsg::NewFavicon(url.clone()); + document.window().upcast::<GlobalScope>().script_to_constellation_chan().send(event).unwrap(); let mozbrowser_event = match *sizes { Some(ref sizes) => MozBrowserEvent::IconChange(rel.to_owned(), url.to_string(), sizes.to_owned()), diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs index 3033480b03d..fc48564d030 100755 --- a/components/script/dom/htmltextareaelement.rs +++ b/components/script/dom/htmltextareaelement.rs @@ -27,8 +27,7 @@ use dom::validation::Validatable; use dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; use html5ever::{LocalName, Prefix}; -use ipc_channel::ipc::IpcSender; -use script_traits::ScriptMsg as ConstellationMsg; +use script_traits::ScriptToConstellationChan; use std::cell::Cell; use std::default::Default; use std::ops::Range; @@ -40,7 +39,7 @@ use textinput::{KeyReaction, Lines, SelectionDirection, TextInput}; pub struct HTMLTextAreaElement { htmlelement: HTMLElement, #[ignore_heap_size_of = "#7193"] - textinput: DOMRefCell<TextInput<IpcSender<ConstellationMsg>>>, + textinput: DOMRefCell<TextInput<ScriptToConstellationChan>>, placeholder: DOMRefCell<DOMString>, // https://html.spec.whatwg.org/multipage/#concept-textarea-dirty value_changed: Cell<bool>, @@ -109,7 +108,7 @@ impl HTMLTextAreaElement { fn new_inherited(local_name: LocalName, prefix: Option<Prefix>, document: &Document) -> HTMLTextAreaElement { - let chan = document.window().upcast::<GlobalScope>().constellation_chan().clone(); + let chan = document.window().upcast::<GlobalScope>().script_to_constellation_chan().clone(); HTMLTextAreaElement { htmlelement: HTMLElement::new_inherited_with_state(IN_ENABLED_STATE | IN_READ_WRITE_STATE, diff --git a/components/script/dom/serviceworker.rs b/components/script/dom/serviceworker.rs index 7e17a9040e7..0c651e07aa4 100644 --- a/components/script/dom/serviceworker.rs +++ b/components/script/dom/serviceworker.rs @@ -93,7 +93,7 @@ impl ServiceWorkerMethods for ServiceWorker { let msg_vec = DOMMessage(data.move_to_arraybuffer()); let _ = self.global() - .constellation_chan() + .script_to_constellation_chan() .send(ScriptMsg::ForwardDOMMessage(msg_vec, self.scope_url.clone())); Ok(()) } diff --git a/components/script/dom/storage.rs b/components/script/dom/storage.rs index ea4662dda20..d596a6243de 100644 --- a/components/script/dom/storage.rs +++ b/components/script/dom/storage.rs @@ -151,11 +151,10 @@ impl Storage { /// https://html.spec.whatwg.org/multipage/#send-a-storage-notification fn broadcast_change_notification(&self, key: Option<String>, old_value: Option<String>, new_value: Option<String>) { - let pipeline_id = self.global().pipeline_id(); let storage = self.storage_type; let url = self.get_url(); - let msg = ScriptMsg::BroadcastStorageEvent(pipeline_id, storage, url, key, old_value, new_value); - self.global().constellation_chan().send(msg).unwrap(); + let msg = ScriptMsg::BroadcastStorageEvent(storage, url, key, old_value, new_value); + self.global().script_to_constellation_chan().send(msg).unwrap(); } /// https://html.spec.whatwg.org/multipage/#send-a-storage-notification diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 73d4ddba1b9..48e6996b85f 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -50,7 +50,7 @@ use js::typedarray::{TypedArray, TypedArrayElement, Float32, Int32}; use net_traits::image::base::PixelFormat; use net_traits::image_cache::ImageResponse; use offscreen_gl_context::{GLContextAttributes, GLLimits}; -use script_traits::ScriptMsg as ConstellationMsg; +use script_traits::ScriptMsg; use servo_config::prefs::PREFS; use std::cell::Cell; use std::collections::HashMap; @@ -172,8 +172,8 @@ impl WebGLRenderingContext { } let (sender, receiver) = ipc::channel().unwrap(); - let constellation_chan = window.upcast::<GlobalScope>().constellation_chan(); - constellation_chan.send(ConstellationMsg::CreateWebGLPaintThread(size, attrs, sender)) + let script_to_constellation_chan = window.upcast::<GlobalScope>().script_to_constellation_chan(); + script_to_constellation_chan.send(ScriptMsg::CreateWebGLPaintThread(size, attrs, sender)) .unwrap(); let result = receiver.recv().unwrap(); diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 3c87e5f6b0b..90693a2ccbf 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -80,7 +80,7 @@ use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, ScriptThreadEventC use script_thread::{ImageCacheMsg, MainThreadScriptChan, MainThreadScriptMsg, Runnable}; use script_thread::{RunnableWrapper, ScriptThread, SendableMainThreadScriptChan}; use script_traits::{ConstellationControlMsg, DocumentState, LoadData, MozBrowserEvent}; -use script_traits::{ScriptMsg as ConstellationMsg, ScrollState, TimerEvent, TimerEventId}; +use script_traits::{ScriptToConstellationChan, ScriptMsg, ScrollState, TimerEvent, TimerEventId}; use script_traits::{TimerSchedulerMsg, UntrustedNodeAddress, WindowSizeData, WindowSizeType}; use script_traits::webdriver_msg::{WebDriverJSError, WebDriverJSResult}; use selectors::attr::CaseSensitivity; @@ -515,11 +515,7 @@ impl WindowMethods for Window { } let (sender, receiver) = ipc::channel().unwrap(); - let global_scope = self.upcast::<GlobalScope>(); - global_scope - .constellation_chan() - .send(ConstellationMsg::Alert(global_scope.pipeline_id(), s.to_string(), sender)) - .unwrap(); + self.send_to_constellation(ScriptMsg::Alert(s.to_string(), sender)); let should_display_alert_dialog = receiver.recv().unwrap(); if should_display_alert_dialog { @@ -918,10 +914,7 @@ impl WindowMethods for Window { // Step 1 //TODO determine if this operation is allowed let size = Size2D::new(x.to_u32().unwrap_or(1), y.to_u32().unwrap_or(1)); - self.upcast::<GlobalScope>() - .constellation_chan() - .send(ConstellationMsg::ResizeTo(size)) - .unwrap() + self.send_to_constellation(ScriptMsg::ResizeTo(size)); } // https://drafts.csswg.org/cssom-view/#dom-window-resizeby @@ -936,10 +929,7 @@ impl WindowMethods for Window { // Step 1 //TODO determine if this operation is allowed let point = Point2D::new(x, y); - self.upcast::<GlobalScope>() - .constellation_chan() - .send(ConstellationMsg::MoveTo(point)) - .unwrap() + self.send_to_constellation(ScriptMsg::MoveTo(point)); } // https://drafts.csswg.org/cssom-view/#dom-window-moveby @@ -1159,9 +1149,8 @@ impl Window { scroll_offset: Vector2D::new(-x, -y), })).unwrap(); - let global_scope = self.upcast::<GlobalScope>(); - let message = ConstellationMsg::ScrollFragmentPoint(scroll_root_id, point, smooth); - global_scope.constellation_chan().send(message).unwrap(); + let message = ScriptMsg::ScrollFragmentPoint(scroll_root_id, point, smooth); + self.send_to_constellation(message); } pub fn update_viewport_for_scroll(&self, x: f32, y: f32) { @@ -1172,10 +1161,7 @@ impl Window { pub fn client_window(&self) -> (Size2D<u32>, Point2D<i32>) { let (send, recv) = ipc::channel::<(Size2D<u32>, Point2D<i32>)>().unwrap(); - self.upcast::<GlobalScope>() - .constellation_chan() - .send(ConstellationMsg::GetClientWindow(send)) - .unwrap(); + self.send_to_constellation(ScriptMsg::GetClientWindow(send)); recv.recv().unwrap_or((Size2D::zero(), Point2D::zero())) } @@ -1371,9 +1357,8 @@ impl Window { let pending_images = self.pending_layout_images.borrow().is_empty(); if ready_state == DocumentReadyState::Complete && !reftest_wait && pending_images { - let global_scope = self.upcast::<GlobalScope>(); - let event = ConstellationMsg::SetDocumentState(global_scope.pipeline_id(), DocumentState::Idle); - global_scope.constellation_chan().send(event).unwrap(); + let event = ScriptMsg::SetDocumentState(DocumentState::Idle); + self.send_to_constellation(event); } } @@ -1779,6 +1764,13 @@ impl Window { self.navigation_start.set(now); self.navigation_start_precise.set(time::precise_time_ns() as f64); } + + fn send_to_constellation(&self, msg: ScriptMsg) { + self.upcast::<GlobalScope>() + .script_to_constellation_chan() + .send(msg) + .unwrap(); + } } impl Window { @@ -1797,7 +1789,7 @@ impl Window { mem_profiler_chan: MemProfilerChan, time_profiler_chan: TimeProfilerChan, devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, - constellation_chan: IpcSender<ConstellationMsg>, + constellation_chan: ScriptToConstellationChan, control_chan: IpcSender<ConstellationControlMsg>, scheduler_chan: IpcSender<TimerSchedulerMsg>, timer_event_chan: IpcSender<TimerEvent>, diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index f5f0e957898..7028518a7c2 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -55,7 +55,7 @@ pub fn prepare_workerscope_init(global: &GlobalScope, to_devtools_sender: global.devtools_chan().cloned(), time_profiler_chan: global.time_profiler_chan().clone(), from_devtools_sender: devtools_sender, - constellation_chan: global.constellation_chan().clone(), + script_to_constellation_chan: global.script_to_constellation_chan().clone(), scheduler_chan: global.scheduler_chan().clone(), worker_id: global.get_next_worker_id(), pipeline_id: global.pipeline_id(), @@ -107,7 +107,7 @@ impl WorkerGlobalScope { init.to_devtools_sender, init.mem_profiler_chan, init.time_profiler_chan, - init.constellation_chan, + init.script_to_constellation_chan, init.scheduler_chan, init.resource_threads, timer_event_chan, diff --git a/components/script/dom/worklet.rs b/components/script/dom/worklet.rs index c492bb3ea16..653155a9433 100644 --- a/components/script/dom/worklet.rs +++ b/components/script/dom/worklet.rs @@ -609,7 +609,7 @@ impl WorkletThread { if old_counter == 1 { debug!("Resolving promise."); let msg = MainThreadScriptMsg::WorkletLoaded(pipeline_id); - self.global_init.script_sender.send(msg).expect("Worklet thread outlived script thread."); + self.global_init.to_script_thread_sender.send(msg).expect("Worklet thread outlived script thread."); self.run_in_script_thread(promise.resolve_runnable(())); } } @@ -651,7 +651,7 @@ impl WorkletThread { { let msg = CommonScriptMsg::RunnableMsg(ScriptThreadEventCategory::WorkletEvent, box runnable); let msg = MainThreadScriptMsg::Common(msg); - self.global_init.script_sender.send(msg).expect("Worklet thread outlived script thread."); + self.global_init.to_script_thread_sender.send(msg).expect("Worklet thread outlived script thread."); } } diff --git a/components/script/dom/workletglobalscope.rs b/components/script/dom/workletglobalscope.rs index d8b5fdac22d..bfefd9d4758 100644 --- a/components/script/dom/workletglobalscope.rs +++ b/components/script/dom/workletglobalscope.rs @@ -31,6 +31,7 @@ use script_thread::MainThreadScriptMsg; use script_thread::Runnable; use script_thread::ScriptThread; use script_traits::ScriptMsg; +use script_traits::ScriptToConstellationChan; use script_traits::TimerSchedulerMsg; use servo_url::ImmutableOrigin; use servo_url::MutableOrigin; @@ -49,7 +50,7 @@ pub struct WorkletGlobalScope { microtask_queue: MicrotaskQueue, /// Sender back to the script thread #[ignore_heap_size_of = "channels are hard"] - script_sender: Sender<MainThreadScriptMsg>, + to_script_thread_sender: Sender<MainThreadScriptMsg>, /// Worklet task executor executor: WorkletExecutor, } @@ -63,19 +64,23 @@ impl WorkletGlobalScope { -> WorkletGlobalScope { // Any timer events fired on this global are ignored. let (timer_event_chan, _) = ipc::channel().unwrap(); + let script_to_constellation_chan = ScriptToConstellationChan { + sender: init.to_constellation_sender.clone(), + pipeline_id: pipeline_id, + }; WorkletGlobalScope { globalscope: GlobalScope::new_inherited(pipeline_id, init.devtools_chan.clone(), init.mem_profiler_chan.clone(), init.time_profiler_chan.clone(), - init.constellation_chan.clone(), + script_to_constellation_chan, init.scheduler_chan.clone(), init.resource_threads.clone(), timer_event_chan, MutableOrigin::new(ImmutableOrigin::new_opaque())), base_url: base_url, microtask_queue: MicrotaskQueue::default(), - script_sender: init.script_sender.clone(), + to_script_thread_sender: init.to_script_thread_sender.clone(), executor: executor, } } @@ -98,7 +103,7 @@ impl WorkletGlobalScope { { let msg = CommonScriptMsg::RunnableMsg(ScriptThreadEventCategory::WorkletEvent, box runnable); let msg = MainThreadScriptMsg::Common(msg); - self.script_sender.send(msg).expect("Worklet thread outlived script thread."); + self.to_script_thread_sender.send(msg).expect("Worklet thread outlived script thread."); } /// Send a message to layout. @@ -156,7 +161,7 @@ impl WorkletGlobalScope { #[derive(Clone)] pub struct WorkletGlobalScopeInit { /// Channel to the main script thread - pub script_sender: Sender<MainThreadScriptMsg>, + pub to_script_thread_sender: Sender<MainThreadScriptMsg>, /// Channel to a resource thread pub resource_threads: ResourceThreads, /// Channel to the memory profiler @@ -166,7 +171,7 @@ pub struct WorkletGlobalScopeInit { /// Channel to devtools pub devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, /// Messages to send to constellation - pub constellation_chan: IpcSender<ScriptMsg>, + pub to_constellation_sender: IpcSender<(PipelineId, ScriptMsg)>, /// Message to send to the scheduler pub scheduler_chan: IpcSender<TimerSchedulerMsg>, /// The image cache diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 4a4657e28a5..ea8038897ac 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -87,7 +87,7 @@ use script_runtime::{ScriptPort, StackRootTLS, get_reports, new_rt_and_cx}; use script_traits::{CompositorEvent, ConstellationControlMsg}; use script_traits::{DocumentActivity, DiscardBrowsingContext, EventResult}; use script_traits::{InitialScriptState, LayoutMsg, LoadData, MouseButton, MouseEventType, MozBrowserEvent}; -use script_traits::{NewLayoutInfo, ScriptMsg as ConstellationMsg, UpdatePipelineIdReason}; +use script_traits::{NewLayoutInfo, ScriptToConstellationChan, ScriptMsg, UpdatePipelineIdReason}; use script_traits::{ScriptThreadFactory, TimerEvent, TimerSchedulerMsg, TimerSource}; use script_traits::{TouchEventType, TouchId, UntrustedNodeAddress, WindowSizeData, WindowSizeType}; use script_traits::CompositorEvent::{KeyEvent, MouseButtonEvent, MouseMoveEvent, ResizeEvent}; @@ -462,7 +462,7 @@ pub struct ScriptThread { control_port: Receiver<ConstellationControlMsg>, /// For communicating load url messages to the constellation - constellation_chan: IpcSender<ConstellationMsg>, + script_sender: IpcSender<(PipelineId, ScriptMsg)>, /// A sender for new layout threads to communicate to the constellation. layout_to_constellation_chan: IpcSender<LayoutMsg>, @@ -733,12 +733,12 @@ impl ScriptThread { let script_thread = unsafe { &*root.get().unwrap() }; script_thread.worklet_thread_pool.borrow_mut().get_or_insert_with(|| { let init = WorkletGlobalScopeInit { - script_sender: script_thread.chan.0.clone(), + to_script_thread_sender: script_thread.chan.0.clone(), resource_threads: script_thread.resource_threads.clone(), mem_profiler_chan: script_thread.mem_profiler_chan.clone(), time_profiler_chan: script_thread.time_profiler_chan.clone(), devtools_chan: script_thread.devtools_chan.clone(), - constellation_chan: script_thread.constellation_chan.clone(), + to_constellation_sender: script_thread.script_sender.clone(), scheduler_chan: script_thread.scheduler_chan.clone(), image_cache: script_thread.image_cache.clone(), }; @@ -855,7 +855,7 @@ impl ScriptThread { control_chan: state.control_chan, control_port: control_port, - constellation_chan: state.constellation_chan, + script_sender: state.script_to_constellation_chan.sender.clone(), time_profiler_chan: state.time_profiler_chan, mem_profiler_chan: state.mem_profiler_chan, @@ -1543,7 +1543,7 @@ impl ScriptThread { fn handle_visibility_change_msg(&self, id: PipelineId, visible: bool) { // Separate message sent since parent script thread could be different (Iframe of different // domain) - self.constellation_chan.send(ConstellationMsg::VisibilityChangeComplete(id, visible)).unwrap(); + self.script_sender.send((id, ScriptMsg::VisibilityChangeComplete(visible))).unwrap(); let window = self.documents.borrow().find_window(id); match window { @@ -1643,13 +1643,13 @@ impl ScriptThread { /// constellation to shut down the pipeline, which will clean everything up /// normally. If we do exit, we will tear down the DOM nodes, possibly at a point /// where layout is still accessing them. - fn handle_exit_window_msg(&self, _: PipelineId) { + fn handle_exit_window_msg(&self, id: PipelineId) { debug!("script thread handling exit window msg"); // TODO(tkuehn): currently there is only one window, // so this can afford to be naive and just shut down the // constellation. In the future it'll need to be smarter. - self.constellation_chan.send(ConstellationMsg::Exit).unwrap(); + self.script_sender.send((id, ScriptMsg::Exit)).unwrap(); } /// We have received notification that the response associated with a load has completed. @@ -1701,7 +1701,7 @@ impl ScriptThread { let script_url = maybe_registration.get_installed().get_script_url(); let scope_things = ServiceWorkerRegistration::create_scope_things(window.upcast(), script_url); - let _ = self.constellation_chan.send(ConstellationMsg::RegisterServiceWorker(scope_things, scope.clone())); + let _ = self.script_sender.send((pipeline_id, ScriptMsg::RegisterServiceWorker(scope_things, scope.clone()))); } pub fn dispatch_job_queue(&self, job_handler: Box<AsyncJobHandler>) { @@ -1718,7 +1718,7 @@ impl ScriptThread { Some(document) => document, None => return warn!("Message sent to closed pipeline {}.", pipeline_id), }; - document.send_title_to_compositor(); + document.send_title_to_constellation(); } /// Handles a request to exit a pipeline and shut down layout. @@ -1758,7 +1758,7 @@ impl ScriptThread { debug!("shutting down layout for page {}", id); let _ = response_port.recv(); chan.send(message::Msg::ExitNow).ok(); - self.constellation_chan.send(ConstellationMsg::PipelineExited(id)).ok(); + self.script_sender.send((id, ScriptMsg::PipelineExited)).ok(); debug!("Exited pipeline {}.", id); } @@ -1883,15 +1883,15 @@ impl ScriptThread { fn ask_constellation_for_browsing_context_id(&self, pipeline_id: PipelineId) -> Option<BrowsingContextId> { let (result_sender, result_receiver) = ipc::channel().unwrap(); - let msg = ConstellationMsg::GetBrowsingContextId(pipeline_id, result_sender); - self.constellation_chan.send(msg).expect("Failed to send to constellation."); + let msg = ScriptMsg::GetBrowsingContextId(pipeline_id, result_sender); + self.script_sender.send((pipeline_id, msg)).expect("Failed to send to constellation."); result_receiver.recv().expect("Failed to get frame id from constellation.") } fn ask_constellation_for_parent_info(&self, pipeline_id: PipelineId) -> Option<(PipelineId, FrameType)> { let (result_sender, result_receiver) = ipc::channel().unwrap(); - let msg = ConstellationMsg::GetParentInfo(pipeline_id, result_sender); - self.constellation_chan.send(msg).expect("Failed to send to constellation."); + let msg = ScriptMsg::GetParentInfo(pipeline_id, result_sender); + self.script_sender.send((pipeline_id, msg)).expect("Failed to send to constellation."); result_receiver.recv().expect("Failed to get frame id from constellation.") } @@ -1976,8 +1976,8 @@ impl ScriptThread { .unwrap(); // update the pipeline url - self.constellation_chan - .send(ConstellationMsg::SetFinalUrl(incomplete.pipeline_id, final_url.clone())) + self.script_sender + .send((incomplete.pipeline_id, ScriptMsg::SetFinalUrl(final_url.clone()))) .unwrap(); } debug!("ScriptThread: loading {} on pipeline {:?}", incomplete.url, incomplete.pipeline_id); @@ -1997,6 +1997,11 @@ impl ScriptThread { MutableOrigin::new(final_url.origin()) }; + let script_to_constellation_chan = ScriptToConstellationChan { + sender: self.script_sender.clone(), + pipeline_id: incomplete.pipeline_id, + }; + // Create the window and document objects. let window = Window::new(self.js_runtime.clone(), MainThreadScriptChan(sender.clone()), @@ -2012,7 +2017,7 @@ impl ScriptThread { self.mem_profiler_chan.clone(), self.time_profiler_chan.clone(), self.devtools_chan.clone(), - self.constellation_chan.clone(), + script_to_constellation_chan, self.control_chan.clone(), self.scheduler_chan.clone(), ipc_timer_event_chan, @@ -2082,8 +2087,8 @@ impl ScriptThread { window.init_document(&document); - self.constellation_chan - .send(ConstellationMsg::ActivateDocument(incomplete.pipeline_id)) + self.script_sender + .send((incomplete.pipeline_id, ScriptMsg::ActivateDocument)) .unwrap(); // Notify devtools that a new script global exists. @@ -2210,8 +2215,8 @@ impl ScriptThread { url.join(&value).map(|url| url.to_string()).ok() }); - let event = ConstellationMsg::NodeStatus(status); - self.constellation_chan.send(event).unwrap(); + let event = ScriptMsg::NodeStatus(status); + self.script_sender.send((pipeline_id, event)).unwrap(); state_already_changed = true; } @@ -2224,8 +2229,8 @@ impl ScriptThread { .inclusive_ancestors() .filter_map(Root::downcast::<HTMLAnchorElement>) .next() { - let event = ConstellationMsg::NodeStatus(None); - self.constellation_chan.send(event).unwrap(); + let event = ScriptMsg::NodeStatus(None); + self.script_sender.send((pipeline_id, event)).unwrap(); } } } @@ -2240,8 +2245,8 @@ impl ScriptThread { } else { EventResult::DefaultPrevented }; - let message = ConstellationMsg::TouchEventProcessed(result); - self.constellation_chan.send(message).unwrap(); + let message = ScriptMsg::TouchEventProcessed(result); + self.script_sender.send((pipeline_id, message)).unwrap(); } _ => { // TODO: Calling preventDefault on a touchup event should prevent clicks. @@ -2262,7 +2267,7 @@ impl ScriptThread { Some(document) => document, None => return warn!("Message sent to closed pipeline {}.", pipeline_id), }; - document.dispatch_key_event(ch, key, state, modifiers, &self.constellation_chan); + document.dispatch_key_event(ch, key, state, modifiers); } } } @@ -2310,8 +2315,8 @@ impl ScriptThread { } } None => { - self.constellation_chan - .send(ConstellationMsg::LoadUrl(parent_pipeline_id, load_data, replace)) + self.script_sender + .send((parent_pipeline_id, ScriptMsg::LoadUrl(load_data, replace))) .unwrap(); } } @@ -2371,7 +2376,7 @@ impl ScriptThread { let context = ParserContext::new(id, load_data.url); self.incomplete_parser_contexts.borrow_mut().push((id, context)); - self.constellation_chan.send(ConstellationMsg::InitiateNavigateRequest(req_init, id)).unwrap(); + self.script_sender.send((id, ScriptMsg::InitiateNavigateRequest(req_init))).unwrap(); self.incomplete_loads.borrow_mut().push(incomplete); } diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index a9023e3c2a3..85122d35c3c 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -45,6 +45,7 @@ use gfx_traits::Epoch; use heapsize::HeapSizeOf; use hyper::header::Headers; use hyper::method::Method; +use ipc_channel::{Error as IpcError}; use ipc_channel::ipc::{IpcReceiver, IpcSender}; use libc::c_void; use msg::constellation_msg::{BrowsingContextId, TopLevelBrowsingContextId, FrameType, Key, KeyModifiers, KeyState}; @@ -500,7 +501,7 @@ pub struct InitialScriptState { /// A port on which messages sent by the constellation to script can be received. pub control_port: IpcReceiver<ConstellationControlMsg>, /// A channel on which messages can be sent to the constellation from script. - pub constellation_chan: IpcSender<ScriptMsg>, + pub script_to_constellation_chan: ScriptToConstellationChan, /// A sender for the layout thread to communicate to the constellation. pub layout_to_constellation_chan: IpcSender<LayoutMsg>, /// A channel to schedule timer events. @@ -740,14 +741,12 @@ pub enum ConstellationMsg { /// Request that the constellation send the current focused top-level browsing context id, /// over a provided channel. GetFocusTopLevelBrowsingContext(IpcSender<Option<TopLevelBrowsingContextId>>), - /// Request to load the initial page. - InitLoadUrl(ServoUrl), /// Query the constellation to see if the current compositor output is stable IsReadyToSaveImage(HashMap<PipelineId, Epoch>), /// Inform the constellation of a key event. KeyEvent(Option<char>, Key, KeyState, KeyModifiers), /// Request to load a page. - LoadUrl(PipelineId, LoadData), + LoadUrl(TopLevelBrowsingContextId, ServoUrl), /// Request to traverse the joint session history of the provided browsing context. TraverseHistory(TopLevelBrowsingContextId, TraversalDirection), /// Inform the constellation of a window being resized. @@ -764,6 +763,10 @@ pub enum ConstellationMsg { SetWebVRThread(IpcSender<WebVRMsg>), /// Dispatch WebVR events to the subscribed script threads. WebVREvents(Vec<PipelineId>, Vec<WebVREvent>), + /// Create a new top level browsing context. + NewBrowser(ServoUrl, IpcSender<TopLevelBrowsingContextId>), + /// Make browser visible. + SelectBrowser(TopLevelBrowsingContextId), } /// Resources required by workerglobalscopes @@ -780,7 +783,7 @@ pub struct WorkerGlobalScopeInit { /// From devtools sender pub from_devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>, /// Messages to send to constellation - pub constellation_chan: IpcSender<ScriptMsg>, + pub script_to_constellation_chan: ScriptToConstellationChan, /// Message to send to the scheduler pub scheduler_chan: IpcSender<TimerSchedulerMsg>, /// The worker id @@ -843,3 +846,19 @@ pub struct DrawAPaintImageResult { /// Drawing the image might have requested loading some image URLs. pub missing_image_urls: Vec<ServoUrl>, } + +/// A Script to Constellation channel. +#[derive(Deserialize, Serialize, Clone)] +pub struct ScriptToConstellationChan { + /// Sender for communicating with constellation thread. + pub sender: IpcSender<(PipelineId, ScriptMsg)>, + /// Used to identify the origin of the message. + pub pipeline_id: PipelineId, +} + +impl ScriptToConstellationChan { + /// Send ScriptMsg and attach the pipeline_id to the message. + pub fn send(&self, msg: ScriptMsg) -> Result<(), IpcError> { + self.sender.send((self.pipeline_id, msg)) + } +} diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs index 6e19ae12b31..4fd8fca5c7f 100644 --- a/components/script_traits/script_msg.rs +++ b/components/script_traits/script_msg.rs @@ -16,7 +16,7 @@ use canvas_traits::CanvasMsg; use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId}; use euclid::{Point2D, Size2D, TypedSize2D}; use ipc_channel::ipc::IpcSender; -use msg::constellation_msg::{BrowsingContextId, TopLevelBrowsingContextId, FrameType, PipelineId, TraversalDirection}; +use msg::constellation_msg::{BrowsingContextId, FrameType, PipelineId, TraversalDirection}; use msg::constellation_msg::{Key, KeyModifiers, KeyState}; use net_traits::CoreResourceMsg; use net_traits::request::RequestInit; @@ -69,12 +69,12 @@ pub enum LogEntry { pub enum ScriptMsg { /// Requests are sent to constellation and fetches are checked manually /// for cross-origin loads - InitiateNavigateRequest(RequestInit, PipelineId), + InitiateNavigateRequest(RequestInit), /// Broadcast a storage event to every same-origin pipeline. /// The strings are key, old value and new value. - BroadcastStorageEvent(PipelineId, StorageType, ServoUrl, Option<String>, Option<String>, Option<String>), + BroadcastStorageEvent(StorageType, ServoUrl, Option<String>, Option<String>, Option<String>), /// Indicates whether this pipeline is currently running animations. - ChangeRunningAnimationsState(PipelineId, AnimationState), + ChangeRunningAnimationsState(AnimationState), /// Requests that a new 2D canvas thread be created. (This is done in the constellation because /// 2D canvases may use the GPU and we don't want to give untrusted content access to the GPU.) CreateCanvasPaintThread(Size2D<i32>, IpcSender<IpcSender<CanvasMsg>>), @@ -84,7 +84,7 @@ pub enum ScriptMsg { GLContextAttributes, IpcSender<Result<(IpcSender<CanvasMsg>, GLLimits), String>>), /// Notifies the constellation that this frame has received focus. - Focus(PipelineId), + Focus, /// Forward an event that was sent to the parent window. ForwardEvent(PipelineId, CompositorEvent), /// Requests that the constellation retrieve the current contents of the clipboard @@ -97,18 +97,18 @@ pub enum ScriptMsg { HeadParsed, /// All pending loads are complete, and the `load` event for this pipeline /// has been dispatched. - LoadComplete(PipelineId), + LoadComplete, /// A new load has been requested, with an option to replace the current entry once loaded /// instead of adding a new entry. - LoadUrl(PipelineId, LoadData, bool), + LoadUrl(LoadData, bool), /// Post a message to the currently active window of a given browsing context. PostMessage(BrowsingContextId, Option<ImmutableOrigin>, Vec<u8>), /// Dispatch a mozbrowser event to the parent of a mozbrowser iframe. - MozBrowserEvent(PipelineId, TopLevelBrowsingContextId, MozBrowserEvent), + MozBrowserEvent(PipelineId, MozBrowserEvent), /// HTMLIFrameElement Forward or Back traversal. - TraverseHistory(TopLevelBrowsingContextId, TraversalDirection), + TraverseHistory(TraversalDirection), /// Gets the length of the joint session history from the constellation. - JointSessionHistoryLength(TopLevelBrowsingContextId, IpcSender<u32>), + JointSessionHistoryLength(IpcSender<u32>), /// Favicon detected NewFavicon(ServoUrl), /// Status message to be displayed in the chrome, eg. a link URL on mouseover. @@ -117,9 +117,9 @@ pub enum ScriptMsg { /// Returns a list of pipelines which were closed. RemoveIFrame(BrowsingContextId, IpcSender<Vec<PipelineId>>), /// Change pipeline visibility - SetVisible(PipelineId, bool), + SetVisible(bool), /// Notifies constellation that an iframe's visibility has been changed. - VisibilityChangeComplete(PipelineId, bool), + VisibilityChangeComplete(bool), /// A load has been requested in an IFrame. ScriptLoadedURLInIFrame(IFrameLoadInfoWithData), /// A load of the initial `about:blank` has been completed in an IFrame. @@ -127,18 +127,18 @@ pub enum ScriptMsg { /// Requests that the constellation set the contents of the clipboard SetClipboardContents(String), /// Mark a new document as active - ActivateDocument(PipelineId), + ActivateDocument, /// Set the document state for a pipeline (used by screenshot / reftests) - SetDocumentState(PipelineId, DocumentState), + SetDocumentState(DocumentState), /// Update the pipeline Url, which can change after redirections. - SetFinalUrl(PipelineId, ServoUrl), + SetFinalUrl(ServoUrl), /// Check if an alert dialog box should be presented - Alert(PipelineId, String, IpcSender<bool>), + Alert(String, IpcSender<bool>), /// Scroll a page in a window ScrollFragmentPoint(ClipId, Point2D<f32>, bool), /// Set title of current page /// https://html.spec.whatwg.org/multipage/#document.title - SetTitle(PipelineId, Option<String>), + SetTitle(Option<String>), /// Send a key event SendKeyEvent(Option<char>, Key, KeyState, KeyModifiers), /// Get Window Informations size and position @@ -150,9 +150,9 @@ pub enum ScriptMsg { /// 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 - LogEntry(Option<TopLevelBrowsingContextId>, Option<String>, LogEntry), + LogEntry(Option<String>, LogEntry), /// Notifies the constellation that this pipeline has exited. - PipelineExited(PipelineId), + PipelineExited, /// Send messages from postMessage calls from serviceworker /// to constellation for storing in service worker manager ForwardDOMMessage(DOMMessage, ServoUrl), diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 7f968183d9b..07212a2b2d1 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -5,16 +5,16 @@ //! Servo, the mighty web browser engine from the future. //! //! This is a very simple library that wires all of Servo's components -//! together as type `Browser`, along with a generic client +//! together as type `Servo`, along with a generic client //! implementing the `WindowMethods` trait, to create a working web //! browser. //! -//! The `Browser` type is responsible for configuring a +//! The `Servo` type is responsible for configuring a //! `Constellation`, which does the heavy lifting of coordinating all //! of Servo's internal subsystems, including the `ScriptThread` and the //! `LayoutThread`, as well maintains the navigation context. //! -//! The `Browser` is fed events from a generic type that implements the +//! `Servo` is fed events from a generic type that implements the //! `WindowMethods` trait. extern crate env_logger; @@ -88,11 +88,10 @@ use profile::mem as profile_mem; use profile::time as profile_time; use profile_traits::mem; use profile_traits::time; -use script_traits::{ConstellationMsg, SWManagerSenders, ScriptMsg}; +use script_traits::{ConstellationMsg, SWManagerSenders, ScriptToConstellationChan}; use servo_config::opts; use servo_config::prefs::PREFS; use servo_config::resource_files::resources_dir_path; -use servo_url::ServoUrl; use std::borrow::Cow; use std::cmp::max; use std::path::PathBuf; @@ -104,6 +103,7 @@ use webvr::{WebVRThread, WebVRCompositorHandler}; pub use gleam::gl; pub use servo_config as config; pub use servo_url as url; +pub use msg::constellation_msg::TopLevelBrowsingContextId as BrowserId; /// The in-process interface to Servo. /// @@ -111,18 +111,18 @@ pub use servo_url as url; /// orchestrating the interaction between JavaScript, CSS layout, /// rendering, and the client window. /// -/// Clients create a `Browser` for a given reference-counted type +/// Clients create a `Servo` instance for a given reference-counted type /// implementing `WindowMethods`, which is the bridge to whatever /// application Servo is embedded in. Clients then create an event /// loop to pump messages between the embedding application and /// various browser components. -pub struct Browser<Window: WindowMethods + 'static> { +pub struct Servo<Window: WindowMethods + 'static> { compositor: IOCompositor<Window>, constellation_chan: Sender<ConstellationMsg>, } -impl<Window> Browser<Window> where Window: WindowMethods + 'static { - pub fn new(window: Rc<Window>, target_url: ServoUrl) -> Browser<Window> { +impl<Window> Servo<Window> where Window: WindowMethods + 'static { + pub fn new(window: Rc<Window>) -> Servo<Window> { // Global configuration options, parsed from the command line. let opts = opts::get(); @@ -205,7 +205,6 @@ impl<Window> Browser<Window> where Window: WindowMethods + 'static { // as the navigation context. let (constellation_chan, sw_senders) = create_constellation(opts.user_agent.clone(), opts.config_dir.clone(), - target_url, compositor_proxy.clone_compositor_proxy(), time_profiler_chan.clone(), mem_profiler_chan.clone(), @@ -238,7 +237,7 @@ impl<Window> Browser<Window> where Window: WindowMethods + 'static { webrender_api, }); - Browser { + Servo { compositor: compositor, constellation_chan: constellation_chan, } @@ -283,7 +282,6 @@ fn create_compositor_channel(event_loop_waker: Box<compositor_thread::EventLoopW fn create_constellation(user_agent: Cow<'static, str>, config_dir: Option<PathBuf>, - url: ServoUrl, compositor_proxy: CompositorProxy, time_profiler_chan: time::ProfilerChan, mem_profiler_chan: mem::ProfilerChan, @@ -335,8 +333,6 @@ fn create_constellation(user_agent: Cow<'static, str>, constellation_chan.send(ConstellationMsg::SetWebVRThread(webvr_thread)).unwrap(); } - constellation_chan.send(ConstellationMsg::InitLoadUrl(url)).unwrap(); - // channels to communicate with Service Worker Manager let sw_senders = SWManagerSenders { swmanager_sender: from_swmanager_sender, @@ -361,10 +357,10 @@ impl<Log1, Log2> Log for BothLogger<Log1, Log2> where Log1: Log, Log2: Log { } } -pub fn set_logger(constellation_chan: IpcSender<ScriptMsg>) { +pub fn set_logger(script_to_constellation_chan: ScriptToConstellationChan) { log::set_logger(|max_log_level| { let env_logger = EnvLogger::new(); - let con_logger = FromScriptLogger::new(constellation_chan); + let con_logger = FromScriptLogger::new(script_to_constellation_chan); let filter = max(env_logger.filter(), con_logger.filter()); let logger = BothLogger(env_logger, con_logger); max_log_level.set(filter); @@ -383,7 +379,7 @@ pub fn run_content_process(token: String) { let unprivileged_content = unprivileged_content_receiver.recv().unwrap(); opts::set_defaults(unprivileged_content.opts()); PREFS.extend(unprivileged_content.prefs()); - set_logger(unprivileged_content.constellation_chan()); + set_logger(unprivileged_content.script_to_constellation_chan().clone()); // Enter the sandbox if necessary. if opts::get().sandbox { diff --git a/ports/cef/browser.rs b/ports/cef/browser.rs index f403bdaa348..fbeb81bfce7 100644 --- a/ports/cef/browser.rs +++ b/ports/cef/browser.rs @@ -9,7 +9,8 @@ use interfaces::{CefBrowser, CefBrowserHost, CefClient, CefFrame, CefRequestCont use interfaces::{cef_browser_t, cef_browser_host_t, cef_client_t, cef_frame_t}; use interfaces::{cef_request_context_t}; use msg::constellation_msg::TraversalDirection; -use servo::Browser; +use servo::{BrowserId, Servo}; +use servo::ipc_channel::ipc; use servo::servo_url::ServoUrl; use types::{cef_browser_settings_t, cef_string_t, cef_window_info_t, cef_window_handle_t}; use window; @@ -29,26 +30,34 @@ thread_local!(pub static BROWSERS: RefCell<Vec<CefBrowser>> = RefCell::new(vec!( pub enum ServoBrowser { Invalid, - OnScreen(Browser<glutin_app::window::Window>), - OffScreen(Browser<window::Window>), + OnScreen(Servo<glutin_app::window::Window>, BrowserId), + OffScreen(Servo<window::Window>, BrowserId), } impl ServoBrowser { fn handle_event(&mut self, event: WindowEvent) { match *self { - ServoBrowser::OnScreen(ref mut browser) => { browser.handle_events(vec![event]); } - ServoBrowser::OffScreen(ref mut browser) => { browser.handle_events(vec![event]); } + ServoBrowser::OnScreen(ref mut browser, _) => { browser.handle_events(vec![event]); } + ServoBrowser::OffScreen(ref mut browser, _) => { browser.handle_events(vec![event]); } ServoBrowser::Invalid => {} } } pub fn pinch_zoom_level(&self) -> f32 { match *self { - ServoBrowser::OnScreen(ref browser) => browser.pinch_zoom_level(), - ServoBrowser::OffScreen(ref browser) => browser.pinch_zoom_level(), + ServoBrowser::OnScreen(ref browser, _) => browser.pinch_zoom_level(), + ServoBrowser::OffScreen(ref browser, _) => browser.pinch_zoom_level(), ServoBrowser::Invalid => 1.0, } } + + pub fn get_browser_id(&self) -> BrowserId { + match *self { + ServoBrowser::Invalid => unreachable!(), + ServoBrowser::OnScreen(_, id) => id, + ServoBrowser::OffScreen(_, id) => id, + } + } } cef_class_impl! { @@ -70,11 +79,11 @@ cef_class_impl! { }} fn go_back(&this,) -> () {{ - this.send_window_event(WindowEvent::Navigation(TraversalDirection::Back(1))); + this.send_window_event(WindowEvent::Navigation(this.get_browser_id(), TraversalDirection::Back(1))); }} fn go_forward(&this,) -> () {{ - this.send_window_event(WindowEvent::Navigation(TraversalDirection::Forward(1))); + this.send_window_event(WindowEvent::Navigation(this.get_browser_id(), TraversalDirection::Forward(1))); }} // Returns the main (top-level) frame for the browser window. @@ -124,9 +133,13 @@ impl ServoCefBrowser { let (glutin_window, servo_browser) = if window_info.windowless_rendering_enabled == 0 { let parent_window = glutin_app::WindowID::new(window_info.parent_window as *mut _); let glutin_window = glutin_app::create_window(Some(parent_window)); - let servo_browser = Browser::new(glutin_window.clone(), target_url); + let mut servo_browser = Servo::new(glutin_window.clone()); + let (sender, receiver) = ipc::channel().unwrap(); + servo_browser.handle_events(vec![WindowEvent::NewBrowser(target_url, sender)]); + let browser_id = receiver.recv().unwrap(); + servo_browser.handle_events(vec![WindowEvent::SelectBrowser(browser_id)]); window_handle = glutin_window.platform_window().window as cef_window_handle_t; - (Some(glutin_window), ServoBrowser::OnScreen(servo_browser)) + (Some(glutin_window), ServoBrowser::OnScreen(servo_browser, browser_id)) } else { (None, ServoBrowser::Invalid) }; @@ -155,6 +168,7 @@ impl ServoCefBrowser { pub trait ServoCefBrowserExtensions { fn init(&self, window_info: &cef_window_info_t); + fn get_browser_id(&self) -> BrowserId; fn send_window_event(&self, event: WindowEvent); fn pinch_zoom_level(&self) -> f32; } @@ -165,8 +179,12 @@ impl ServoCefBrowserExtensions for CefBrowser { let window = window::Window::new(window_info.width, window_info.height); window.set_browser(self.clone()); let home_url = ServoUrl::parse("about:blank").unwrap(); - let servo_browser = Browser::new(window.clone(), home_url); - *self.downcast().servo_browser.borrow_mut() = ServoBrowser::OffScreen(servo_browser); + let mut servo_browser = Servo::new(window.clone()); + let (sender, receiver) = ipc::channel().unwrap(); + servo_browser.handle_events(vec![WindowEvent::NewBrowser(home_url, sender)]); + let browser_id = receiver.recv().unwrap(); + servo_browser.handle_events(vec![WindowEvent::SelectBrowser(browser_id)]); + *self.downcast().servo_browser.borrow_mut() = ServoBrowser::OffScreen(servo_browser, browser_id); } self.downcast().host.set_browser((*self).clone()); @@ -176,6 +194,10 @@ impl ServoCefBrowserExtensions for CefBrowser { } } + fn get_browser_id(&self) -> BrowserId { + self.downcast().servo_browser.borrow().get_browser_id() + } + fn send_window_event(&self, event: WindowEvent) { let browser = self.downcast(); diff --git a/ports/cef/frame.rs b/ports/cef/frame.rs index 82f72e627cc..387d515faba 100644 --- a/ports/cef/frame.rs +++ b/ports/cef/frame.rs @@ -8,6 +8,7 @@ use interfaces::{CefBrowser, CefFrame, CefStringVisitor, cef_frame_t, cef_string use types::{cef_string_t, cef_string_userfree_t}; use compositing::windowing::WindowEvent; +use servo::servo_url::ServoUrl; use std::cell::RefCell; pub struct ServoCefFrame { @@ -34,7 +35,9 @@ full_cef_class_impl! { let this = this.downcast(); let url = String::from_utf16(url).unwrap(); *this.url.borrow_mut() = url.clone(); - let event = WindowEvent::LoadUrl(url); + let id = this.browser.borrow().as_ref().unwrap().get_browser_id(); + let url = ServoUrl::parse(&url).or(ServoUrl::parse("about:blank")).unwrap(); + let event = WindowEvent::LoadUrl(id, url); this.browser.borrow_mut().as_mut().unwrap().send_window_event(event); }} fn get_url(&this,) -> cef_string_userfree_t {{ @@ -60,7 +63,10 @@ impl ServoCefFrameExtensions for CefFrame { *self.downcast().browser.borrow_mut() = Some(browser) } fn load(&self) { - let event = WindowEvent::LoadUrl(self.downcast().url.borrow().clone()); + let id = self.downcast().browser.borrow().as_ref().unwrap().get_browser_id(); + let url = self.downcast().url.borrow(); + let url = ServoUrl::parse(&*url).or(ServoUrl::parse("about:blank")).unwrap(); + let event = WindowEvent::LoadUrl(id, url); self.downcast().browser.borrow_mut().as_mut().unwrap().send_window_event(event); } } diff --git a/ports/cef/window.rs b/ports/cef/window.rs index 4fe62cfd601..ebead54b8b4 100644 --- a/ports/cef/window.rs +++ b/ports/cef/window.rs @@ -24,6 +24,7 @@ use gleam::gl; use msg::constellation_msg::{Key, KeyModifiers}; use net_traits::net_error_list::NetError; use script_traits::LoadData; +use servo::BrowserId; use servo::ipc_channel::ipc::IpcSender; use servo_geometry::DeviceIndependentPixel; use std::cell::RefCell; @@ -233,7 +234,7 @@ impl WindowMethods for Window { } } - fn client_window(&self) -> (Size2D<u32>, Point2D<i32>) { + fn client_window(&self, _: BrowserId) -> (Size2D<u32>, Point2D<i32>) { let size = self.size().to_untyped(); let width = size.width as u32; let height = size.height as u32; @@ -241,15 +242,15 @@ impl WindowMethods for Window { (Size2D::new(width, height), Point2D::zero()) } - fn set_inner_size(&self, _size: Size2D<u32>) { + fn set_inner_size(&self, _: BrowserId, _size: Size2D<u32>) { } - fn set_position(&self, _point: Point2D<i32>) { + fn set_position(&self, _: BrowserId, _point: Point2D<i32>) { } - fn set_fullscreen_state(&self, _state: bool) { + fn set_fullscreen_state(&self, _: BrowserId, _state: bool) { } fn present(&self) { @@ -327,7 +328,7 @@ impl WindowMethods for Window { } } - fn set_favicon(&self, url: ServoUrl) { + fn set_favicon(&self, _: BrowserId, url: ServoUrl) { let browser = self.cef_browser.borrow(); let browser = match *browser { None => return, @@ -336,7 +337,7 @@ impl WindowMethods for Window { browser.downcast().favicons.borrow_mut().push(url.into_string()); } - fn status(&self, info: Option<String>) { + fn status(&self, _: BrowserId, info: Option<String>) { let browser = self.cef_browser.borrow(); let browser = match *browser { None => return, @@ -353,7 +354,7 @@ impl WindowMethods for Window { } } - fn load_start(&self) { + fn load_start(&self, _: BrowserId) { let browser = self.cef_browser.borrow(); let browser = match *browser { None => return, @@ -372,7 +373,7 @@ impl WindowMethods for Window { } } - fn load_end(&self) { + fn load_end(&self, _: BrowserId) { // FIXME(pcwalton): The status code 200 is a lie. let browser = self.cef_browser.borrow(); let browser = match *browser { @@ -398,7 +399,7 @@ impl WindowMethods for Window { } } - fn load_error(&self, code: NetError, url: String) { + fn load_error(&self, _: BrowserId, code: NetError, url: String) { let browser = self.cef_browser.borrow(); let browser = match *browser { None => return, @@ -415,7 +416,7 @@ impl WindowMethods for Window { } } - fn head_parsed(&self) { + fn head_parsed(&self, _: BrowserId) { let browser = self.cef_browser.borrow(); let browser = match *browser { None => return, @@ -427,7 +428,7 @@ impl WindowMethods for Window { } } - fn set_page_title(&self, string: Option<String>) { + fn set_page_title(&self, _: BrowserId, string: Option<String>) { let browser = self.cef_browser.borrow(); let browser = match *browser { None => return, @@ -448,7 +449,7 @@ impl WindowMethods for Window { *frame.title.borrow_mut() = str; } - fn history_changed(&self, history: Vec<LoadData>, current: usize) { + fn history_changed(&self, _: BrowserId, history: Vec<LoadData>, current: usize) { let browser = self.cef_browser.borrow(); let browser = match *browser { None => return, @@ -470,7 +471,7 @@ impl WindowMethods for Window { } } - fn handle_key(&self, _: Option<char>, _: Key, _: KeyModifiers) { + fn handle_key(&self, _: Option<BrowserId>, _: Option<char>, _: Key, _: KeyModifiers) { // TODO(negge) } @@ -491,7 +492,7 @@ impl WindowMethods for Window { } } - fn allow_navigation(&self, _: ServoUrl, response_chan: IpcSender<bool>) { + fn allow_navigation(&self, _: BrowserId, _: ServoUrl, response_chan: IpcSender<bool>) { if let Err(e) = response_chan.send(true) { warn!("Failed to send allow_navigation() response: {}", e); }; diff --git a/ports/glutin/window.rs b/ports/glutin/window.rs index 2dbd0aecd38..1e35d36b610 100644 --- a/ports/glutin/window.rs +++ b/ports/glutin/window.rs @@ -19,7 +19,7 @@ use glutin::ScanCode; use glutin::TouchPhase; #[cfg(target_os = "macos")] use glutin::os::macos::{ActivationPolicy, WindowBuilderExt}; -use msg::constellation_msg::{self, Key}; +use msg::constellation_msg::{self, Key, TopLevelBrowsingContextId as BrowserId}; use msg::constellation_msg::{ALT, CONTROL, KeyState, NONE, SHIFT, SUPER, TraversalDirection}; use net_traits::net_error_list::NetError; #[cfg(any(target_os = "linux", target_os = "macos"))] @@ -182,6 +182,10 @@ pub struct Window { mouse_down_point: Cell<Point2D<i32>>, event_queue: RefCell<Vec<WindowEvent>>, + /// id of the top level browsing context. It is unique as tabs + /// are not supported yet. None until created. + browser_id: Cell<Option<BrowserId>>, + mouse_pos: Cell<Point2D<i32>>, key_modifiers: Cell<KeyModifiers>, current_url: RefCell<Option<ServoUrl>>, @@ -217,6 +221,10 @@ fn window_creation_scale_factor() -> ScaleFactor<f32, DeviceIndependentPixel, De impl Window { + pub fn set_browser_id(&self, browser_id: BrowserId) { + self.browser_id.set(Some(browser_id)); + } + pub fn new(is_foreground: bool, window_size: TypedSize2D<u32, DeviceIndependentPixel>, parent: Option<glutin::WindowID>) -> Rc<Window> { @@ -309,6 +317,8 @@ impl Window { mouse_down_button: Cell::new(None), mouse_down_point: Cell::new(Point2D::new(0, 0)), + browser_id: Cell::new(None), + mouse_pos: Cell::new(Point2D::new(0, 0)), key_modifiers: Cell::new(KeyModifiers::empty()), current_url: RefCell::new(None), @@ -929,20 +939,22 @@ impl Window { } #[cfg(not(target_os = "win"))] - fn platform_handle_key(&self, key: Key, mods: constellation_msg::KeyModifiers) { + fn platform_handle_key(&self, key: Key, mods: constellation_msg::KeyModifiers, browser_id: BrowserId) { match (mods, key) { (CMD_OR_CONTROL, Key::LeftBracket) => { - self.event_queue.borrow_mut().push(WindowEvent::Navigation(TraversalDirection::Back(1))); + let event = WindowEvent::Navigation(browser_id, TraversalDirection::Back(1)); + self.event_queue.borrow_mut().push(event); } (CMD_OR_CONTROL, Key::RightBracket) => { - self.event_queue.borrow_mut().push(WindowEvent::Navigation(TraversalDirection::Forward(1))); + let event = WindowEvent::Navigation(browser_id, TraversalDirection::Forward(1)); + self.event_queue.borrow_mut().push(event); } _ => {} } } #[cfg(target_os = "win")] - fn platform_handle_key(&self, key: Key, mods: constellation_msg::KeyModifiers) { + fn platform_handle_key(&self, key: Key, mods: constellation_msg::KeyModifiers, browser_id: BrowserId) { } } @@ -995,7 +1007,7 @@ impl WindowMethods for Window { } } - fn client_window(&self) -> (Size2D<u32>, Point2D<i32>) { + fn client_window(&self, _: BrowserId) -> (Size2D<u32>, Point2D<i32>) { match self.kind { WindowKind::Window(ref window) => { // TODO(ajeffrey): can this fail? @@ -1018,7 +1030,7 @@ impl WindowMethods for Window { self.animation_state.set(state); } - fn set_inner_size(&self, size: Size2D<u32>) { + fn set_inner_size(&self, _: BrowserId, size: Size2D<u32>) { match self.kind { WindowKind::Window(ref window) => { window.set_inner_size(size.width as u32, size.height as u32) @@ -1027,7 +1039,7 @@ impl WindowMethods for Window { } } - fn set_position(&self, point: Point2D<i32>) { + fn set_position(&self, _: BrowserId, point: Point2D<i32>) { match self.kind { WindowKind::Window(ref window) => { window.set_position(point.x, point.y) @@ -1036,7 +1048,7 @@ impl WindowMethods for Window { } } - fn set_fullscreen_state(&self, _state: bool) { + fn set_fullscreen_state(&self, _: BrowserId, _state: bool) { match self.kind { WindowKind::Window(..) => { warn!("Fullscreen is not implemented!") @@ -1098,7 +1110,7 @@ impl WindowMethods for Window { ScaleFactor::new(ppi as f32 / 96.0) } - fn set_page_title(&self, title: Option<String>) { + fn set_page_title(&self, _: BrowserId, title: Option<String>) { match self.kind { WindowKind::Window(ref window) => { let fallback_title: String = if let Some(ref current_url) = *self.current_url.borrow() { @@ -1118,13 +1130,13 @@ impl WindowMethods for Window { } } - fn status(&self, _: Option<String>) { + fn status(&self, _: BrowserId, _: Option<String>) { } - fn load_start(&self) { + fn load_start(&self, _: BrowserId) { } - fn load_end(&self) { + fn load_end(&self, _: BrowserId) { if opts::get().no_native_titlebar { match self.kind { WindowKind::Window(ref window) => { @@ -1135,14 +1147,14 @@ impl WindowMethods for Window { } } - fn history_changed(&self, history: Vec<LoadData>, current: usize) { + fn history_changed(&self, _: BrowserId, history: Vec<LoadData>, current: usize) { *self.current_url.borrow_mut() = Some(history[current].url.clone()); } - fn load_error(&self, _: NetError, _: String) { + fn load_error(&self, _: BrowserId, _: NetError, _: String) { } - fn head_parsed(&self) { + fn head_parsed(&self, _: BrowserId) { } /// Has no effect on Android. @@ -1194,7 +1206,7 @@ impl WindowMethods for Window { } } - fn set_favicon(&self, _: ServoUrl) { + fn set_favicon(&self, _: BrowserId, _: ServoUrl) { } fn prepare_for_composite(&self, _width: usize, _height: usize) -> bool { @@ -1202,7 +1214,11 @@ impl WindowMethods for Window { } /// Helper function to handle keyboard events. - fn handle_key(&self, ch: Option<char>, key: Key, mods: constellation_msg::KeyModifiers) { + fn handle_key(&self, _: Option<BrowserId>, ch: Option<char>, key: Key, mods: constellation_msg::KeyModifiers) { + let browser_id = match self.browser_id.get() { + Some(id) => id, + None => { unreachable!("Can't get keys without a browser"); } + }; match (mods, ch, key) { (_, Some('+'), _) => { if mods & !SHIFT == CMD_OR_CONTROL { @@ -1222,10 +1238,12 @@ impl WindowMethods for Window { } (NONE, None, Key::NavigateForward) => { - self.event_queue.borrow_mut().push(WindowEvent::Navigation(TraversalDirection::Forward(1))); + let event = WindowEvent::Navigation(browser_id, TraversalDirection::Forward(1)); + self.event_queue.borrow_mut().push(event); } (NONE, None, Key::NavigateBackward) => { - self.event_queue.borrow_mut().push(WindowEvent::Navigation(TraversalDirection::Back(1))); + let event = WindowEvent::Navigation(browser_id, TraversalDirection::Back(1)); + self.event_queue.borrow_mut().push(event); } (NONE, None, Key::Escape) => { @@ -1235,10 +1253,12 @@ impl WindowMethods for Window { } (CMD_OR_ALT, None, Key::Right) => { - self.event_queue.borrow_mut().push(WindowEvent::Navigation(TraversalDirection::Forward(1))); + let event = WindowEvent::Navigation(browser_id, TraversalDirection::Forward(1)); + self.event_queue.borrow_mut().push(event); } (CMD_OR_ALT, None, Key::Left) => { - self.event_queue.borrow_mut().push(WindowEvent::Navigation(TraversalDirection::Back(1))); + let event = WindowEvent::Navigation(browser_id, TraversalDirection::Back(1)); + self.event_queue.borrow_mut().push(event); } (NONE, None, Key::PageDown) => { @@ -1284,7 +1304,7 @@ impl WindowMethods for Window { } (CMD_OR_CONTROL, Some('r'), _) => { if let Some(true) = PREFS.get("shell.builtin-key-shortcuts.enabled").as_boolean() { - self.event_queue.borrow_mut().push(WindowEvent::Reload); + self.event_queue.borrow_mut().push(WindowEvent::Reload(browser_id)); } } (CMD_OR_CONTROL, Some('q'), _) => { @@ -1297,12 +1317,12 @@ impl WindowMethods for Window { } _ => { - self.platform_handle_key(key, mods); + self.platform_handle_key(key, mods, browser_id); } } } - fn allow_navigation(&self, _: ServoUrl, response_chan: IpcSender<bool>) { + fn allow_navigation(&self, _: BrowserId, _: ServoUrl, response_chan: IpcSender<bool>) { if let Err(e) = response_chan.send(true) { warn!("Failed to send allow_navigation() response: {}", e); }; diff --git a/ports/servo/main.rs b/ports/servo/main.rs index ff99c9c5afa..2a2227486a6 100644 --- a/ports/servo/main.rs +++ b/ports/servo/main.rs @@ -4,7 +4,7 @@ //! The `servo` test application. //! -//! Creates a `Browser` instance with a simple implementation of +//! Creates a `Servo` instance with a simple implementation of //! the compositor's `WindowMethods` to create a working web browser. //! //! This browser's implementation of `WindowMethods` is built on top @@ -31,12 +31,13 @@ extern crate servo; extern crate sig; use backtrace::Backtrace; -use servo::Browser; +use servo::Servo; use servo::compositing::windowing::WindowEvent; #[cfg(target_os = "android")] use servo::config; use servo::config::opts::{self, ArgumentParsingResult, parse_url_or_filename}; use servo::config::servo_version; +use servo::ipc_channel::ipc; use servo::servo_config::prefs::PREFS; use servo::servo_url::ServoUrl; use std::env; @@ -155,20 +156,26 @@ fn main() { let target_url = cmdline_url.or(pref_url).or(blank_url).unwrap(); - // Our wrapper around `Browser` that also implements some + // Our wrapper around `ServoWrapper` that also implements some // callbacks required by the glutin window implementation. - let mut browser = BrowserWrapper { - browser: Browser::new(window.clone(), target_url) + let mut servo_wrapper = ServoWrapper { + servo: Servo::new(window.clone()) }; - browser.browser.setup_logging(); + let (sender, receiver) = ipc::channel().unwrap(); + servo_wrapper.servo.handle_events(vec![WindowEvent::NewBrowser(target_url, sender)]); + let browser_id = receiver.recv().unwrap(); + window.set_browser_id(browser_id); + servo_wrapper.servo.handle_events(vec![WindowEvent::SelectBrowser(browser_id)]); - register_glutin_resize_handler(&window, &mut browser); + servo_wrapper.servo.setup_logging(); + + register_glutin_resize_handler(&window, &mut servo_wrapper); // Feed events from the window to the browser until the browser // says to stop. loop { - let should_continue = browser.browser.handle_events(window.wait_events()); + let should_continue = servo_wrapper.servo.handle_events(window.wait_events()); if !should_continue { break; } @@ -179,7 +186,7 @@ fn main() { platform::deinit() } -fn register_glutin_resize_handler(window: &Rc<app::window::Window>, browser: &mut BrowserWrapper) { +fn register_glutin_resize_handler(window: &Rc<app::window::Window>, browser: &mut ServoWrapper) { unsafe { window.set_nested_event_loop_listener(browser); } @@ -191,21 +198,21 @@ fn unregister_glutin_resize_handler(window: &Rc<app::window::Window>) { } } -struct BrowserWrapper { - browser: Browser<app::window::Window>, +struct ServoWrapper { + servo: Servo<app::window::Window>, } -impl app::NestedEventLoopListener for BrowserWrapper { +impl app::NestedEventLoopListener for ServoWrapper { fn handle_event_from_nested_event_loop(&mut self, event: WindowEvent) -> bool { let is_resize = match event { WindowEvent::Resize(..) => true, _ => false, }; - if !self.browser.handle_events(vec![event]) { + if !self.servo.handle_events(vec![event]) { return false; } if is_resize { - self.browser.repaint_synchronously() + self.servo.repaint_synchronously() } true } |