diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2017-08-29 12:57:58 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-29 12:57:58 -0500 |
commit | ef401dd6373a393ff1d76e31e13d1827a5f0571e (patch) | |
tree | 96f245aa38371966f9bb3df0379fd680645ac4cb | |
parent | 62930d0073fbf07362b02be0bd774986c8fb94e9 (diff) | |
parent | 6bca3402a61d5a06103909b35e358e6ec745b522 (diff) | |
download | servo-ef401dd6373a393ff1d76e31e13d1827a5f0571e.tar.gz servo-ef401dd6373a393ff1d76e31e13d1827a5f0571e.zip |
Auto merge of #17269 - gterzian:remove_compositor_forwarding_code_and_use_dedicated_mechanism, r=asajeffrey
Remove compositor forwarding code and use dedicated mechanism
<!-- Please describe your changes on the following line: -->
@paulrouget Here is a first sketch of the proposed "design", handling a first message as a proof of concept, if you could please already take a look before I move all the messages(or method calls) across... thanks
---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [ ] `./mach build -d` does not report any errors
- [ ] `./mach test-tidy` does not report any errors
- [ ] These changes fix #15934 (github issue number if applicable).
<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because _____
<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->
<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/17269)
<!-- Reviewable:end -->
-rw-r--r-- | components/canvas/gl_context.rs | 2 | ||||
-rw-r--r-- | components/compositing/compositor.rs | 295 | ||||
-rw-r--r-- | components/compositing/compositor_thread.rs | 141 | ||||
-rw-r--r-- | components/compositing/lib.rs | 1 | ||||
-rw-r--r-- | components/constellation/constellation.rs | 54 | ||||
-rw-r--r-- | components/servo/lib.rs | 232 |
6 files changed, 432 insertions, 293 deletions
diff --git a/components/canvas/gl_context.rs b/components/canvas/gl_context.rs index 69a26c0e03c..ae7446e2eb5 100644 --- a/components/canvas/gl_context.rs +++ b/components/canvas/gl_context.rs @@ -27,7 +27,7 @@ impl GLContextFactory { if cfg!(target_os = "windows") { // Used to dispatch functions from the GLContext thread to the main thread's event loop. // Required to allow WGL GLContext sharing in Windows. - GLContextFactory::Native(handle, Some(MainThreadDispatcher::new(proxy.clone_compositor_proxy()))) + GLContextFactory::Native(handle, Some(MainThreadDispatcher::new(proxy.clone()))) } else { GLContextFactory::Native(handle, None) } diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 8ff38e772c3..c7d18be536f 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -11,7 +11,7 @@ use gfx_traits::Epoch; use gleam::gl; use image::{DynamicImage, ImageFormat, RgbImage}; use ipc_channel::ipc::{self, IpcSharedMemory}; -use msg::constellation_msg::{KeyState, PipelineId, PipelineIndex, PipelineNamespaceId}; +use msg::constellation_msg::{PipelineId, PipelineIndex, PipelineNamespaceId}; use net_traits::image::base::{Image, PixelFormat}; use profile_traits::time::{self, ProfilerCategory, profile}; use script_traits::{AnimationState, AnimationTickType, ConstellationControlMsg}; @@ -34,7 +34,7 @@ use touch::{TouchHandler, TouchAction}; use webrender; use webrender_api::{self, ClipId, DeviceUintRect, DeviceUintSize, LayoutPoint, LayoutVector2D}; use webrender_api::{ScrollEventPhase, ScrollLocation, ScrollClamping}; -use windowing::{self, MouseWindowEvent, WebRenderDebugOption, WindowEvent, WindowMethods}; +use windowing::{self, MouseWindowEvent, WebRenderDebugOption, WindowMethods}; #[derive(Debug, PartialEq)] enum UnableToComposite { @@ -94,7 +94,7 @@ enum LayerPixel {} /// NB: Never block on the constellation, because sometimes the constellation blocks on us. pub struct IOCompositor<Window: WindowMethods> { /// The application window. - window: Rc<Window>, + pub window: Rc<Window>, /// The port on which we receive messages. port: CompositorReceiver, @@ -137,7 +137,7 @@ pub struct IOCompositor<Window: WindowMethods> { /// Tracks whether we are in the process of shutting down, or have shut down and should close /// the compositor. - shutdown_state: ShutdownState, + pub shutdown_state: ShutdownState, /// Tracks the last composite time. last_composite_time: u64, @@ -216,7 +216,7 @@ enum CompositionRequest { } #[derive(Clone, Copy, Debug, PartialEq)] -enum ShutdownState { +pub enum ShutdownState { NotShuttingDown, ShuttingDown, FinishedShuttingDown, @@ -355,7 +355,7 @@ impl<Window: WindowMethods> IOCompositor<Window> { window_rect: window_rect, scale: ScaleFactor::new(1.0), scale_factor: scale_factor, - channel_to_self: state.sender.clone_compositor_proxy(), + channel_to_self: state.sender.clone(), composition_request: CompositionRequest::NoCompositingNecessary, touch_handler: TouchHandler::new(), pending_scroll_zoom_events: Vec::new(), @@ -386,7 +386,7 @@ impl<Window: WindowMethods> IOCompositor<Window> { let mut compositor = IOCompositor::new(window, state); let compositor_proxy_for_webrender = compositor.channel_to_self - .clone_compositor_proxy(); + .clone(); let render_notifier = RenderNotifier::new(compositor_proxy_for_webrender, compositor.constellation_chan.clone()); compositor.webrender.set_render_notifier(Box::new(render_notifier)); @@ -404,6 +404,13 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.webrender.deinit(); } + pub fn maybe_start_shutting_down(&mut self) { + if self.shutdown_state == ShutdownState::NotShuttingDown { + debug!("Shutting down the constellation for WindowEvent::Quit"); + self.start_shutting_down(); + } + } + fn start_shutting_down(&mut self) { debug!("Compositor sending Exit message to Constellation"); if let Err(e) = self.constellation_chan.send(ConstellationMsg::Exit) { @@ -450,10 +457,6 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.change_running_animations_state(pipeline_id, animation_state); } - (Msg::ChangePageTitle(top_level_browsing_context, title), ShutdownState::NotShuttingDown) => { - self.window.set_page_title(top_level_browsing_context, title); - } - (Msg::SetFrameTree(frame_tree), ShutdownState::NotShuttingDown) => { self.set_frame_tree(&frame_tree); @@ -465,67 +468,15 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.scroll_fragment_to_point(scroll_root_id, point); } - (Msg::MoveTo(top_level_browsing_context_id, point), - ShutdownState::NotShuttingDown) => { - self.window.set_position(top_level_browsing_context_id, point); - } - - (Msg::ResizeTo(top_level_browsing_context_id, size), - ShutdownState::NotShuttingDown) => { - self.window.set_inner_size(top_level_browsing_context_id, size); - } - - (Msg::GetClientWindow(top_level_browsing_context_id, send), - ShutdownState::NotShuttingDown) => { - 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(top_level_browsing_context_id, message), - ShutdownState::NotShuttingDown) => { - self.window.status(top_level_browsing_context_id, message); - } - - (Msg::LoadStart(top_level_browsing_context_id), ShutdownState::NotShuttingDown) => { - self.window.load_start(top_level_browsing_context_id); - } - - (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. - self.window.load_end(top_level_browsing_context_id); - } - - (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(top_level_browsing_context_id, ch, key, state, modified), - ShutdownState::NotShuttingDown) => { - if state == KeyState::Pressed { - self.window.handle_key(top_level_browsing_context_id, ch, key, modified); - } - } (Msg::TouchEventProcessed(result), ShutdownState::NotShuttingDown) => { self.touch_handler.on_event_processed(result); } - (Msg::SetCursor(cursor), ShutdownState::NotShuttingDown) => { - self.window.set_cursor(cursor) - } - (Msg::CreatePng(reply), ShutdownState::NotShuttingDown) => { let res = self.composite_specific_target(CompositeTarget::WindowAndPng); if let Err(ref e) = res { @@ -558,18 +509,6 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.composite_if_necessary(CompositingReason::Headless); } - (Msg::NewFavicon(top_level_browsing_context_id, url), ShutdownState::NotShuttingDown) => { - self.window.set_favicon(top_level_browsing_context_id, url); - } - - (Msg::HeadParsed(top_level_browsing_context_id), ShutdownState::NotShuttingDown) => { - self.window.head_parsed(top_level_browsing_context_id); - } - - (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) => { self.pipeline_details(pipeline_id).visible = visible; if visible { @@ -597,9 +536,12 @@ impl<Window: WindowMethods> IOCompositor<Window> { func(); } - (Msg::SetFullscreenState(top_level_browsing_context_id, state), ShutdownState::NotShuttingDown) => { - self.window.set_fullscreen_state(top_level_browsing_context_id, state); - } + (Msg::LoadComplete(_), 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); + } + }, (Msg::PendingPaintMetric(pipeline_id, epoch), _) => { self.pending_paint_metrics.insert(pipeline_id, epoch); @@ -608,7 +550,7 @@ impl<Window: WindowMethods> IOCompositor<Window> { // When we are shutting_down, we need to avoid performing operations // such as Paint that may crash because we have begun tearing down // the rest of our resources. - (_, ShutdownState::ShuttingDown) => { } + (_, ShutdownState::ShuttingDown) => {} } true @@ -717,134 +659,7 @@ impl<Window: WindowMethods> IOCompositor<Window> { ScrollClamping::ToContentBounds); } - fn handle_window_message(&mut self, event: WindowEvent) { - match event { - WindowEvent::Idle => {} - - WindowEvent::Refresh => { - self.composite(); - } - - WindowEvent::Resize(size) => { - self.on_resize_window_event(size); - } - - 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) => { - self.on_mouse_window_event_class(mouse_window_event); - } - - WindowEvent::MouseWindowMoveEventClass(cursor) => { - self.on_mouse_window_move_event_class(cursor); - } - - WindowEvent::Touch(event_type, identifier, location) => { - match event_type { - TouchEventType::Down => self.on_touch_down(identifier, location), - TouchEventType::Move => self.on_touch_move(identifier, location), - TouchEventType::Up => self.on_touch_up(identifier, location), - TouchEventType::Cancel => self.on_touch_cancel(identifier, location), - } - } - - WindowEvent::Scroll(delta, cursor, phase) => { - match phase { - TouchEventType::Move => self.on_scroll_window_event(delta, cursor), - TouchEventType::Up | TouchEventType::Cancel => { - self.on_scroll_end_window_event(delta, cursor); - } - TouchEventType::Down => { - self.on_scroll_start_window_event(delta, cursor); - } - } - } - - WindowEvent::Zoom(magnification) => { - self.on_zoom_window_event(magnification); - } - - WindowEvent::ResetZoom => { - self.on_zoom_reset_window_event(); - } - - WindowEvent::PinchZoom(magnification) => { - self.on_pinch_zoom_window_event(magnification); - } - - 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) => { - self.on_touchpad_pressure_event(cursor, pressure, stage); - } - - WindowEvent::KeyEvent(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 => { - if self.shutdown_state == ShutdownState::NotShuttingDown { - debug!("Shutting down the constellation for WindowEvent::Quit"); - self.start_shutting_down(); - } - } - - 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); - } - } - - WindowEvent::ToggleWebRenderDebug(option) => { - let mut flags = self.webrender.get_debug_flags(); - let flag = match option { - WebRenderDebugOption::Profiler => webrender::PROFILER_DBG, - WebRenderDebugOption::TextureCacheDebug => webrender::TEXTURE_CACHE_DBG, - WebRenderDebugOption::RenderTargetDebug => webrender::RENDER_TARGET_DBG, - }; - flags.toggle(flag); - 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::CloseBrowser(ctx) => { - let msg = ConstellationMsg::CloseBrowser(ctx); - if let Err(e) = self.constellation_chan.send(msg) { - warn!("Sending CloseBrowser 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); - } - } - } - } - - fn on_resize_window_event(&mut self, new_size: DeviceUintSize) { + pub fn on_resize_window_event(&mut self, new_size: DeviceUintSize) { debug!("compositor resizing to {:?}", new_size.to_untyped()); // A size change could also mean a resolution change. @@ -868,7 +683,7 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.send_window_size(WindowSizeType::Resize); } - fn on_mouse_window_event_class(&mut self, mouse_window_event: MouseWindowEvent) { + pub fn on_mouse_window_event_class(&mut self, mouse_window_event: MouseWindowEvent) { if opts::get().convert_mouse_to_touch { match mouse_window_event { MouseWindowEvent::Click(_, _) => {} @@ -914,7 +729,7 @@ impl<Window: WindowMethods> IOCompositor<Window> { } } - fn on_mouse_window_move_event_class(&mut self, cursor: TypedPoint2D<f32, DevicePixel>) { + pub fn on_mouse_window_move_event_class(&mut self, cursor: TypedPoint2D<f32, DevicePixel>) { if opts::get().convert_mouse_to_touch { self.on_touch_move(TouchId(0), cursor); return @@ -956,6 +771,18 @@ impl<Window: WindowMethods> IOCompositor<Window> { } } + pub fn on_touch_event(&mut self, + event_type: TouchEventType, + identifier: TouchId, + location: TypedPoint2D<f32, DevicePixel>) { + match event_type { + TouchEventType::Down => self.on_touch_down(identifier, location), + TouchEventType::Move => self.on_touch_move(identifier, location), + TouchEventType::Up => self.on_touch_up(identifier, location), + TouchEventType::Cancel => self.on_touch_cancel(identifier, location), + } + } + fn on_touch_down(&mut self, identifier: TouchId, point: TypedPoint2D<f32, DevicePixel>) { self.touch_handler.on_touch_down(identifier, point); let dppx = self.page_zoom * self.hidpi_factor(); @@ -1021,7 +848,7 @@ impl<Window: WindowMethods> IOCompositor<Window> { translated_point)); } - fn on_touchpad_pressure_event(&self, + pub fn on_touchpad_pressure_event(&self, point: TypedPoint2D<f32, DevicePixel>, pressure: f32, phase: TouchpadPressurePhase) { @@ -1043,6 +870,21 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.dispatch_mouse_window_event_class(MouseWindowEvent::Click(button, p)); } + pub fn on_scroll_event(&mut self, + delta: ScrollLocation, + cursor: TypedPoint2D<i32, DevicePixel>, + phase: TouchEventType) { + match phase { + TouchEventType::Move => self.on_scroll_window_event(delta, cursor), + TouchEventType::Up | TouchEventType::Cancel => { + self.on_scroll_end_window_event(delta, cursor); + } + TouchEventType::Down => { + self.on_scroll_start_window_event(delta, cursor); + } + } + } + fn on_scroll_window_event(&mut self, scroll_location: ScrollLocation, cursor: TypedPoint2D<i32, DevicePixel>) { @@ -1261,14 +1103,14 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.scale = ScaleFactor::new(scale.get()); } - fn on_zoom_reset_window_event(&mut self) { + pub fn on_zoom_reset_window_event(&mut self) { self.page_zoom = ScaleFactor::new(1.0); self.update_zoom_transform(); self.send_window_size(WindowSizeType::Resize); self.update_page_zoom_for_webrender(); } - fn on_zoom_window_event(&mut self, magnification: f32) { + pub fn on_zoom_window_event(&mut self, magnification: f32) { self.page_zoom = ScaleFactor::new((self.page_zoom.get() * magnification) .max(MIN_ZOOM).min(MAX_ZOOM)); self.update_zoom_transform(); @@ -1282,7 +1124,7 @@ impl<Window: WindowMethods> IOCompositor<Window> { } /// Simulate a pinch zoom - fn on_pinch_zoom_window_event(&mut self, magnification: f32) { + pub fn on_pinch_zoom_window_event(&mut self, magnification: f32) { self.pending_scroll_zoom_events.push(ScrollZoomEvent { magnification: magnification, scroll_location: ScrollLocation::Delta(TypedVector2D::zero()), // TODO: Scroll to keep the center in view? @@ -1385,7 +1227,7 @@ impl<Window: WindowMethods> IOCompositor<Window> { } } - fn composite(&mut self) { + pub fn composite(&mut self) { let target = self.composite_target; match self.composite_specific_target(target) { Ok(_) => if opts::get().output_file.is_some() || opts::get().exit_after_load { @@ -1580,7 +1422,7 @@ impl<Window: WindowMethods> IOCompositor<Window> { } } - pub fn handle_events(&mut self, messages: Vec<WindowEvent>) -> bool { + pub fn receive_messages(&mut self) -> bool { // Check for new messages coming from the other threads in the system. let mut compositor_messages = vec![]; let mut found_recomposite_msg = false; @@ -1596,19 +1438,17 @@ impl<Window: WindowMethods> IOCompositor<Window> { } for msg in compositor_messages { if !self.handle_browser_message(msg) { - break + return false } } + true + } + pub fn perform_updates(&mut self) -> bool { if self.shutdown_state == ShutdownState::FinishedShuttingDown { return false; } - // Handle any messages coming from the windowing system. - for message in messages { - self.handle_window_message(message); - } - // If a pinch-zoom happened recently, ask for tiles at the new resolution if self.zoom_action && precise_time_s() - self.zoom_time > 0.3 { self.zoom_action = false; @@ -1624,7 +1464,6 @@ impl<Window: WindowMethods> IOCompositor<Window> { if !self.pending_scroll_zoom_events.is_empty() && !self.waiting_for_results_of_scroll { self.process_pending_scroll_events() } - self.shutdown_state != ShutdownState::FinishedShuttingDown } @@ -1654,6 +1493,18 @@ impl<Window: WindowMethods> IOCompositor<Window> { // TODO(gw): Access via WR. 1.0 } + + pub fn toggle_webrender_debug(&mut self, option: WebRenderDebugOption) { + let mut flags = self.webrender.get_debug_flags(); + let flag = match option { + WebRenderDebugOption::Profiler => webrender::PROFILER_DBG, + WebRenderDebugOption::TextureCacheDebug => webrender::TEXTURE_CACHE_DBG, + WebRenderDebugOption::RenderTargetDebug => webrender::RENDER_TARGET_DBG, + }; + flags.toggle(flag); + self.webrender.set_debug_flags(flags); + self.webrender_api.generate_frame(self.webrender_document, None); + } } /// Why we performed a composite. This is used for debugging. diff --git a/components/compositing/compositor_thread.rs b/components/compositing/compositor_thread.rs index 08ecfef50d2..03a7b46c7c0 100644 --- a/components/compositing/compositor_thread.rs +++ b/components/compositing/compositor_thread.rs @@ -29,6 +29,45 @@ pub trait EventLoopWaker : 'static + Send { fn wake(&self); } +/// Sends messages to the embedder. +pub struct EmbedderProxy { + pub sender: Sender<EmbedderMsg>, + pub event_loop_waker: Box<EventLoopWaker>, +} + +impl EmbedderProxy { + pub fn send(&self, msg: EmbedderMsg) { + // Send a message and kick the OS event loop awake. + if let Err(err) = self.sender.send(msg) { + warn!("Failed to send response ({}).", err); + } + self.event_loop_waker.wake(); + } +} + +impl Clone for EmbedderProxy { + fn clone(&self) -> EmbedderProxy { + EmbedderProxy { + sender: self.sender.clone(), + event_loop_waker: self.event_loop_waker.clone(), + } + } +} + +/// The port that the embedder receives messages on. +pub struct EmbedderReceiver { + pub receiver: Receiver<EmbedderMsg> +} + +impl EmbedderReceiver { + pub fn try_recv_embedder_msg(&mut self) -> Option<EmbedderMsg> { + self.receiver.try_recv().ok() + } + pub fn recv_embedder_msg(&mut self) -> EmbedderMsg { + self.receiver.recv().unwrap() + } +} + /// Sends messages to the compositor. pub struct CompositorProxy { pub sender: Sender<Msg>, @@ -43,7 +82,10 @@ impl CompositorProxy { } self.event_loop_waker.wake(); } - pub fn clone_compositor_proxy(&self) -> CompositorProxy { +} + +impl Clone for CompositorProxy { + fn clone(&self) -> CompositorProxy { CompositorProxy { sender: self.sender.clone(), event_loop_waker: self.event_loop_waker.clone(), @@ -75,6 +117,37 @@ impl RenderListener for CompositorProxy { } } +pub enum EmbedderMsg { + /// A status message to be displayed by the browser chrome. + Status(TopLevelBrowsingContextId, Option<String>), + /// Alerts the embedder that the current page has changed its title. + ChangePageTitle(TopLevelBrowsingContextId, Option<String>), + /// Move the window to a point + MoveTo(TopLevelBrowsingContextId, Point2D<i32>), + /// Resize the window to size + ResizeTo(TopLevelBrowsingContextId, Size2D<u32>), + /// Get Window Informations size and position + GetClientWindow(TopLevelBrowsingContextId, IpcSender<(Size2D<u32>, Point2D<i32>)>), + /// Wether or not to follow a link + AllowNavigation(TopLevelBrowsingContextId, ServoUrl, IpcSender<bool>), + /// Sends an unconsumed key event back to the embedder. + KeyEvent(Option<TopLevelBrowsingContextId>, Option<char>, Key, KeyState, KeyModifiers), + /// Changes the cursor. + SetCursor(Cursor), + /// A favicon was detected + NewFavicon(TopLevelBrowsingContextId, ServoUrl), + /// <head> tag finished parsing + HeadParsed(TopLevelBrowsingContextId), + /// The history state has changed. + HistoryChanged(TopLevelBrowsingContextId, Vec<LoadData>, usize), + /// Enter or exit fullscreen + SetFullscreenState(TopLevelBrowsingContextId, bool), + /// The load of a page has begun + LoadStart(TopLevelBrowsingContextId), + /// The load of a page has completed + LoadComplete(TopLevelBrowsingContextId), +} + /// Messages from the painting thread and the constellation thread to the compositor thread. pub enum Msg { /// Requests that the compositor shut down. @@ -87,46 +160,20 @@ 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(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(TopLevelBrowsingContextId), - /// The load of a page has completed - LoadComplete(TopLevelBrowsingContextId), - /// The history state has changed. - HistoryChanged(TopLevelBrowsingContextId, Vec<LoadData>, usize), - /// Wether or not to follow a link - AllowNavigation(TopLevelBrowsingContextId, ServoUrl, IpcSender<bool>), /// Composite. Recomposite(CompositingReason), - /// Sends an unconsumed key event back to the compositor. - 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. - SetCursor(Cursor), /// Composite to a PNG file and return the Image over a passed channel. CreatePng(IpcSender<Option<Image>>), /// Alerts the compositor that the viewport has been constrained in some manner ViewportConstrained(PipelineId, ViewportConstraints), /// A reply to the compositor asking if the output image is stable. IsReadyToSaveImageReply(bool), - /// A favicon was detected - NewFavicon(TopLevelBrowsingContextId, ServoUrl), - /// <head> tag finished parsing - HeadParsed(TopLevelBrowsingContextId), - /// A status message to be displayed by the browser chrome. - Status(TopLevelBrowsingContextId, Option<String>), - /// Get Window Informations size and position - GetClientWindow(TopLevelBrowsingContextId, IpcSender<(Size2D<u32>, Point2D<i32>)>), - /// Move the window to a point - MoveTo(TopLevelBrowsingContextId, Point2D<i32>), - /// Resize the window to size - ResizeTo(TopLevelBrowsingContextId, Size2D<u32>), /// Pipeline visibility changed PipelineVisibilityChanged(PipelineId, bool), /// WebRender has successfully processed a scroll. The boolean specifies whether a composite is @@ -142,12 +189,12 @@ pub enum Msg { /// It's used to dispatch functions from webrender to the main thread's event loop. /// Required to allow WGL GLContext sharing in Windows. Dispatch(Box<Fn() + Send>), - /// Enter or exit fullscreen - SetFullscreenState(TopLevelBrowsingContextId, bool), /// Indicates to the compositor that it needs to record the time when the frame with /// the given ID (epoch) is painted and report it to the layout thread of the given /// pipeline ID. PendingPaintMetric(PipelineId, Epoch), + /// The load of a page has completed + LoadComplete(TopLevelBrowsingContextId), } impl Debug for Msg { @@ -157,31 +204,39 @@ impl Debug for Msg { Msg::ShutdownComplete => write!(f, "ShutdownComplete"), Msg::ScrollFragmentPoint(..) => write!(f, "ScrollFragmentPoint"), Msg::ChangeRunningAnimationsState(..) => write!(f, "ChangeRunningAnimationsState"), - Msg::ChangePageTitle(..) => write!(f, "ChangePageTitle"), Msg::SetFrameTree(..) => write!(f, "SetFrameTree"), - Msg::LoadComplete(..) => write!(f, "LoadComplete"), - Msg::AllowNavigation(..) => write!(f, "AllowNavigation"), - Msg::LoadStart(..) => write!(f, "LoadStart"), - Msg::HistoryChanged(..) => write!(f, "HistoryChanged"), Msg::Recomposite(..) => write!(f, "Recomposite"), - Msg::KeyEvent(..) => write!(f, "KeyEvent"), Msg::TouchEventProcessed(..) => write!(f, "TouchEventProcessed"), - Msg::SetCursor(..) => write!(f, "SetCursor"), Msg::CreatePng(..) => write!(f, "CreatePng"), Msg::ViewportConstrained(..) => write!(f, "ViewportConstrained"), Msg::IsReadyToSaveImageReply(..) => write!(f, "IsReadyToSaveImageReply"), - Msg::NewFavicon(..) => write!(f, "NewFavicon"), - Msg::HeadParsed(..) => write!(f, "HeadParsed"), - Msg::Status(..) => write!(f, "Status"), - Msg::GetClientWindow(..) => write!(f, "GetClientWindow"), - Msg::MoveTo(..) => write!(f, "MoveTo"), - Msg::ResizeTo(..) => write!(f, "ResizeTo"), Msg::PipelineVisibilityChanged(..) => write!(f, "PipelineVisibilityChanged"), Msg::PipelineExited(..) => write!(f, "PipelineExited"), Msg::NewScrollFrameReady(..) => write!(f, "NewScrollFrameReady"), Msg::Dispatch(..) => write!(f, "Dispatch"), - Msg::SetFullscreenState(..) => write!(f, "SetFullscreenState"), Msg::PendingPaintMetric(..) => write!(f, "PendingPaintMetric"), + Msg::LoadComplete(..) => write!(f, "LoadComplete"), + } + } +} + +impl Debug for EmbedderMsg { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + match *self { + EmbedderMsg::Status(..) => write!(f, "Status"), + EmbedderMsg::ChangePageTitle(..) => write!(f, "ChangePageTitle"), + EmbedderMsg::MoveTo(..) => write!(f, "MoveTo"), + EmbedderMsg::ResizeTo(..) => write!(f, "ResizeTo"), + EmbedderMsg::GetClientWindow(..) => write!(f, "GetClientWindow"), + EmbedderMsg::AllowNavigation(..) => write!(f, "AllowNavigation"), + EmbedderMsg::KeyEvent(..) => write!(f, "KeyEvent"), + EmbedderMsg::SetCursor(..) => write!(f, "SetCursor"), + EmbedderMsg::NewFavicon(..) => write!(f, "NewFavicon"), + EmbedderMsg::HeadParsed(..) => write!(f, "HeadParsed"), + EmbedderMsg::HistoryChanged(..) => write!(f, "HistoryChanged"), + EmbedderMsg::SetFullscreenState(..) => write!(f, "SetFullscreenState"), + EmbedderMsg::LoadStart(..) => write!(f, "LoadStart"), + EmbedderMsg::LoadComplete(..) => write!(f, "LoadComplete"), } } } diff --git a/components/compositing/lib.rs b/components/compositing/lib.rs index bb1c769eaaf..38371599678 100644 --- a/components/compositing/lib.rs +++ b/components/compositing/lib.rs @@ -26,6 +26,7 @@ extern crate webrender_api; pub use compositor_thread::CompositorProxy; pub use compositor::IOCompositor; +pub use compositor::ShutdownState; use euclid::TypedSize2D; use ipc_channel::ipc::IpcSender; use msg::constellation_msg::PipelineId; diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index ad15d1673b8..ae286fedd09 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -74,7 +74,7 @@ use canvas::webgl_thread::WebGLThreads; use canvas_traits::canvas::CanvasMsg; use clipboard::{ClipboardContext, ClipboardProvider}; use compositing::SendableFrameTree; -use compositing::compositor_thread::CompositorProxy; +use compositing::compositor_thread::{CompositorProxy, EmbedderMsg, EmbedderProxy}; use compositing::compositor_thread::Msg as ToCompositorMsg; use debugger; use devtools_traits::{ChromeToDevtoolsControlMsg, DevtoolsControlMsg}; @@ -169,6 +169,9 @@ pub struct Constellation<Message, LTF, STF> { /// A channel for the constellation to receive messages from the compositor thread. compositor_receiver: Receiver<FromCompositorMsg>, + /// A channel through which messages can be sent to the embedder. + embedder_proxy: EmbedderProxy, + /// A channel (the implementation of which is port-specific) for the /// constellation to send messages to the compositor thread. compositor_proxy: CompositorProxy, @@ -306,6 +309,9 @@ pub struct Constellation<Message, LTF, STF> { /// State needed to construct a constellation. pub struct InitialConstellationState { + /// A channel through which messages can be sent to the embedder. + pub embedder_proxy: EmbedderProxy, + /// A channel through which messages can be sent to the compositor. pub compositor_proxy: CompositorProxy, @@ -537,6 +543,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> layout_receiver: layout_receiver, network_listener_sender: network_listener_sender, network_listener_receiver: network_listener_receiver, + embedder_proxy: state.embedder_proxy, compositor_proxy: state.compositor_proxy, active_browser_id: None, debugger_chan: state.debugger_chan, @@ -692,7 +699,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> }, layout_to_constellation_chan: self.layout_sender.clone(), scheduler_chan: self.scheduler_chan.clone(), - compositor_proxy: self.compositor_proxy.clone_compositor_proxy(), + compositor_proxy: self.compositor_proxy.clone(), devtools_chan: self.devtools_chan.clone(), bluetooth_thread: self.bluetooth_thread.clone(), swmanager_thread: self.swmanager_sender.clone(), @@ -1152,13 +1159,13 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> FromScriptMsg::NewFavicon(url) => { debug!("constellation got new favicon message"); if source_is_top_level_pipeline { - self.compositor_proxy.send(ToCompositorMsg::NewFavicon(source_top_ctx_id, url)); + self.embedder_proxy.send(EmbedderMsg::NewFavicon(source_top_ctx_id, url)); } } FromScriptMsg::HeadParsed => { debug!("constellation got head parsed message"); if source_is_top_level_pipeline { - self.compositor_proxy.send(ToCompositorMsg::HeadParsed(source_top_ctx_id)); + self.embedder_proxy.send(EmbedderMsg::HeadParsed(source_top_ctx_id)); } } FromScriptMsg::CreateCanvasPaintThread(size, sender) => { @@ -1167,7 +1174,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } FromScriptMsg::NodeStatus(message) => { debug!("constellation got NodeStatus message"); - self.compositor_proxy.send(ToCompositorMsg::Status(source_top_ctx_id, message)); + self.embedder_proxy.send(EmbedderMsg::Status(source_top_ctx_id, message)); } FromScriptMsg::SetDocumentState(state) => { debug!("constellation got SetDocumentState message"); @@ -1185,15 +1192,15 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } FromScriptMsg::GetClientWindow(send) => { - self.compositor_proxy.send(ToCompositorMsg::GetClientWindow(source_top_ctx_id, send)); + self.embedder_proxy.send(EmbedderMsg::GetClientWindow(source_top_ctx_id, send)); } FromScriptMsg::MoveTo(point) => { - self.compositor_proxy.send(ToCompositorMsg::MoveTo(source_top_ctx_id, point)); + self.embedder_proxy.send(EmbedderMsg::MoveTo(source_top_ctx_id, point)); } FromScriptMsg::ResizeTo(size) => { - self.compositor_proxy.send(ToCompositorMsg::ResizeTo(source_top_ctx_id, size)); + self.embedder_proxy.send(EmbedderMsg::ResizeTo(source_top_ctx_id, size)); } FromScriptMsg::Exit => { @@ -1205,13 +1212,13 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> FromScriptMsg::SetTitle(title) => { if source_is_top_level_pipeline { - self.compositor_proxy.send(ToCompositorMsg::ChangePageTitle(source_top_ctx_id, title)) + self.embedder_proxy.send(EmbedderMsg::ChangePageTitle(source_top_ctx_id, title)) } } FromScriptMsg::SendKeyEvent(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); + let event = EmbedderMsg::KeyEvent(Some(source_top_ctx_id), ch, key, key_state, key_modifiers); + self.embedder_proxy.send(event); } FromScriptMsg::TouchEventProcessed(result) => { @@ -1244,7 +1251,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> self.handle_broadcast_storage_event(source_pipeline_id, storage, url, key, old_value, new_value); } FromScriptMsg::SetFullscreenState(state) => { - self.compositor_proxy.send(ToCompositorMsg::SetFullscreenState(source_top_ctx_id, state)); + self.embedder_proxy.send(EmbedderMsg::SetFullscreenState(source_top_ctx_id, state)); } } } @@ -1687,7 +1694,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> Some((parent_pipeline_id, frame_type)), script_sender, layout_sender, - self.compositor_proxy.clone_compositor_proxy(), + self.compositor_proxy.clone(), is_private || parent_pipeline.is_private, url.clone(), parent_pipeline.visible) @@ -1719,7 +1726,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } fn handle_set_cursor_msg(&mut self, cursor: Cursor) { - self.compositor_proxy.send(ToCompositorMsg::SetCursor(cursor)) + self.embedder_proxy.send(EmbedderMsg::SetCursor(cursor)) } fn handle_change_running_animations_state(&mut self, @@ -1793,8 +1800,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> 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!"); - let msg = ToCompositorMsg::AllowNavigation(top_level_browsing_context_id, load_data.url.clone(), chan); - self.compositor_proxy.send(msg); + let msg = EmbedderMsg::AllowNavigation(top_level_browsing_context_id, load_data.url.clone(), chan); + self.embedder_proxy.send(msg); if let Ok(false) = port.recv() { return None; } @@ -1888,7 +1895,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> 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)); + self.embedder_proxy.send(EmbedderMsg::LoadStart(top_level_browsing_context_id)); } } @@ -1920,8 +1927,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> .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. + // Notify embedder and compositor top level document finished loading. self.compositor_proxy.send(ToCompositorMsg::LoadComplete(top_level_browsing_context_id)); + self.embedder_proxy.send(EmbedderMsg::LoadComplete(top_level_browsing_context_id)); } } self.handle_subframe_loaded(pipeline_id); @@ -1989,8 +1997,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } }, None => { - let event = ToCompositorMsg::KeyEvent(None, ch, key, state, mods); - self.compositor_proxy.clone_compositor_proxy().send(event); + let event = EmbedderMsg::KeyEvent(None, ch, key, state, mods); + self.embedder_proxy.clone().send(event); } } } @@ -2169,7 +2177,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> }, WebDriverCommandMsg::SetWindowSize(top_level_browsing_context_id, size, reply) => { self.webdriver.resize_channel = Some(reply); - self.compositor_proxy.send(ToCompositorMsg::ResizeTo(top_level_browsing_context_id, size)); + self.embedder_proxy.send(EmbedderMsg::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); @@ -2402,8 +2410,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)); - let msg = ToCompositorMsg::HistoryChanged(top_level_browsing_context_id, entries, current_index); - self.compositor_proxy.send(msg); + let msg = EmbedderMsg::HistoryChanged(top_level_browsing_context_id, entries, current_index); + self.embedder_proxy.send(msg); } fn load_url_for_webdriver(&mut self, diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 35cfcef64c6..cddc84707d0 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -21,6 +21,7 @@ extern crate env_logger; #[cfg(all(not(target_os = "windows"), not(target_os = "ios")))] extern crate gaol; extern crate gleam; +#[macro_use] extern crate log; pub extern crate bluetooth; @@ -70,8 +71,9 @@ use bluetooth::BluetoothThreadFactory; use bluetooth_traits::BluetoothRequest; use canvas::gl_context::GLContextFactory; use canvas::webgl_thread::WebGLThreads; -use compositing::IOCompositor; +use compositing::{IOCompositor, ShutdownState}; use compositing::compositor_thread::{self, CompositorProxy, CompositorReceiver, InitialCompositorState}; +use compositing::compositor_thread::{EmbedderMsg, EmbedderProxy, EmbedderReceiver}; use compositing::windowing::WindowEvent; use compositing::windowing::WindowMethods; use constellation::{Constellation, InitialConstellationState, UnprivilegedPipelineContent}; @@ -84,6 +86,7 @@ use gaol::sandbox::{ChildSandbox, ChildSandboxMethods}; use gfx::font_cache_thread::FontCacheThread; use ipc_channel::ipc::{self, IpcSender}; use log::{Log, LogMetadata, LogRecord}; +use msg::constellation_msg::KeyState; use net::resource_thread::new_resource_threads; use net_traits::IpcSend; use profile::mem as profile_mem; @@ -121,6 +124,7 @@ pub use msg::constellation_msg::TopLevelBrowsingContextId as BrowserId; pub struct Servo<Window: WindowMethods + 'static> { compositor: IOCompositor<Window>, constellation_chan: Sender<ConstellationMsg>, + embedder_receiver: EmbedderReceiver } impl<Window> Servo<Window> where Window: WindowMethods + 'static { @@ -137,6 +141,8 @@ impl<Window> Servo<Window> where Window: WindowMethods + 'static { // to deliver the message. let (compositor_proxy, compositor_receiver) = create_compositor_channel(window.create_event_loop_waker()); + let (embedder_proxy, embedder_receiver) = + create_embedder_channel(window.create_event_loop_waker()); let supports_clipboard = window.supports_clipboard(); let time_profiler_chan = profile_time::Profiler::create(&opts.time_profiling, opts.time_profiler_trace_path.clone()); @@ -207,7 +213,8 @@ impl<Window> Servo<Window> where Window: WindowMethods + 'static { // as the navigation context. let (constellation_chan, sw_senders) = create_constellation(opts.user_agent.clone(), opts.config_dir.clone(), - compositor_proxy.clone_compositor_proxy(), + embedder_proxy.clone(), + compositor_proxy.clone(), time_profiler_chan.clone(), mem_profiler_chan.clone(), debugger_chan, @@ -242,11 +249,214 @@ impl<Window> Servo<Window> where Window: WindowMethods + 'static { Servo { compositor: compositor, constellation_chan: constellation_chan, + embedder_receiver: embedder_receiver, + } + } + + fn handle_window_event(&mut self, event: WindowEvent) { + match event { + WindowEvent::Idle => { + } + + WindowEvent::Refresh => { + self.compositor.composite(); + } + + WindowEvent::Resize(size) => { + self.compositor.on_resize_window_event(size); + } + + 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) => { + self.compositor.on_mouse_window_event_class(mouse_window_event); + } + + WindowEvent::MouseWindowMoveEventClass(cursor) => { + self.compositor.on_mouse_window_move_event_class(cursor); + } + + WindowEvent::Touch(event_type, identifier, location) => { + self.compositor.on_touch_event(event_type, identifier, location); + } + + WindowEvent::Scroll(delta, cursor, phase) => { + self.compositor.on_scroll_event(delta, cursor, phase); + } + + WindowEvent::Zoom(magnification) => { + self.compositor.on_zoom_window_event(magnification); + } + + WindowEvent::ResetZoom => { + self.compositor.on_zoom_reset_window_event(); + } + + WindowEvent::PinchZoom(magnification) => { + self.compositor.on_pinch_zoom_window_event(magnification); + } + + 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) => { + self.compositor.on_touchpad_pressure_event(cursor, pressure, stage); + } + + WindowEvent::KeyEvent(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 => { + self.compositor.maybe_start_shutting_down(); + } + + 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); + } + } + + WindowEvent::ToggleWebRenderDebug(option) => { + self.compositor.toggle_webrender_debug(option); + } + + 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); + } + } + + WindowEvent::CloseBrowser(ctx) => { + let msg = ConstellationMsg::CloseBrowser(ctx); + if let Err(e) = self.constellation_chan.send(msg) { + warn!("Sending CloseBrowser message to constellation failed ({}).", e); + } + } + } + } + + fn receive_messages(&mut self) { + while let Some(msg) = self.embedder_receiver.try_recv_embedder_msg() { + match (msg, self.compositor.shutdown_state) { + (_, ShutdownState::FinishedShuttingDown) => { + error!("embedder shouldn't be handling messages after compositor has shut down"); + }, + + (_, ShutdownState::ShuttingDown) => {}, + + (EmbedderMsg::Status(top_level_browsing_context, message), ShutdownState::NotShuttingDown) => { + self.compositor.window.status(top_level_browsing_context, message); + }, + + (EmbedderMsg::ChangePageTitle(top_level_browsing_context, title), ShutdownState::NotShuttingDown) => { + self.compositor.window.set_page_title(top_level_browsing_context, title); + }, + + (EmbedderMsg::MoveTo(top_level_browsing_context, point), + ShutdownState::NotShuttingDown) => { + self.compositor.window.set_position(top_level_browsing_context, point); + }, + + (EmbedderMsg::ResizeTo(top_level_browsing_context, size), + ShutdownState::NotShuttingDown) => { + self.compositor.window.set_inner_size(top_level_browsing_context, size); + }, + + (EmbedderMsg::GetClientWindow(top_level_browsing_context, send), + ShutdownState::NotShuttingDown) => { + let rect = self.compositor.window.client_window(top_level_browsing_context); + if let Err(e) = send.send(rect) { + warn!("Sending response to get client window failed ({}).", e); + } + }, + + (EmbedderMsg::AllowNavigation(top_level_browsing_context, + url, + response_chan), + ShutdownState::NotShuttingDown) => { + self.compositor.window.allow_navigation(top_level_browsing_context, url, response_chan); + }, + + (EmbedderMsg::KeyEvent(top_level_browsing_context, + ch, + key, + state, + modified), + ShutdownState::NotShuttingDown) => { + if state == KeyState::Pressed { + self.compositor.window.handle_key(top_level_browsing_context, ch, key, modified); + } + }, + + (EmbedderMsg::SetCursor(cursor), ShutdownState::NotShuttingDown) => { + self.compositor.window.set_cursor(cursor) + }, + + (EmbedderMsg::NewFavicon(top_level_browsing_context, url), ShutdownState::NotShuttingDown) => { + self.compositor.window.set_favicon(top_level_browsing_context, url); + }, + + (EmbedderMsg::HeadParsed(top_level_browsing_context, ), ShutdownState::NotShuttingDown) => { + self.compositor.window.head_parsed(top_level_browsing_context, ); + }, + + (EmbedderMsg::HistoryChanged(top_level_browsing_context, entries, current), + ShutdownState::NotShuttingDown) => { + self.compositor.window.history_changed(top_level_browsing_context, entries, current); + }, + + (EmbedderMsg::SetFullscreenState(top_level_browsing_context, state), + ShutdownState::NotShuttingDown) => { + self.compositor.window.set_fullscreen_state(top_level_browsing_context, state); + }, + + (EmbedderMsg::LoadStart(top_level_browsing_context), ShutdownState::NotShuttingDown) => { + self.compositor.window.load_start(top_level_browsing_context); + }, + + (EmbedderMsg::LoadComplete(top_level_browsing_context), ShutdownState::NotShuttingDown) => { + // Inform the embedder that the load has finished. + // + // TODO(pcwalton): Specify which frame's load completed. + self.compositor.window.load_end(top_level_browsing_context); + }, + } } } pub fn handle_events(&mut self, events: Vec<WindowEvent>) -> bool { - self.compositor.handle_events(events) + if self.compositor.receive_messages() { + self.receive_messages(); + } + for event in events { + self.handle_window_event(event); + } + if self.compositor.shutdown_state != ShutdownState::FinishedShuttingDown { + self.compositor.perform_updates(); + } + self.compositor.shutdown_state != ShutdownState::FinishedShuttingDown } pub fn repaint_synchronously(&mut self) { @@ -274,13 +484,25 @@ impl<Window> Servo<Window> where Window: WindowMethods + 'static { } } +fn create_embedder_channel(event_loop_waker: Box<compositor_thread::EventLoopWaker>) + -> (EmbedderProxy, EmbedderReceiver) { + let (sender, receiver) = channel(); + (EmbedderProxy { + sender: sender, + event_loop_waker: event_loop_waker, + }, + EmbedderReceiver { + receiver: receiver + }) +} + fn create_compositor_channel(event_loop_waker: Box<compositor_thread::EventLoopWaker>) -> (CompositorProxy, CompositorReceiver) { let (sender, receiver) = channel(); (CompositorProxy { sender: sender, event_loop_waker: event_loop_waker, - }, + }, CompositorReceiver { receiver: receiver }) @@ -288,6 +510,7 @@ fn create_compositor_channel(event_loop_waker: Box<compositor_thread::EventLoopW fn create_constellation(user_agent: Cow<'static, str>, config_dir: Option<PathBuf>, + embedder_proxy: EmbedderProxy, compositor_proxy: CompositorProxy, time_profiler_chan: time::ProfilerChan, mem_profiler_chan: mem::ProfilerChan, @@ -336,6 +559,7 @@ fn create_constellation(user_agent: Cow<'static, str>, let initial_state = InitialConstellationState { compositor_proxy, + embedder_proxy, debugger_chan, devtools_chan, bluetooth_thread, |