diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2016-03-29 12:42:01 +0530 |
---|---|---|
committer | bors-servo <lbergstrom+bors@mozilla.com> | 2016-03-29 12:42:01 +0530 |
commit | aac2da75f40f4c55a4b450b6d9d134429fcf741e (patch) | |
tree | 46b3d933d44726121af4f4079a80282b7b73018e | |
parent | ddc57fe641c3940ecdad98297ac5b2ff95c3340c (diff) | |
parent | a5a299ea881cc589511f8a03f63d53f4b39cdf66 (diff) | |
download | servo-aac2da75f40f4c55a4b450b6d9d134429fcf741e.tar.gz servo-aac2da75f40f4c55a4b450b6d9d134429fcf741e.zip |
Auto merge of #8641 - notriddle:no_headless, r=glennw
No more headless compositor. Just the normal one.
Fixes #8573
<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/8641)
<!-- Reviewable:end -->
26 files changed, 121 insertions, 474 deletions
diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index b5df18b2564..7f6c28c178e 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -525,6 +525,7 @@ impl<Window: WindowMethods> IOCompositor<Window> { (Msg::InitializeLayersForPipeline(pipeline_id, epoch, properties), ShutdownState::NotShuttingDown) => { + debug!("initializing layers for pipeline: {:?}", pipeline_id); self.pipeline_details(pipeline_id).current_epoch = epoch; self.collect_old_layers(pipeline_id, &properties); @@ -542,7 +543,7 @@ impl<Window: WindowMethods> IOCompositor<Window> { (Msg::GetNativeDisplay(chan), ShutdownState::NotShuttingDown) => { - chan.send(Some(self.native_display.clone())).unwrap(); + chan.send(self.native_display.clone()).unwrap(); } (Msg::AssignPaintedBuffers(pipeline_id, epoch, replies, frame_tree_id), @@ -641,7 +642,8 @@ impl<Window: WindowMethods> IOCompositor<Window> { reply.send(img).unwrap(); } - (Msg::PaintThreadExited(pipeline_id), ShutdownState::NotShuttingDown) => { + (Msg::PaintThreadExited(pipeline_id), _) => { + debug!("compositor learned about paint thread exiting: {:?}", pipeline_id); self.remove_pipeline_root_layer(pipeline_id); } @@ -690,8 +692,11 @@ impl<Window: WindowMethods> IOCompositor<Window> { reports_chan.send(reports); } - (Msg::PipelineExited(pipeline_id), _) => { + (Msg::PipelineExited(pipeline_id, sender), _) => { + debug!("Compositor got pipeline exited: {:?}", pipeline_id); self.pending_subpages.remove(&pipeline_id); + self.remove_pipeline_root_layer(pipeline_id); + sender.send(()).unwrap(); } // When we are shutting_down, we need to avoid performing operations diff --git a/components/compositing/compositor_thread.rs b/components/compositing/compositor_thread.rs index eb0020c366d..fdfd4c633bf 100644 --- a/components/compositing/compositor_thread.rs +++ b/components/compositing/compositor_thread.rs @@ -9,7 +9,6 @@ use compositor::{self, CompositingReason}; use euclid::point::Point2D; use euclid::size::Size2D; use gfx_traits::{Epoch, FrameTreeId, LayerId, LayerProperties, PaintListener}; -use headless; use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use layers::layers::{BufferRequest, LayerBufferSet}; use layers::platform::surface::{NativeDisplay, NativeSurface}; @@ -98,6 +97,8 @@ pub fn run_script_listener_thread(compositor_proxy: Box<CompositorProxy + 'stati ScriptToCompositorMsg::TouchEventProcessed(result) => { compositor_proxy.send(Msg::TouchEventProcessed(result)) } + + ScriptToCompositorMsg::Exited => break, } } } @@ -123,7 +124,7 @@ impl PaintListener for Box<CompositorProxy + 'static + Send> { // just return None in this case, since the paint thread // will exit shortly and never actually be requested // to paint buffers by the compositor. - port.recv().unwrap_or(None) + port.recv().ok() } fn assign_painted_buffers(&mut self, @@ -174,9 +175,7 @@ pub enum Msg { /// Requests the compositor's graphics metadata. Graphics metadata is what the painter needs /// to create surfaces that the compositor can see. On Linux this is the X display; on Mac this /// is the pixel format. - /// - /// The headless compositor returns `None`. - GetNativeDisplay(Sender<Option<NativeDisplay>>), + GetNativeDisplay(Sender<NativeDisplay>), /// Tells the compositor to create or update the layers for a pipeline if necessary /// (i.e. if no layer with that ID exists). @@ -233,7 +232,11 @@ pub enum Msg { /// Resize the window to size ResizeTo(Size2D<u32>), /// A pipeline was shut down. - PipelineExited(PipelineId), + // This message acts as a synchronization point between the constellation, + // when it shuts down a pipeline, to the compositor; when the compositor + // sends a reply on the IpcSender, the constellation knows it's safe to + // tear down the other threads associated with this pipeline. + PipelineExited(PipelineId, IpcSender<()>), } impl Debug for Msg { @@ -276,20 +279,12 @@ impl Debug for Msg { pub struct CompositorThread; impl CompositorThread { - pub fn create<Window>(window: Option<Rc<Window>>, + pub fn create<Window>(window: Rc<Window>, state: InitialCompositorState) -> Box<CompositorEventListener + 'static> where Window: WindowMethods + 'static { - match window { - Some(window) => { - box compositor::IOCompositor::create(window, state) - as Box<CompositorEventListener> - } - None => { - box headless::NullCompositor::create(state) - as Box<CompositorEventListener> - } - } + box compositor::IOCompositor::create(window, state) + as Box<CompositorEventListener> } } diff --git a/components/compositing/constellation.rs b/components/compositing/constellation.rs index f1876e660c7..159477e34cb 100644 --- a/components/compositing/constellation.rs +++ b/components/compositing/constellation.rs @@ -648,8 +648,13 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF> } // Update pipeline url after redirections Request::Script(FromScriptMsg::SetFinalUrl(pipeline_id, final_url)) => { - debug!("constellation got set final url message"); - self.mut_pipeline(pipeline_id).url = 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) { + debug!("constellation got set final url message"); + pipeline.url = final_url; + } else { + debug!("constellation got set final url message for dead pipeline"); + } } Request::Script(FromScriptMsg::MozBrowserEvent(pipeline_id, subpage_id, @@ -693,9 +698,12 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF> } } } - Request::Script(FromScriptMsg::RemoveIFrame(pipeline_id)) => { + Request::Script(FromScriptMsg::RemoveIFrame(pipeline_id, sender)) => { debug!("constellation got remove iframe message"); self.handle_remove_iframe_msg(pipeline_id); + if let Some(sender) = sender { + sender.send(()).unwrap(); + } } Request::Script(FromScriptMsg::NewFavicon(url)) => { debug!("constellation got new favicon message"); diff --git a/components/compositing/headless.rs b/components/compositing/headless.rs deleted file mode 100644 index c46bdd52262..00000000000 --- a/components/compositing/headless.rs +++ /dev/null @@ -1,147 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * 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 AnimationTickType; -use CompositorMsg as ConstellationMsg; -use compositor_thread::{CompositorEventListener, CompositorReceiver}; -use compositor_thread::{InitialCompositorState, Msg}; -use euclid::scale_factor::ScaleFactor; -use euclid::{Point2D, Size2D}; -use msg::constellation_msg::WindowSizeData; -use profile_traits::mem; -use profile_traits::time; -use script_traits::AnimationState; -use std::sync::mpsc::Sender; -use util::opts; -use windowing::WindowEvent; - -/// Starts the compositor, which listens for messages on the specified port. -/// -/// This is the null compositor which doesn't draw anything to the screen. -/// It's intended for headless testing. -pub struct NullCompositor { - /// The port on which we receive messages. - pub port: Box<CompositorReceiver>, - /// A channel to the constellation. - constellation_chan: Sender<ConstellationMsg>, - /// A channel to the time profiler. - time_profiler_chan: time::ProfilerChan, - /// A channel to the memory profiler. - mem_profiler_chan: mem::ProfilerChan, -} - -impl NullCompositor { - fn new(state: InitialCompositorState) -> NullCompositor { - NullCompositor { - port: state.receiver, - constellation_chan: state.constellation_chan, - time_profiler_chan: state.time_profiler_chan, - mem_profiler_chan: state.mem_profiler_chan, - } - } - - pub fn create(state: InitialCompositorState) -> NullCompositor { - let compositor = NullCompositor::new(state); - - // Tell the constellation about the initial fake size. - { - compositor.constellation_chan.send(ConstellationMsg::ResizedWindow(WindowSizeData { - initial_viewport: Size2D::typed(800_f32, 600_f32), - visible_viewport: Size2D::typed(800_f32, 600_f32), - device_pixel_ratio: - ScaleFactor::new(opts::get().device_pixels_per_px.unwrap_or(1.0)), - })).unwrap(); - } - - compositor - } -} - -impl CompositorEventListener for NullCompositor { - fn handle_events(&mut self, _: Vec<WindowEvent>) -> bool { - match self.port.recv_compositor_msg() { - Msg::Exit(chan) => { - debug!("shutting down the constellation"); - self.constellation_chan.send(ConstellationMsg::Exit).unwrap(); - chan.send(()).unwrap(); - } - - Msg::ShutdownComplete => { - debug!("constellation completed shutdown"); - - // Drain compositor port, sometimes messages contain channels that are blocking - // another thread from finishing (i.e. SetIds) - while self.port.try_recv_compositor_msg().is_some() {} - - self.time_profiler_chan.send(time::ProfilerMsg::Exit); - self.mem_profiler_chan.send(mem::ProfilerMsg::Exit); - - return false - } - - Msg::GetNativeDisplay(chan) => { - chan.send(None).unwrap(); - } - - Msg::SetFrameTree(_, response_chan, _) => { - response_chan.send(()).unwrap(); - } - - Msg::GetClientWindow(send) => { - let rect = (Size2D::zero(), Point2D::zero()); - send.send(rect).unwrap(); - } - - Msg::ChangeRunningAnimationsState(pipeline_id, animation_state) => { - match animation_state { - AnimationState::AnimationsPresent | - AnimationState::NoAnimationsPresent | - AnimationState::NoAnimationCallbacksPresent => {} - AnimationState::AnimationCallbacksPresent => { - let msg = ConstellationMsg::TickAnimation(pipeline_id, AnimationTickType::Script); - self.constellation_chan.send(msg).unwrap() - } - } - } - - // Explicitly list ignored messages so that when we add a new one, - // we'll notice and think about whether it needs a response, like - // SetFrameTree. - - Msg::InitializeLayersForPipeline(..) | - Msg::AssignPaintedBuffers(..) | - Msg::ScrollFragmentPoint(..) | - Msg::Status(..) | - Msg::LoadStart(..) | - Msg::LoadComplete(..) | - Msg::DelayedCompositionTimeout(..) | - Msg::Recomposite(..) | - Msg::ChangePageTitle(..) | - Msg::ChangePageUrl(..) | - Msg::KeyEvent(..) | - Msg::TouchEventProcessed(..) | - Msg::SetCursor(..) | - Msg::ViewportConstrained(..) => {} - Msg::CreatePng(..) | - Msg::PaintThreadExited(..) | - Msg::MoveTo(..) | - Msg::ResizeTo(..) | - Msg::IsReadyToSaveImageReply(..) => {} - Msg::NewFavicon(..) => {} - Msg::HeadParsed => {} - Msg::ReturnUnusedNativeSurfaces(..) => {} - Msg::CollectMemoryReports(..) => {} - Msg::PipelineExited(..) => {} - } - true - } - - fn repaint_synchronously(&mut self) {} - - fn pinch_zoom_level(&self) -> f32 { - 1.0 - } - - fn title_for_main_frame(&self) {} -} diff --git a/components/compositing/lib.rs b/components/compositing/lib.rs index c5fc7537e0a..d72c2bace6c 100644 --- a/components/compositing/lib.rs +++ b/components/compositing/lib.rs @@ -68,7 +68,6 @@ mod compositor_layer; pub mod compositor_thread; pub mod constellation; mod delayed_composition; -mod headless; pub mod pipeline; #[cfg(not(target_os = "windows"))] pub mod sandboxing; diff --git a/components/compositing/pipeline.rs b/components/compositing/pipeline.rs index bbf892048c8..40b1a2baa6a 100644 --- a/components/compositing/pipeline.rs +++ b/components/compositing/pipeline.rs @@ -28,13 +28,13 @@ use script_traits::{LayoutControlMsg, LayoutMsg, NewLayoutInfo, ScriptMsg}; use script_traits::{ScriptToCompositorMsg, ScriptThreadFactory, TimerEventRequest}; use std::mem; use std::sync::mpsc::{Receiver, Sender, channel}; -use std::thread; use url::Url; use util; use util::geometry::{PagePx, ViewportPx}; use util::ipc::OptionalIpcSender; use util::opts::{self, Opts}; use util::prefs; +use util::thread; use webrender_traits; /// A uniquely-identifiable pipeline of script thread, layout thread, and paint thread. @@ -290,6 +290,13 @@ impl Pipeline { pub fn exit(&self) { debug!("pipeline {:?} exiting", self.id); + // The compositor wants to know when pipelines shut down too. + // It may still have messages to process from these other threads + // before they can be safely shut down. + let (sender, receiver) = ipc::channel().unwrap(); + self.compositor_proxy.send(CompositorMsg::PipelineExited(self.id, sender)); + receiver.recv().unwrap(); + // Script thread handles shutting down layout, and layout handles shutting down the painter. // For now, if the script thread has failed, we give up on clean shutdown. if self.script_chan @@ -300,9 +307,6 @@ impl Pipeline { let _ = self.paint_shutdown_port.recv(); let _ = self.layout_shutdown_port.recv(); } - - // The compositor wants to know when pipelines shut down too. - self.compositor_proxy.send(CompositorMsg::PipelineExited(self.id)) } pub fn freeze(&self) { @@ -472,7 +476,7 @@ impl PrivilegedPipelineContent { let compositor_proxy_for_script_listener_thread = self.compositor_proxy.clone_compositor_proxy(); let script_to_compositor_port = self.script_to_compositor_port; - thread::spawn(move || { + thread::spawn_named("CompositorScriptListener".to_owned(), move || { compositor_thread::run_script_listener_thread( compositor_proxy_for_script_listener_thread, script_to_compositor_port) diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index 02eda99b521..8719db56a03 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -15,7 +15,6 @@ use msg::constellation_msg::{Key, KeyModifiers, KeyState}; use net_traits::net_error_list::NetError; use script_traits::{MouseButton, TouchEventType, TouchId}; use std::fmt::{Debug, Error, Formatter}; -use std::rc::Rc; use style_traits::cursor::Cursor; use url::Url; use util::geometry::ScreenPx; @@ -142,7 +141,7 @@ pub trait WindowMethods { /// /// This is part of the windowing system because its implementation often involves OS-specific /// magic to wake the up window's event loop. - fn create_compositor_channel(_: &Option<Rc<Self>>) + fn create_compositor_channel(&self) -> (Box<CompositorProxy + Send>, Box<CompositorReceiver>); /// Requests that the window system prepare a composite. Typically this will involve making diff --git a/components/gfx/paint_thread.rs b/components/gfx/paint_thread.rs index 3f945c3898c..50afd79bd58 100644 --- a/components/gfx/paint_thread.rs +++ b/components/gfx/paint_thread.rs @@ -342,7 +342,7 @@ pub enum Msg { #[derive(Deserialize, Serialize)] pub enum LayoutToPaintMsg { PaintInit(Epoch, Arc<DisplayList>), - Exit(IpcSender<()>), + Exit, } pub enum ChromeToPaintMsg { @@ -505,21 +505,20 @@ impl<C> PaintThread<C> where C: PaintListener + Send + 'static { // FIXME(njn): should eventually measure the paint thread. channel.send(Vec::new()) } - Msg::FromLayout(LayoutToPaintMsg::Exit(ref response_channel)) => { + Msg::FromLayout(LayoutToPaintMsg::Exit) => { // Ask the compositor to remove any layers it is holding for this paint thread. // FIXME(mrobinson): This can probably move back to the constellation now. + debug!("PaintThread: Exiting."); self.compositor.notify_paint_thread_exiting(self.id); - debug!("PaintThread: Exiting."); - let _ = response_channel.send(()); break; } Msg::FromChrome(ChromeToPaintMsg::Exit) => { // Ask the compositor to remove any layers it is holding for this paint thread. // FIXME(mrobinson): This can probably move back to the constellation now. + debug!("PaintThread: Exiting."); self.compositor.notify_paint_thread_exiting(self.id); - debug!("PaintThread: Exiting."); break; } } diff --git a/components/layout/layout_thread.rs b/components/layout/layout_thread.rs index e6412348e6c..6e8ab8635f9 100644 --- a/components/layout/layout_thread.rs +++ b/components/layout/layout_thread.rs @@ -777,9 +777,7 @@ impl LayoutThread { traversal.shutdown() } - let (response_chan, response_port) = ipc::channel().unwrap(); - self.paint_chan.send(LayoutToPaintMsg::Exit(response_chan)).unwrap(); - response_port.recv().unwrap() + self.paint_chan.send(LayoutToPaintMsg::Exit).unwrap(); } fn handle_add_stylesheet<'a, 'b>(&self, diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index a4ccafd2d4c..4e7e6108785 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -28,6 +28,7 @@ use dom::node::{Node, UnbindContext, window_from_node, document_from_node}; use dom::urlhelper::UrlHelper; use dom::virtualmethods::VirtualMethods; use dom::window::{ReflowReason, Window}; +use ipc_channel::ipc; use js::jsapi::{JSAutoCompartment, JSAutoRequest, RootedValue, JSContext, MutableHandleValue}; use js::jsval::{UndefinedValue, NullValue}; use layout_interface::ReflowQueryType; @@ -559,9 +560,30 @@ impl VirtualMethods for HTMLIFrameElement { let window = window_from_node(self); let window = window.r(); + // The only reason we're waiting for the iframe to be totally + // removed is to ensure the script thread can't add iframes faster + // than the compositor can remove them. + // + // Since most of this cleanup doesn't happen on same-origin + // iframes, and since that would cause a deadlock, don't do it. let ConstellationChan(ref chan) = window.constellation_chan(); - let msg = ConstellationMsg::RemoveIFrame(pipeline_id); + let same_origin = if let Some(self_url) = self.get_url() { + let win_url = window_from_node(self).get_url(); + UrlHelper::SameOrigin(&self_url, &win_url) + } else { + false + }; + let (sender, receiver) = if same_origin { + (None, None) + } else { + let (sender, receiver) = ipc::channel().unwrap(); + (Some(sender), Some(receiver)) + }; + let msg = ConstellationMsg::RemoveIFrame(pipeline_id, sender); chan.send(msg).unwrap(); + if let Some(receiver) = receiver { + receiver.recv().unwrap() + } // Resetting the subpage id to None is required here so that // if this iframe is subsequently re-added to the document diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 9ee7fd81160..1e79620fb29 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -1060,7 +1060,7 @@ impl Window { // When all these conditions are met, notify the constellation // that this pipeline is ready to write the image (from the script thread // perspective at least). - if opts::get().output_file.is_some() && for_display { + if (opts::get().output_file.is_some() || opts::get().exit_after_load) && for_display { let document = self.Document(); // Checks if the html element has reftest-wait attribute present. diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 5876f7d16c9..c591cd955a3 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -548,6 +548,7 @@ impl ScriptThreadFactory for ScriptThread { let reporter_name = format!("script-reporter-{}", id); mem_profiler_chan.run_with_memory_reporting(|| { script_thread.start(); + let _ = script_thread.compositor.borrow_mut().send(ScriptToCompositorMsg::Exited); let _ = script_thread.content_process_shutdown_chan.send(()); }, reporter_name, channel_for_reporter, CommonScriptMsg::CollectReports); diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 6aeca4068ec..e61c83b4e6b 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -365,6 +365,8 @@ pub enum ScriptToCompositorMsg { TouchEventProcessed(EventResult), /// Requests that the compositor shut down. Exit, + /// Allow the compositor to free script-specific resources. + Exited, } /// Whether a DOM event was prevented by web content diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs index 5b6afa3db1e..7c82de027bf 100644 --- a/components/script_traits/script_msg.rs +++ b/components/script_traits/script_msg.rs @@ -74,7 +74,7 @@ pub enum ScriptMsg { /// Status message to be displayed in the chrome, eg. a link URL on mouseover. NodeStatus(Option<String>), /// Notification that this iframe should be removed. - RemoveIFrame(PipelineId), + RemoveIFrame(PipelineId, Option<IpcSender<()>>), /// A load has been requested in an IFrame. ScriptLoadedURLInIFrame(IFrameLoadInfo), /// Requests that the constellation set the contents of the clipboard diff --git a/components/servo/Cargo.toml b/components/servo/Cargo.toml index c547e09a071..6591a0bd898 100644 --- a/components/servo/Cargo.toml +++ b/components/servo/Cargo.toml @@ -60,9 +60,7 @@ git = "https://github.com/servo/webrender_traits" git = "https://github.com/servo/webrender" [features] -default = ["glutin_app", "window", "webdriver"] -window = ["glutin_app/window"] -headless = ["glutin_app/headless"] +default = ["glutin_app", "webdriver"] webdriver = ["webdriver_server"] energy-profiling = ["profile_traits/energy-profiling"] diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 6a18419d581..6ddcd58222a 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -79,7 +79,6 @@ use profile::mem as profile_mem; use profile::time as profile_time; use profile_traits::mem; use profile_traits::time; -use std::borrow::Borrow; use std::rc::Rc; use std::sync::mpsc::Sender; use util::opts; @@ -103,7 +102,7 @@ pub struct Browser { } impl Browser { - pub fn new<Window>(window: Option<Rc<Window>>) -> Browser + pub fn new<Window>(window: Rc<Window>) -> Browser where Window: WindowMethods + 'static { // Global configuration options, parsed from the command line. let opts = opts::get(); @@ -115,14 +114,8 @@ impl Browser { // messages to client may need to pump a platform-specific event loop // to deliver the message. let (compositor_proxy, compositor_receiver) = - WindowMethods::create_compositor_channel(&window); - let supports_clipboard = match window { - Some(ref win_rc) => { - let win: &Window = win_rc.borrow(); - win.supports_clipboard() - } - None => false - }; + window.create_compositor_channel(); + let supports_clipboard = window.supports_clipboard(); let time_profiler_chan = profile_time::Profiler::create(opts.time_profiler_period); let mem_profiler_chan = profile_mem::Profiler::create(opts.mem_profiler_period); let devtools_chan = opts.devtools_port.map(|port| { @@ -134,9 +127,7 @@ impl Browser { resource_path.push("shaders"); // TODO(gw): Duplicates device_pixels_per_screen_px from compositor. Tidy up! - let hidpi_factor = window.as_ref() - .map(|window| window.hidpi_factor().get()) - .unwrap_or(1.0); + let hidpi_factor = window.hidpi_factor().get(); let device_pixel_ratio = match opts.device_pixels_per_px { Some(device_pixels_per_px) => device_pixels_per_px, None => match opts.output_file { diff --git a/components/servo/main.rs b/components/servo/main.rs index 8033110e7f1..08ed645b246 100644 --- a/components/servo/main.rs +++ b/components/servo/main.rs @@ -32,21 +32,11 @@ extern crate offscreen_gl_context; // The Servo engine extern crate servo; -use gleam::gl; -use offscreen_gl_context::{GLContext, NativeGLContext}; use servo::Browser; use servo::compositing::windowing::WindowEvent; use servo::util::opts::{self, ArgumentParsingResult}; use std::rc::Rc; -#[cfg(not(target_os = "android"))] -fn load_gl_when_headless() { - gl::load_with(|addr| GLContext::<NativeGLContext>::get_proc_address(addr) as *const _); -} - -#[cfg(target_os = "android")] -fn load_gl_when_headless() {} - fn main() { // Parse the command line options and store them globally let opts_result = opts::from_cmdline_args(&*args()); @@ -69,14 +59,7 @@ fn main() { return servo::run_content_process(token) } - let window = if opts::get().headless { - // Load gl functions even when in headless mode, - // to avoid crashing with WebGL - load_gl_when_headless(); - None - } else { - Some(app::create_window(None)) - }; + let window = app::create_window(None); // Our wrapper around `Browser` that also implements some // callbacks required by the glutin window implementation. @@ -84,45 +67,32 @@ fn main() { browser: Browser::new(window.clone()), }; - maybe_register_glutin_resize_handler(&window, &mut browser); + register_glutin_resize_handler(&window, &mut browser); browser.browser.handle_events(vec![WindowEvent::InitializeCompositing]); // Feed events from the window to the browser until the browser // says to stop. loop { - let should_continue = match window { - None => browser.browser.handle_events(Vec::new()), - Some(ref window) => browser.browser.handle_events(window.wait_events()), - }; + let should_continue = browser.browser.handle_events(window.wait_events()); if !should_continue { break } }; - maybe_unregister_glutin_resize_handler(&window); + unregister_glutin_resize_handler(&window); } -fn maybe_register_glutin_resize_handler(window: &Option<Rc<app::window::Window>>, +fn register_glutin_resize_handler(window: &Rc<app::window::Window>, browser: &mut BrowserWrapper) { - match *window { - None => {} - Some(ref window) => { - unsafe { - window.set_nested_event_loop_listener(browser); - } - } + unsafe { + window.set_nested_event_loop_listener(browser); } } -fn maybe_unregister_glutin_resize_handler(window: &Option<Rc<app::window::Window>>) { - match *window { - None => {} - Some(ref window) => { - unsafe { - window.remove_nested_event_loop_listener(); - } - } +fn unregister_glutin_resize_handler(window: &Rc<app::window::Window>) { + unsafe { + window.remove_nested_event_loop_listener(); } } diff --git a/ports/cef/browser.rs b/ports/cef/browser.rs index 3adbe7451a9..39b360a3744 100644 --- a/ports/cef/browser.rs +++ b/ports/cef/browser.rs @@ -126,19 +126,15 @@ impl ServoCefBrowser { let frame = ServoCefFrame::new().as_cef_interface(); let host = ServoCefBrowserHost::new(client.clone()).as_cef_interface(); let mut window_handle: cef_window_handle_t = get_null_window_handle(); - let mut glutin_window: Option<Rc<glutin_app::window::Window>> = None; - let servo_browser = if window_info.windowless_rendering_enabled == 0 { + 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 _); - glutin_window = Some(glutin_app::create_window(Some(parent_window))); + let glutin_window = glutin_app::create_window(Some(parent_window)); let servo_browser = Browser::new(glutin_window.clone()); - window_handle = match glutin_window { - Some(ref win) => win.platform_window().window as cef_window_handle_t, - None => get_null_window_handle() - }; - ServoBrowser::OnScreen(servo_browser) + window_handle = glutin_window.platform_window().window as cef_window_handle_t; + (Some(glutin_window), ServoBrowser::OnScreen(servo_browser)) } else { - ServoBrowser::Invalid + (None, ServoBrowser::Invalid) }; let id = ID_COUNTER.with(|counter| { @@ -175,7 +171,7 @@ impl ServoCefBrowserExtensions for CefBrowser { if window_info.windowless_rendering_enabled != 0 { let window = window::Window::new(window_info.width, window_info.height); window.set_browser(self.clone()); - let servo_browser = Browser::new(Some(window.clone())); + let servo_browser = Browser::new(window.clone()); *self.downcast().servo_browser.borrow_mut() = ServoBrowser::OffScreen(servo_browser); } diff --git a/ports/cef/window.rs b/ports/cef/window.rs index 2854b4c84cb..57183164a86 100644 --- a/ports/cef/window.rs +++ b/ports/cef/window.rs @@ -297,7 +297,7 @@ impl WindowMethods for Window { NativeDisplay::new() } - fn create_compositor_channel(_: &Option<Rc<Window>>) + fn create_compositor_channel(&self) -> (Box<CompositorProxy+Send>, Box<CompositorReceiver>) { let (sender, receiver) = channel(); (box CefCompositorProxy { diff --git a/ports/glutin/Cargo.toml b/ports/glutin/Cargo.toml index 082708bacd0..c292f105a0c 100644 --- a/ports/glutin/Cargo.toml +++ b/ports/glutin/Cargo.toml @@ -7,10 +7,6 @@ authors = ["The Servo Project Developers"] name = "glutin_app" path = "lib.rs" -[features] -window = [] -headless = ["servo-glutin/headless"] - [dependencies] bitflags = "0.4" url = {version = "0.5.7", features = ["heap_size"]} diff --git a/ports/glutin/lib.rs b/ports/glutin/lib.rs index 785aefb10ea..d8c6a41ce5b 100644 --- a/ports/glutin/lib.rs +++ b/ports/glutin/lib.rs @@ -16,7 +16,7 @@ extern crate glutin; extern crate layers; extern crate msg; extern crate net_traits; -#[cfg(feature = "window")] extern crate script_traits; +extern crate script_traits; extern crate style_traits; extern crate url; extern crate util; @@ -39,7 +39,7 @@ pub trait NestedEventLoopListener { pub fn create_window(parent: Option<WindowID>) -> Rc<Window> { // Read command-line options. let opts = opts::get(); - let foreground = opts.output_file.is_none(); + let foreground = opts.output_file.is_none() && !opts.headless; let scale_factor = ScaleFactor::new(opts.device_pixels_per_px.unwrap_or(1.0)); let size = opts.initial_window_size.as_f32() * scale_factor; diff --git a/ports/glutin/window.rs b/ports/glutin/window.rs index 840d7ec34fd..c8534710797 100644 --- a/ports/glutin/window.rs +++ b/ports/glutin/window.rs @@ -6,7 +6,6 @@ use NestedEventLoopListener; use compositing::compositor_thread::{self, CompositorProxy, CompositorReceiver}; -#[cfg(feature = "window")] use compositing::windowing::{MouseWindowEvent, WindowNavigateMsg}; use compositing::windowing::{WindowEvent, WindowMethods}; use euclid::scale_factor::ScaleFactor; @@ -14,34 +13,25 @@ use euclid::size::TypedSize2D; use euclid::{Size2D, Point2D}; use gleam::gl; use glutin; -#[cfg(feature = "window")] use glutin::{Api, ElementState, Event, GlRequest, MouseButton, VirtualKeyCode, MouseScrollDelta}; use glutin::{TouchPhase}; use layers::geometry::DevicePixel; use layers::platform::surface::NativeDisplay; -#[cfg(feature = "window")] use msg::constellation_msg::{KeyState, NONE, CONTROL, SHIFT, ALT, SUPER}; use msg::constellation_msg::{self, Key}; use net_traits::net_error_list::NetError; -#[cfg(feature = "window")] use script_traits::TouchEventType; -#[cfg(feature = "window")] use std::cell::{Cell, RefCell}; use std::os::raw::c_void; -#[cfg(all(feature = "headless", target_os = "linux"))] -use std::ptr; use std::rc::Rc; use std::sync::mpsc::{channel, Sender}; use style_traits::cursor::Cursor; use url::Url; use util::geometry::ScreenPx; -#[cfg(feature = "window")] use util::opts::{self, RenderApi}; -#[cfg(feature = "window")] static mut g_nested_event_loop_listener: Option<*mut (NestedEventLoopListener + 'static)> = None; -#[cfg(feature = "window")] bitflags! { flags KeyModifiers: u8 { const LEFT_CONTROL = 1, @@ -56,25 +46,23 @@ bitflags! { } // Some shortcuts use Cmd on Mac and Control on other systems. -#[cfg(all(feature = "window", target_os = "macos"))] +#[cfg(target_os = "macos")] const CMD_OR_CONTROL: constellation_msg::KeyModifiers = SUPER; -#[cfg(all(feature = "window", not(target_os = "macos")))] +#[cfg(not(target_os = "macos"))] const CMD_OR_CONTROL: constellation_msg::KeyModifiers = CONTROL; // Some shortcuts use Cmd on Mac and Alt on other systems. -#[cfg(all(feature = "window", target_os = "macos"))] +#[cfg(target_os = "macos")] const CMD_OR_ALT: constellation_msg::KeyModifiers = SUPER; -#[cfg(all(feature = "window", not(target_os = "macos")))] +#[cfg(not(target_os = "macos"))] const CMD_OR_ALT: constellation_msg::KeyModifiers = ALT; // This should vary by zoom level and maybe actual text size (focused or under cursor) -#[cfg(feature = "window")] const LINE_HEIGHT: f32 = 38.0; const MULTISAMPLES: u16 = 16; /// The type of a window. -#[cfg(feature = "window")] pub struct Window { window: glutin::Window, @@ -87,7 +75,6 @@ pub struct Window { current_url: RefCell<Option<Url>>, } -#[cfg(feature = "window")] impl Window { pub fn new(is_foreground: bool, window_size: TypedSize2D<DevicePixel, u32>, @@ -391,7 +378,7 @@ impl Window { // When writing to a file then exiting, use event // polling so that we don't block on a GUI event // such as mouse click. - if opts::get().output_file.is_some() || opts::get().exit_after_load { + if opts::get().output_file.is_some() || opts::get().exit_after_load || opts::get().headless { while let Some(event) = self.window.poll_events().next() { close_event = self.handle_window_event(event) || close_event; } @@ -523,7 +510,7 @@ impl Window { result } - #[cfg(all(feature = "window", not(target_os = "win")))] + #[cfg(not(target_os = "win"))] fn platform_handle_key(&self, key: Key, mods: constellation_msg::KeyModifiers) { match (mods, key) { (CMD_OR_CONTROL, Key::LeftBracket) => { @@ -536,24 +523,23 @@ impl Window { } } - #[cfg(all(feature = "window", target_os = "win"))] + #[cfg(target_os = "win")] fn platform_handle_key(&self, key: Key, mods: constellation_msg::KeyModifiers) { } } // WindowProxy is not implemented for android yet -#[cfg(all(feature = "window", target_os = "android"))] -fn create_window_proxy(_: &Rc<Window>) -> Option<glutin::WindowProxy> { +#[cfg(target_os = "android")] +fn create_window_proxy(_: &Window) -> Option<glutin::WindowProxy> { None } -#[cfg(all(feature = "window", not(target_os = "android")))] -fn create_window_proxy(window: &Rc<Window>) -> Option<glutin::WindowProxy> { +#[cfg(not(target_os = "android"))] +fn create_window_proxy(window: &Window) -> Option<glutin::WindowProxy> { Some(window.window.create_window_proxy()) } -#[cfg(feature = "window")] impl WindowMethods for Window { fn framebuffer_size(&self) -> TypedSize2D<DevicePixel, u32> { let scale_factor = self.window.hidpi_factor() as u32; @@ -586,14 +572,11 @@ impl WindowMethods for Window { self.window.swap_buffers().unwrap(); } - fn create_compositor_channel(window: &Option<Rc<Window>>) + fn create_compositor_channel(&self) -> (Box<CompositorProxy + Send>, Box<CompositorReceiver>) { let (sender, receiver) = channel(); - let window_proxy = match window { - &Some(ref window) => create_window_proxy(window), - &None => None, - }; + let window_proxy = create_window_proxy(self); (box GlutinCompositorProxy { sender: sender, @@ -796,139 +779,6 @@ impl WindowMethods for Window { } } -/// The type of a window. -#[cfg(feature = "headless")] -pub struct Window { - #[allow(dead_code)] - context: glutin::HeadlessContext, - width: u32, - height: u32, -} - -#[cfg(feature = "headless")] -impl Window { - pub fn new(_is_foreground: bool, - window_size: TypedSize2D<DevicePixel, u32>, - _parent: Option<glutin::WindowID>) -> Rc<Window> { - let window_size = window_size.to_untyped(); - let headless_builder = glutin::HeadlessRendererBuilder::new(window_size.width, - window_size.height); - let headless_context = headless_builder.build().unwrap(); - unsafe { headless_context.make_current().expect("Failed to make context current!") }; - - gl::load_with(|s| headless_context.get_proc_address(s) as *const c_void); - - let window = Window { - context: headless_context, - width: window_size.width, - height: window_size.height, - }; - - Rc::new(window) - } - - pub fn wait_events(&self) -> Vec<WindowEvent> { - vec![WindowEvent::Idle] - } - - pub unsafe fn set_nested_event_loop_listener( - &self, - _listener: *mut (NestedEventLoopListener + 'static)) { - } - - pub unsafe fn remove_nested_event_loop_listener(&self) { - } -} - -#[cfg(feature = "headless")] -impl WindowMethods for Window { - fn framebuffer_size(&self) -> TypedSize2D<DevicePixel, u32> { - Size2D::typed(self.width, self.height) - } - - fn size(&self) -> TypedSize2D<ScreenPx, f32> { - Size2D::typed(self.width as f32, self.height as f32) - } - - fn present(&self) { - } - - fn set_inner_size(&self, _: Size2D<u32>) { - - } - - fn set_position(&self, _: Point2D<i32>) { - - } - - fn client_window(&self) -> (Size2D<u32>, Point2D<i32>) { - let width = self.width; - let height = self.height; - (Size2D::new(width, height), Point2D::zero()) - } - - fn create_compositor_channel(_: &Option<Rc<Window>>) - -> (Box<CompositorProxy + Send>, Box<CompositorReceiver>) { - let (sender, receiver) = channel(); - - (box GlutinCompositorProxy { - sender: sender, - window_proxy: None, - } as Box<CompositorProxy + Send>, - box receiver as Box<CompositorReceiver>) - } - - fn hidpi_factor(&self) -> ScaleFactor<ScreenPx, DevicePixel, f32> { - ScaleFactor::new(1.0) - } - - fn set_page_title(&self, _: Option<String>) { - } - - fn set_page_url(&self, _: Url) { - } - - fn load_start(&self, _: bool, _: bool) { - } - fn load_end(&self, _: bool, _: bool, _: bool) { - } - fn load_error(&self, _: NetError, _: String) { - } - fn head_parsed(&self) { - } - - fn set_cursor(&self, _: Cursor) { - } - - fn set_favicon(&self, _: Url) { - } - - fn status(&self, _: Option<String>) { - } - - fn prepare_for_composite(&self, _width: usize, _height: usize) -> bool { - true - } - - #[cfg(target_os = "linux")] - fn native_display(&self) -> NativeDisplay { - NativeDisplay::new(ptr::null_mut()) - } - - #[cfg(not(target_os = "linux"))] - fn native_display(&self) -> NativeDisplay { - NativeDisplay::new() - } - - /// Helper function to handle keyboard events. - fn handle_key(&self, _: Key, _: constellation_msg::KeyModifiers) { - } - - fn supports_clipboard(&self) -> bool { - false - } -} - struct GlutinCompositorProxy { sender: Sender<compositor_thread::Msg>, window_proxy: Option<glutin::WindowProxy>, @@ -953,7 +803,6 @@ impl CompositorProxy for GlutinCompositorProxy { } } -#[cfg(feature = "window")] fn glutin_phase_to_touch_event_type(phase: TouchPhase) -> TouchEventType { match phase { TouchPhase::Started => TouchEventType::Down, diff --git a/ports/gonk/src/main.rs b/ports/gonk/src/main.rs index d477c48f2a7..2d8cb9ca551 100644 --- a/ports/gonk/src/main.rs +++ b/ports/gonk/src/main.rs @@ -61,11 +61,7 @@ fn main() { // Parse the command line options and store them globally opts::from_cmdline_args(env::args().collect::<Vec<_>>().as_slice()); - let window = if opts::get().headless { - None - } else { - Some(window::Window::new()) - }; + let window = window::Window::new(); // Our wrapper around `Browser` that also implements some // callbacks required by the glutin window implementation. @@ -73,23 +69,15 @@ fn main() { browser: Browser::new(window.clone()), }; - match window { - None => (), - Some(ref window) => input::run_input_loop(&window.event_send) - } + input::run_input_loop(&window.event_send); browser.browser.handle_events(vec![WindowEvent::InitializeCompositing]); // Feed events from the window to the browser until the browser // says to stop. loop { - let should_continue = match window { - None => browser.browser.handle_events(vec![WindowEvent::Idle]), - Some(ref window) => { - let events = window.wait_events(); - browser.browser.handle_events(events) - } - }; + let events = window.wait_events(); + let should_continue = browser.browser.handle_events(events); if !should_continue { break } diff --git a/ports/gonk/src/window.rs b/ports/gonk/src/window.rs index fb362a73981..20394979965 100644 --- a/ports/gonk/src/window.rs +++ b/ports/gonk/src/window.rs @@ -840,12 +840,12 @@ impl WindowMethods for Window { fn handle_key(&self, _: Key, _: KeyModifiers) { } - fn create_compositor_channel(window: &Option<Rc<Window>>) + fn create_compositor_channel(&self) -> (Box<CompositorProxy + Send>, Box<CompositorReceiver>) { let (sender, receiver) = channel(); (box GonkCompositorProxy { sender: sender, - event_sender: window.as_ref().unwrap().event_send.clone(), + event_sender: self.event_send.clone(), } as Box<CompositorProxy + Send>, box receiver as Box<CompositorReceiver>) } diff --git a/python/servo/build_commands.py b/python/servo/build_commands.py index 581bbaf6821..ad8025dacdf 100644 --- a/python/servo/build_commands.py +++ b/python/servo/build_commands.py @@ -25,20 +25,6 @@ from mach.decorators import ( from servo.command_base import CommandBase, cd, call -def is_headless_build(): - return int(os.getenv('SERVO_HEADLESS', 0)) == 1 - - -def headless_supported(): - supported = sys.platform.startswith("linux") - - if not supported: - print("Headless mode (OSMesa) is not supported on your platform.") - print("Building without headless mode.") - - return supported - - def notify_linux(title, text): try: import dbus @@ -136,10 +122,6 @@ class MachCommands(CommandBase): @CommandArgument('--dev', '-d', action='store_true', help='Build in development mode') - @CommandArgument('--headless', - default=None, - action='store_true', - help='Enable headless mode (OSMesa)') @CommandArgument('--jobs', '-j', default=None, help='Number of jobs to run in parallel') @@ -161,7 +143,7 @@ class MachCommands(CommandBase): @CommandArgument('params', nargs='...', help="Command-line arguments to be passed through to Cargo") def build(self, target=None, release=False, dev=False, jobs=None, - features=None, headless=False, android=None, verbose=False, debug_mozjs=False, params=None): + features=None, android=None, verbose=False, debug_mozjs=False, params=None): if android is None: android = self.config["build"]["android"] features = features or [] @@ -212,10 +194,6 @@ class MachCommands(CommandBase): if debug_mozjs or self.config["build"]["debug-mozjs"]: features += ["script/debugmozjs"] - if (headless or is_headless_build()) and headless_supported(): - opts += ["--no-default-features"] - features += ["headless"] - if android: features += ["android_glue"] @@ -378,20 +356,14 @@ class MachCommands(CommandBase): @Command('build-tests', description='Build the Servo test suites', category='build') - @CommandArgument('--headless', - default=None, - action='store_true', - help='Enable headless mode (OSMesa)') @CommandArgument('--jobs', '-j', default=None, help='Number of jobs to run in parallel') @CommandArgument('--release', default=False, action="store_true", help="Build tests with release mode") - def build_tests(self, headless=False, jobs=None, verbose=False, release=False): + def build_tests(self, jobs=None, verbose=False, release=False): self.ensure_bootstrapped() args = ["cargo", "test", "--no-run"] - if (headless or is_headless_build()) and headless_supported(): - args += ["--no-default-features", "--features", "headless"] if release: args += ["--release"] return call( diff --git a/tests/wpt/metadata/html/semantics/scripting-1/the-template-element/definitions/template-contents-owner-test-002.html.ini b/tests/wpt/metadata/html/semantics/scripting-1/the-template-element/definitions/template-contents-owner-test-002.html.ini index e7699f55db9..0b74e26325e 100644 --- a/tests/wpt/metadata/html/semantics/scripting-1/the-template-element/definitions/template-contents-owner-test-002.html.ini +++ b/tests/wpt/metadata/html/semantics/scripting-1/the-template-element/definitions/template-contents-owner-test-002.html.ini @@ -1,5 +1,7 @@ [template-contents-owner-test-002.html] type: testharness + disabled: https://github.com/servo/servo/issues/9723 + [The template contents owner document must be different from template owner document, which has browsing context. Template element is created by createElement()] expected: FAIL |