diff options
author | Patrick Walton <pcwalton@mimiga.net> | 2013-12-12 19:36:51 -0800 |
---|---|---|
committer | Patrick Walton <pcwalton@mimiga.net> | 2013-12-13 10:43:27 -0800 |
commit | 21e8c72a7526a32733453221d4ed10ac070521dd (patch) | |
tree | 03204e5058c7b16f07a3718d240d3bacfd9a0021 /src | |
parent | 499aa97fa4424cad9585e57987665542003e2597 (diff) | |
download | servo-21e8c72a7526a32733453221d4ed10ac070521dd.tar.gz servo-21e8c72a7526a32733453221d4ed10ac070521dd.zip |
constellation: Stop using futures for frame sizes.
This will allow us to stop going to the DOM in order to handle iframe
sizing. Instead we can just store the pipeline and frame IDs of iframes
inside the flow tree itself.
Diffstat (limited to 'src')
-rw-r--r-- | src/components/main/compositing/mod.rs | 3 | ||||
-rw-r--r-- | src/components/main/compositing/run.rs | 55 | ||||
-rw-r--r-- | src/components/main/compositing/run_headless.rs | 6 | ||||
-rw-r--r-- | src/components/main/constellation.rs | 102 | ||||
-rw-r--r-- | src/components/main/layout/layout_task.rs | 26 | ||||
-rw-r--r-- | src/components/main/pipeline.rs | 46 | ||||
-rwxr-xr-x | src/components/main/servo.rc | 32 | ||||
-rw-r--r-- | src/components/msg/constellation_msg.rs | 9 | ||||
-rw-r--r-- | src/components/script/dom/htmliframeelement.rs | 14 | ||||
-rw-r--r-- | src/components/script/html/hubbub_html_parser.rs | 34 | ||||
-rw-r--r-- | src/components/script/script_task.rs | 110 | ||||
-rw-r--r-- | src/test/html/summit2.html | 1 |
12 files changed, 242 insertions, 196 deletions
diff --git a/src/components/main/compositing/mod.rs b/src/components/main/compositing/mod.rs index 56472b895d1..9cf6df5f2aa 100644 --- a/src/components/main/compositing/mod.rs +++ b/src/components/main/compositing/mod.rs @@ -148,6 +148,7 @@ pub enum Msg { pub struct CompositorTask { opts: Opts, port: Port<Msg>, + constellation_chan: ConstellationChan, profiler_chan: ProfilerChan, shutdown_chan: SharedChan<()>, } @@ -155,12 +156,14 @@ pub struct CompositorTask { impl CompositorTask { pub fn new(opts: Opts, port: Port<Msg>, + constellation_chan: ConstellationChan, profiler_chan: ProfilerChan, shutdown_chan: Chan<()>) -> CompositorTask { CompositorTask { opts: opts, port: port, + constellation_chan: constellation_chan, profiler_chan: profiler_chan, shutdown_chan: SharedChan::new(shutdown_chan), } diff --git a/src/components/main/compositing/run.rs b/src/components/main/compositing/run.rs index a498b7fc9b6..b8125665543 100644 --- a/src/components/main/compositing/run.rs +++ b/src/components/main/compositing/run.rs @@ -2,41 +2,35 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use compositing::compositor_layer::CompositorLayer; +use compositing::*; use platform::{Application, Window}; - use windowing::{ApplicationMethods, WindowEvent, WindowMethods}; use windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass}; use windowing::{ScrollWindowEvent, ZoomWindowEvent, NavigationWindowEvent, FinishedWindowEvent}; use windowing::{QuitWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent}; -use servo_msg::constellation_msg::{ConstellationChan, NavigateMsg, ResizedWindowMsg, LoadUrlMsg}; -use servo_msg::constellation_msg; - use azure::azure_hl::SourceSurfaceMethods; use azure::azure_hl; -use std::comm::Port; -use std::num::Orderable; -use std::vec; -use std::path::Path; -use std::rt::io::timer::Timer; +use extra::time::precise_time_s; use geom::matrix::identity; use geom::point::Point2D; -use geom::size::Size2D; use geom::rect::Rect; +use geom::size::Size2D; use layers::layers::{ContainerLayer, ContainerLayerKind}; use layers::rendergl; use layers::scene::Scene; use opengles::gl2; use png; -use servo_util::{time, url}; +use servo_msg::constellation_msg::{ConstellationChan, NavigateMsg, ResizedWindowMsg, LoadUrlMsg}; +use servo_msg::constellation_msg; use servo_util::time::profile; - -use extra::future::Future; -use extra::time::precise_time_s; - -use compositing::compositor_layer::CompositorLayer; - -use compositing::*; +use servo_util::{time, url}; +use std::comm::Port; +use std::num::Orderable; +use std::path::Path; +use std::rt::io::timer::Timer; +use std::vec; /// Starts the compositor, which listens for messages on the specified port. pub fn run_compositor(compositor: &CompositorTask) { @@ -63,7 +57,7 @@ pub fn run_compositor(compositor: &CompositorTask) { // The root CompositorLayer let mut compositor_layer: Option<CompositorLayer> = None; - let mut constellation_chan: Option<ConstellationChan> = None; + let mut constellation_chan: ConstellationChan = compositor.constellation_chan.clone(); // Get BufferRequests from each layer. let ask_for_tiles = || { @@ -128,7 +122,7 @@ pub fn run_compositor(compositor: &CompositorTask) { window_size.height as uint); new_constellation_chan.send(ResizedWindowMsg(window_size)); - constellation_chan = Some(new_constellation_chan); + constellation_chan = new_constellation_chan; } GetGraphicsMetadata(chan) => chan.send(Some(azure_hl::current_graphics_metadata())), @@ -252,10 +246,7 @@ pub fn run_compositor(compositor: &CompositorTask) { if window_size != new_size { debug!("osmain: window resized to {:u}x{:u}", width, height); window_size = new_size; - match constellation_chan { - Some(ref chan) => chan.send(ResizedWindowMsg(new_size)), - None => error!("Compositor: Received resize event without initialized layout chan"), - } + constellation_chan.send(ResizedWindowMsg(new_size)) } else { debug!("osmain: dropping window resize since size is still {:u}x{:u}", width, height); } @@ -267,12 +258,8 @@ pub fn run_compositor(compositor: &CompositorTask) { Some(ref layer) => layer.pipeline.id.clone(), None => fail!("Compositor: Received LoadUrlWindowEvent without initialized compositor layers"), }; - match constellation_chan { - Some(ref chan) => chan.send(LoadUrlMsg(root_pipeline_id, - url::make_url(url_string.to_str(), None), - Future::from_value(window_size))), - None => error!("Compositor: Received loadurl event without initialized layout chan"), - } + constellation_chan.send(LoadUrlMsg(root_pipeline_id, + url::make_url(url_string.to_str(), None))) } MouseWindowEventClass(mouse_window_event) => { @@ -327,10 +314,7 @@ pub fn run_compositor(compositor: &CompositorTask) { windowing::Forward => constellation_msg::Forward, windowing::Back => constellation_msg::Back, }; - match constellation_chan { - Some(ref chan) => chan.send(NavigateMsg(direction)), - None => error!("Compositor: Received navigation event without initialized layout chan"), - } + constellation_chan.send(NavigateMsg(direction)) } FinishedWindowEvent => { @@ -403,6 +387,9 @@ pub fn run_compositor(compositor: &CompositorTask) { if exit { done = true; } }; + // Tell the constellation about the initial window size. + constellation_chan.send(ResizedWindowMsg(window_size)); + // Enter the main event loop. let mut tm = Timer::new().unwrap(); while !done { diff --git a/src/components/main/compositing/run_headless.rs b/src/components/main/compositing/run_headless.rs index 29a8e1db96c..9c7b8c3482d 100644 --- a/src/components/main/compositing/run_headless.rs +++ b/src/components/main/compositing/run_headless.rs @@ -4,11 +4,17 @@ use compositing::*; +use geom::size::Size2D; +use servo_msg::constellation_msg::ResizedWindowMsg; + /// 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 fn run_compositor(compositor: &CompositorTask) { + // Tell the constellation about the initial fake size. + compositor.constellation_chan.send(ResizedWindowMsg(Size2D(640u, 480u))); + loop { match compositor.port.recv() { Exit => break, diff --git a/src/components/main/constellation.rs b/src/components/main/constellation.rs index 43ca99a62f6..bdd1b87c8d5 100644 --- a/src/components/main/constellation.rs +++ b/src/components/main/constellation.rs @@ -4,28 +4,27 @@ use compositing::{CompositorChan, SetIds, SetLayerClipRect}; -use std::comm; -use std::comm::Port; -use std::task::spawn_with; -use geom::size::Size2D; +use extra::url::Url; use geom::rect::Rect; +use geom::size::Size2D; use gfx::opts::Opts; use pipeline::Pipeline; +use script::script_task::{ResizeMsg, ResizeInactiveMsg}; use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, FailureMsg, FrameRectMsg}; -use servo_msg::constellation_msg::{IFrameSandboxState, InitLoadUrlMsg, LoadIframeUrlMsg, LoadUrlMsg}; -use servo_msg::constellation_msg::{Msg, NavigateMsg, NavigationType, IFrameUnsandboxed}; +use servo_msg::constellation_msg::{IFrameSandboxState, IFrameUnsandboxed, InitLoadUrlMsg}; +use servo_msg::constellation_msg::{LoadIframeUrlMsg, LoadUrlMsg, Msg, NavigateMsg, NavigationType}; use servo_msg::constellation_msg::{PipelineId, RendererReadyMsg, ResizedWindowMsg, SubpageId}; use servo_msg::constellation_msg; -use script::script_task::{ResizeMsg, ResizeInactiveMsg}; use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient}; use servo_net::resource_task::ResourceTask; use servo_net::resource_task; use servo_util::time::ProfilerChan; use servo_util::url::make_url; +use std::comm::Port; +use std::comm; use std::hashmap::{HashMap, HashSet}; +use std::task::spawn_with; use std::util::replace; -use extra::url::Url; -use extra::future::Future; /// Maintains the pipelines and navigation context and grants permission to composite pub struct Constellation { @@ -249,18 +248,27 @@ impl NavigationContext { } impl Constellation { - pub fn start(compositor_chan: CompositorChan, + pub fn start(constellation_port: Port<Msg>, + constellation_chan: ConstellationChan, + compositor_chan: CompositorChan, opts: &Opts, resource_task: ResourceTask, image_cache_task: ImageCacheTask, - profiler_chan: ProfilerChan) - -> ConstellationChan { - let (constellation_port, constellation_chan) = special_stream!(ConstellationChan); - do spawn_with((constellation_port, constellation_chan.clone(), - compositor_chan, resource_task, image_cache_task, - profiler_chan, opts.clone())) - |(constellation_port, constellation_chan, compositor_chan, resource_task, - image_cache_task, profiler_chan, opts)| { + profiler_chan: ProfilerChan) { + do spawn_with((constellation_port, + constellation_chan.clone(), + compositor_chan, + resource_task, + image_cache_task, + profiler_chan, + opts.clone())) + |(constellation_port, + constellation_chan, + compositor_chan, + resource_task, + image_cache_task, + profiler_chan, + opts)| { let mut constellation = Constellation { chan: constellation_chan, request_port: constellation_port, @@ -278,7 +286,6 @@ impl Constellation { }; constellation.run(); } - constellation_chan } fn run(&mut self) { @@ -324,32 +331,38 @@ impl Constellation { } // This should only be called once per constellation, and only by the browser InitLoadUrlMsg(url) => { + debug!("constellation got init load URL message"); self.handle_init_load(url); } - // A layout assigned a size and position to a subframe. This needs to be reflected by all - // frame trees in the navigation context containing the subframe. + // A layout assigned a size and position to a subframe. This needs to be reflected by + // all frame trees in the navigation context containing the subframe. FrameRectMsg(pipeline_id, subpage_id, rect) => { + debug!("constellation got frame rect message"); self.handle_frame_rect_msg(pipeline_id, subpage_id, rect); } - LoadIframeUrlMsg(url, source_pipeline_id, subpage_id, size_future, sandbox) => { - self.handle_load_iframe_url_msg(url, source_pipeline_id, subpage_id, size_future, sandbox); + LoadIframeUrlMsg(url, source_pipeline_id, subpage_id, sandbox) => { + debug!("constellation got iframe URL load message"); + self.handle_load_iframe_url_msg(url, source_pipeline_id, subpage_id, sandbox); } // Load a new page, usually -- but not always -- from a mouse click or typed url // If there is already a pending page (self.pending_frames), it will not be overridden; // However, if the id is not encompassed by another change, it will be. - LoadUrlMsg(source_id, url, size_future) => { - self.handle_load_url_msg(source_id, url, size_future); + LoadUrlMsg(source_id, url) => { + debug!("constellation got URL load message"); + self.handle_load_url_msg(source_id, url); } // Handle a forward or back request NavigateMsg(direction) => { + debug!("constellation got navigation message"); self.handle_navigate_msg(direction); } // Notification that rendering has finished and is requesting permission to paint. RendererReadyMsg(pipeline_id) => { + debug!("constellation got renderer ready message"); self.handle_renderer_ready_msg(pipeline_id); } - ResizedWindowMsg(new_size) => { + debug!("constellation got window resize message"); self.handle_resized_window_msg(new_size); } } @@ -375,8 +388,7 @@ impl Constellation { self.image_cache_task.clone(), self.resource_task.clone(), self.profiler_chan.clone(), - self.opts.clone(), - Future::from_value(self.window_size)); + self.opts.clone()); let failure = ~"about:failure"; let url = make_url(failure, None); pipeline.load(url); @@ -397,11 +409,10 @@ impl Constellation { self.image_cache_task.clone(), self.resource_task.clone(), self.profiler_chan.clone(), - self.opts.clone(), - Future::from_value(self.window_size)); + self.opts.clone()); pipeline.load(url); - self.pending_frames.push(FrameChange{ + self.pending_frames.push(FrameChange { before: None, after: @mut FrameTree { pipeline: pipeline, @@ -476,7 +487,6 @@ impl Constellation { url: Url, source_pipeline_id: PipelineId, subpage_id: SubpageId, - size_future: Future<Size2D<uint>>, sandbox: IFrameSandboxState) { // A message from the script associated with pipeline_id that it has // parsed an iframe during html parsing. This iframe will result in a @@ -524,8 +534,7 @@ impl Constellation { self.image_cache_task.clone(), self.profiler_chan.clone(), self.opts.clone(), - source_pipeline, - size_future) + source_pipeline) } else { debug!("Constellation: loading cross-origin iframe at {:?}", url); // Create a new script task if not same-origin url's @@ -536,8 +545,7 @@ impl Constellation { self.image_cache_task.clone(), self.resource_task.clone(), self.profiler_chan.clone(), - self.opts.clone(), - size_future) + self.opts.clone()) }; debug!("Constellation: sending load msg to pipeline {:?}", pipeline.id); @@ -556,7 +564,7 @@ impl Constellation { self.pipelines.insert(pipeline.id, pipeline); } - fn handle_load_url_msg(&mut self, source_id: PipelineId, url: Url, size_future: Future<Size2D<uint>>) { + fn handle_load_url_msg(&mut self, source_id: PipelineId, url: Url) { debug!("Constellation: received message to load {:s}", url.to_str()); // Make sure no pending page would be overridden. let source_frame = self.current_frame().get_ref().find(source_id).expect( @@ -590,8 +598,7 @@ impl Constellation { self.image_cache_task.clone(), self.resource_task.clone(), self.profiler_chan.clone(), - self.opts.clone(), - size_future); + self.opts.clone()); pipeline.load(url); @@ -723,13 +730,16 @@ impl Constellation { } } } - self.grant_paint_permission(next_frame_tree, frame_change.navigation_type); + + self.grant_paint_permission(next_frame_tree, frame_change.navigation_type); } } + /// Called when the window is resized. fn handle_resized_window_msg(&mut self, new_size: Size2D<uint>) { let mut already_seen = HashSet::new(); for &@FrameTree { pipeline: pipeline, _ } in self.current_frame().iter() { + debug!("constellation sending resize message to active frame"); pipeline.script_chan.send(ResizeMsg(pipeline.id, new_size)); already_seen.insert(pipeline.id); } @@ -737,10 +747,22 @@ impl Constellation { .chain(self.navigation_context.next.iter()) { let pipeline = &frame_tree.pipeline; if !already_seen.contains(&pipeline.id) { + debug!("constellation sending resize message to inactive frame"); pipeline.script_chan.send(ResizeInactiveMsg(pipeline.id, new_size)); already_seen.insert(pipeline.id); } } + + // If there are any pending outermost frames, then tell them to resize. (This is how the + // initial window size gets sent to the first page loaded, giving it permission to reflow.) + for change in self.pending_frames.iter() { + let frame_tree = change.after; + if frame_tree.parent.is_none() { + debug!("constellation sending resize message to pending outer frame"); + frame_tree.pipeline.script_chan.send(ResizeMsg(frame_tree.pipeline.id, new_size)) + } + } + self.window_size = new_size; } diff --git a/src/components/main/layout/layout_task.rs b/src/components/main/layout/layout_task.rs index 3519a782607..ec82722afa0 100644 --- a/src/components/main/layout/layout_task.rs +++ b/src/components/main/layout/layout_task.rs @@ -295,7 +295,9 @@ impl LayoutTask { } } PrepareToExitMsg(response_chan) => { - self.prepare_to_exit(response_chan) + debug!("layout: PrepareToExitMsg received"); + self.prepare_to_exit(response_chan); + return false } ExitNowMsg => { debug!("layout: ExitNowMsg received"); @@ -312,15 +314,21 @@ impl LayoutTask { /// response channel. fn prepare_to_exit(&mut self, response_chan: Chan<()>) { response_chan.send(()); - match self.port.recv() { - ReapLayoutDataMsg(dead_layout_data) => { - unsafe { - self.handle_reap_layout_data(dead_layout_data) + loop { + match self.port.recv() { + ReapLayoutDataMsg(dead_layout_data) => { + unsafe { + self.handle_reap_layout_data(dead_layout_data) + } + } + ExitNowMsg => { + self.exit_now(); + break + } + _ => { + fail!("layout: message that wasn't `ExitNowMsg` received after \ + `PrepareToExitMsg`") } - } - ExitNowMsg => self.exit_now(), - _ => { - fail!("layout: message that wasn't `ExitNowMsg` received after `PrepareToExitMsg`") } } } diff --git a/src/components/main/pipeline.rs b/src/components/main/pipeline.rs index 77ac8741787..e277beccbd9 100644 --- a/src/components/main/pipeline.rs +++ b/src/components/main/pipeline.rs @@ -2,23 +2,22 @@ * 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 extra::url::Url; use compositing::CompositorChan; -use gfx::render_task::{RenderChan, RenderTask}; -use gfx::render_task::{PaintPermissionGranted, PaintPermissionRevoked}; -use gfx::opts::Opts; use layout::layout_task::LayoutTask; + +use extra::url::Url; +use gfx::opts::Opts; +use gfx::render_task::{PaintPermissionGranted, PaintPermissionRevoked}; +use gfx::render_task::{RenderChan, RenderTask}; +use script::dom::node::AbstractNode; use script::layout_interface::LayoutChan; use script::script_task::LoadMsg; -use servo_msg::constellation_msg::{ConstellationChan, FailureMsg, PipelineId, SubpageId}; -use script::dom::node::AbstractNode; use script::script_task::{AttachLayoutMsg, NewLayoutInfo, ScriptTask, ScriptChan}; use script::script_task; +use servo_msg::constellation_msg::{ConstellationChan, FailureMsg, PipelineId, SubpageId}; use servo_net::image_cache_task::ImageCacheTask; use servo_net::resource_task::ResourceTask; use servo_util::time::ProfilerChan; -use geom::size::Size2D; -use extra::future::Future; use std::task; /// A uniquely-identifiable pipeline of script task, layout task, and render task. @@ -34,7 +33,8 @@ pub struct Pipeline { } impl Pipeline { - /// Starts a render task, layout task, and script task. Returns the channels wrapped in a struct. + /// Starts a render task, layout task, and script task. Returns the channels wrapped in a + /// struct. pub fn with_script(id: PipelineId, subpage_id: Option<SubpageId>, constellation_chan: ConstellationChan, @@ -42,8 +42,8 @@ impl Pipeline { image_cache_task: ImageCacheTask, profiler_chan: ProfilerChan, opts: Opts, - script_pipeline: &Pipeline, - size_future: Future<Size2D<uint>>) -> Pipeline { + script_pipeline: &Pipeline) + -> Pipeline { let (layout_port, layout_chan) = special_stream!(LayoutChan); let (render_port, render_chan) = special_stream!(RenderChan); @@ -67,7 +67,6 @@ impl Pipeline { old_id: script_pipeline.id.clone(), new_id: id, layout_chan: layout_chan.clone(), - size_future: size_future, }; script_pipeline.script_chan.send(AttachLayoutMsg(new_layout_info)); @@ -86,9 +85,8 @@ impl Pipeline { image_cache_task: ImageCacheTask, resource_task: ResourceTask, profiler_chan: ProfilerChan, - opts: Opts, - size: Future<Size2D<uint>>) -> Pipeline { - + opts: Opts) + -> Pipeline { let (script_port, script_chan) = special_stream!(ScriptChan); let (layout_port, layout_chan) = special_stream!(LayoutChan); let (render_port, render_chan) = special_stream!(RenderChan); @@ -106,9 +104,15 @@ impl Pipeline { let task_port = supervised_task.future_result(); supervised_task.supervised(); - spawn_with!(supervised_task, [script_port, resource_task, size, render_port, - layout_port, constellation_chan, image_cache_task, - profiler_chan], { + spawn_with!(supervised_task, [ + script_port, + resource_task, + render_port, + layout_port, + constellation_chan, + image_cache_task, + profiler_chan + ], { ScriptTask::create(id, compositor_chan.clone(), layout_chan.clone(), @@ -116,8 +120,7 @@ impl Pipeline { script_chan.clone(), constellation_chan.clone(), resource_task, - image_cache_task.clone(), - size); + image_cache_task.clone()); RenderTask::create(id, render_port, @@ -187,8 +190,7 @@ impl Pipeline { } pub fn exit(&self) { - // Script task handles shutting down layout, - // and layout handles shutting down the renderer. + // Script task handles shutting down layout, and layout handles shutting down the renderer. self.script_chan.try_send(script_task::ExitPipelineMsg(self.id)); } } diff --git a/src/components/main/servo.rc b/src/components/main/servo.rc index f286368b332..a19c0ba6dcb 100755 --- a/src/components/main/servo.rc +++ b/src/components/main/servo.rc @@ -41,7 +41,7 @@ extern mod core_text = "rust-core-text"; use compositing::{CompositorChan, CompositorTask}; use constellation::Constellation; -use servo_msg::constellation_msg::{ExitMsg, InitLoadUrlMsg}; +use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, InitLoadUrlMsg}; #[cfg(not(test))] use gfx::opts; @@ -127,21 +127,32 @@ fn run(opts: Opts) { let (shutdown_port, shutdown_chan) = comm::stream(); let (profiler_port, profiler_chan) = special_stream!(ProfilerChan); let (compositor_port, compositor_chan) = special_stream!(CompositorChan); + let (constellation_port, constellation_chan) = special_stream!(ConstellationChan); Profiler::create(profiler_port, profiler_chan.clone(), opts.profiler_period); - do spawn_with((profiler_chan.clone(), compositor_chan, opts.clone())) - |(profiler_chan, compositor_chan, opts)| { - + do spawn_with((constellation_port, + constellation_chan.clone(), + profiler_chan.clone(), + compositor_chan, + opts.clone())) + |(constellation_port, + constellation_chan, + profiler_chan, + compositor_chan, + opts)| { let opts = &opts; + // Create a Servo instance. let resource_task = ResourceTask(); let image_cache_task = ImageCacheTask(resource_task.clone()); - let constellation_chan = Constellation::start(compositor_chan, - opts, - resource_task, - image_cache_task, - profiler_chan.clone()); + Constellation::start(constellation_port, + constellation_chan.clone(), + compositor_chan, + opts, + resource_task, + image_cache_task, + profiler_chan.clone()); // Send the URL command to the constellation. for filename in opts.urls.iter() { @@ -158,11 +169,12 @@ fn run(opts: Opts) { exit_response_from_constellation.recv(); } - let compositor_task = CompositorTask::new(opts, compositor_port, + constellation_chan, profiler_chan, shutdown_chan); + debug!("preparing to enter main loop"); compositor_task.run(); } diff --git a/src/components/msg/constellation_msg.rs b/src/components/msg/constellation_msg.rs index d24619fd9af..5c91b329379 100644 --- a/src/components/msg/constellation_msg.rs +++ b/src/components/msg/constellation_msg.rs @@ -5,11 +5,10 @@ //! The high-level interface from script to constellation. Using this abstract interface helps reduce /// coupling between these two components -use std::comm::{Chan, SharedChan}; use extra::url::Url; -use extra::future::Future; -use geom::size::Size2D; use geom::rect::Rect; +use geom::size::Size2D; +use std::comm::{Chan, SharedChan}; #[deriving(Clone)] pub struct ConstellationChan(SharedChan<Msg>); @@ -32,8 +31,8 @@ pub enum Msg { FailureMsg(PipelineId, Option<SubpageId>), InitLoadUrlMsg(Url), FrameRectMsg(PipelineId, SubpageId, Rect<f32>), - LoadUrlMsg(PipelineId, Url, Future<Size2D<uint>>), - LoadIframeUrlMsg(Url, PipelineId, SubpageId, Future<Size2D<uint>>, IFrameSandboxState), + LoadUrlMsg(PipelineId, Url), + LoadIframeUrlMsg(Url, PipelineId, SubpageId, IFrameSandboxState), NavigateMsg(NavigationDirection), RendererReadyMsg(PipelineId), ResizedWindowMsg(Size2D<uint>), diff --git a/src/components/script/dom/htmliframeelement.rs b/src/components/script/dom/htmliframeelement.rs index 73172cb0ad8..7f39cfa58d8 100644 --- a/src/components/script/dom/htmliframeelement.rs +++ b/src/components/script/dom/htmliframeelement.rs @@ -9,15 +9,11 @@ use dom::element::HTMLIframeElementTypeId; use dom::htmlelement::HTMLElement; use dom::node::{AbstractNode, Node, ScriptView}; use dom::windowproxy::WindowProxy; -use geom::size::Size2D; -use geom::rect::Rect; +use extra::url::Url; +use geom::rect::Rect; use servo_msg::constellation_msg::{ConstellationChan, FrameRectMsg, PipelineId, SubpageId}; - use std::ascii::StrAsciiExt; -use std::comm::ChanOne; -use extra::url::Url; -use std::util::replace; enum SandboxAllowance { AllowNothing = 0x00, @@ -39,17 +35,11 @@ pub struct HTMLIFrameElement { struct IFrameSize { pipeline_id: PipelineId, subpage_id: SubpageId, - future_chan: Option<ChanOne<Size2D<uint>>>, constellation_chan: ConstellationChan, } impl IFrameSize { pub fn set_rect(&mut self, rect: Rect<f32>) { - let future_chan = replace(&mut self.future_chan, None); - do future_chan.map |future_chan| { - let Size2D { width, height } = rect.size; - future_chan.send(Size2D(width as uint, height as uint)); - }; self.constellation_chan.send(FrameRectMsg(self.pipeline_id, self.subpage_id, rect)); } } diff --git a/src/components/script/html/hubbub_html_parser.rs b/src/components/script/html/hubbub_html_parser.rs index b36e1d60cf2..e73d1205950 100644 --- a/src/components/script/html/hubbub_html_parser.rs +++ b/src/components/script/html/hubbub_html_parser.rs @@ -12,26 +12,24 @@ use dom::namespace; use dom::node::{AbstractNode, ElementNodeTypeId, ScriptView}; use dom::types::*; use html::cssparse::{InlineProvenance, StylesheetProvenance, UrlProvenance, spawn_css_parser}; -use js::jsapi::JSContext; -use style::Stylesheet; use script_task::page_from_context; -use std::cast; -use std::cell::Cell; -use std::comm; -use std::comm::{Port, SharedChan}; -use std::str; -use std::str::eq_slice; -use std::from_str::FromStr; +use extra::url::Url; use hubbub::hubbub; +use js::jsapi::JSContext; use servo_msg::constellation_msg::{ConstellationChan, SubpageId}; use servo_net::image_cache_task::ImageCacheTask; use servo_net::resource_task::{Load, Payload, Done, ResourceTask, load_whole_resource}; use servo_util::tree::{TreeNodeRef, ElementLike}; use servo_util::url::make_url; -use extra::future::Future; -use extra::url::Url; -use geom::size::Size2D; +use std::cast; +use std::cell::Cell; +use std::comm::{Port, SharedChan}; +use std::comm; +use std::from_str::FromStr; +use std::str::eq_slice; +use std::str; +use style::Stylesheet; macro_rules! handle_element( ($document: expr, @@ -67,7 +65,7 @@ enum JSMessage { /// Messages generated by the HTML parser upon discovery of additional resources pub enum HtmlDiscoveryMessage { HtmlDiscoveredStyle(Stylesheet), - HtmlDiscoveredIFrame((Url, SubpageId, Future<Size2D<uint>>, bool)), + HtmlDiscoveredIFrame((Url, SubpageId, bool)), HtmlDiscoveredScript(JSResult) } @@ -374,10 +372,6 @@ pub fn parse_html(cx: *JSContext, let iframe_url = make_url(src.clone(), Some(url2.clone())); iframe_element.frame = Some(iframe_url.clone()); - // Size future - let (port, chan) = comm::oneshot(); - let size_future = Future::from_port(port); - // Subpage Id let subpage_id = next_subpage_id.take(); next_subpage_id.put_back(SubpageId(*subpage_id + 1)); @@ -391,11 +385,11 @@ pub fn parse_html(cx: *JSContext, iframe_element.size = Some(IFrameSize { pipeline_id: pipeline_id, subpage_id: subpage_id, - future_chan: Some(chan), constellation_chan: constellation_chan.clone(), }); - iframe_chan.send(HtmlDiscoveredIFrame((iframe_url, subpage_id, - size_future, sandboxed))); + iframe_chan.send(HtmlDiscoveredIFrame((iframe_url, + subpage_id, + sandboxed))); } } } diff --git a/src/components/script/script_task.rs b/src/components/script/script_task.rs index b77b383f4ed..4676639a6a4 100644 --- a/src/components/script/script_task.rs +++ b/src/components/script/script_task.rs @@ -27,11 +27,9 @@ use layout_interface::ContentChangedDocumentDamage; use layout_interface; use dom::node::ScriptView; -use extra::future::Future; use extra::url::Url; -use std::str::eq_slice; -use geom::size::Size2D; use geom::point::Point2D; +use geom::size::Size2D; use js::JSVAL_NULL; use js::global::debug_fns; use js::glue::RUST_JSVAL_TO_OBJECT; @@ -53,6 +51,7 @@ use std::cell::Cell; use std::comm::{Port, SharedChan}; use std::comm; use std::ptr; +use std::str::eq_slice; use std::task::{spawn_sched, SingleThreaded}; use std::util::replace; @@ -84,7 +83,6 @@ pub struct NewLayoutInfo { old_id: PipelineId, new_id: PipelineId, layout_chan: LayoutChan, - size_future: Future<Size2D<uint>>, } /// Encapsulates external communication with the script task. @@ -118,8 +116,8 @@ pub struct Page { /// What parts of the document are dirty, if any. damage: Option<DocumentDamage>, - /// The current size of the window, in pixels. - window_size: Future<Size2D<uint>>, + /// The current size of the window, in pixels. If `None`, we do not know the window size yet. + window_size: Option<Size2D<uint>>, js_info: Option<JSPageInfo>, @@ -148,7 +146,7 @@ pub struct PageTreeIterator<'self> { } impl PageTree { - fn new(id: PipelineId, layout_chan: LayoutChan, size_future: Future<Size2D<uint>>) -> PageTree { + fn new(id: PipelineId, layout_chan: LayoutChan) -> PageTree { PageTree { page: @mut Page { id: id, @@ -156,7 +154,7 @@ impl PageTree { layout_chan: layout_chan, layout_join_port: None, damage: None, - window_size: size_future, + window_size: None, js_info: None, url: None, next_subpage_id: SubpageId(0), @@ -280,18 +278,32 @@ impl Page { response_port.recv() } - /// This method will wait until the layout task has completed its current action, join the - /// layout task, and then request a new layout run. It won't wait for the new layout - /// computation to finish. + /// Reflows the page if it's possible to do so. This method will wait until the layout task has + /// completed its current action, join the layout task, and then request a new layout run. It + /// won't wait for the new layout computation to finish. + /// + /// If there is no window size yet, the page is presumed invisible and no reflow is performed. /// /// This function fails if there is no root frame. - pub fn reflow(&mut self, goal: ReflowGoal, script_chan: ScriptChan, compositor: @ScriptListener) { + pub fn reflow(&mut self, + goal: ReflowGoal, + script_chan: ScriptChan, + compositor: @ScriptListener) { let root = match self.frame { None => return, Some(ref frame) => { frame.document.document().GetDocumentElement() } }; + + let window_size = match self.window_size { + None => { + debug!("not reflowing due to lack of a window size"); + return + } + Some(window_size) => window_size, + }; + match root { None => {}, Some(root) => { @@ -314,7 +326,7 @@ impl Page { document_root: root, url: self.url.get_ref().first().clone(), goal: goal, - window_size: self.window_size.get(), + window_size: window_size, script_chan: script_chan, script_join_chan: join_chan, damage: replace(&mut self.damage, None).unwrap(), @@ -329,8 +341,8 @@ impl Page { } pub fn initialize_js_info(&mut self, js_context: @Cx, global: *JSObject) { - // Note that the order that these variables are initialized is _not_ arbitrary. Switching them around - // can -- and likely will -- lead to things breaking. + // Note that the order that these variables are initialized is _not_ arbitrary. Switching + // them around can -- and likely will -- lead to things breaking. js_context.set_default_options_and_version(); js_context.set_logging_error_reporter(); @@ -425,13 +437,12 @@ impl ScriptTask { chan: ScriptChan, constellation_chan: ConstellationChan, resource_task: ResourceTask, - img_cache_task: ImageCacheTask, - initial_size: Future<Size2D<uint>>) + img_cache_task: ImageCacheTask) -> @mut ScriptTask { let js_runtime = js::rust::rt(); let script_task = @mut ScriptTask { - page_tree: PageTree::new(id, layout_chan, initial_size), + page_tree: PageTree::new(id, layout_chan), image_cache_task: img_cache_task, resource_task: resource_task, @@ -463,25 +474,33 @@ impl ScriptTask { chan: ScriptChan, constellation_chan: ConstellationChan, resource_task: ResourceTask, - image_cache_task: ImageCacheTask, - initial_size: Future<Size2D<uint>>) { - let parms = Cell::new((compositor, layout_chan, port, chan, constellation_chan, - resource_task, image_cache_task, initial_size)); + image_cache_task: ImageCacheTask) { + let parms = Cell::new((compositor, + layout_chan, + port, + chan, + constellation_chan, + resource_task, + image_cache_task)); // Since SpiderMonkey is blocking it needs to run in its own thread. // If we don't do this then we'll just end up with a bunch of SpiderMonkeys // starving all the other tasks. do spawn_sched(SingleThreaded) { - let (compositor, layout_chan, port, chan, constellation_chan, - resource_task, image_cache_task, initial_size) = parms.take(); + let (compositor, + layout_chan, + port, + chan, + constellation_chan, + resource_task, + image_cache_task) = parms.take(); let script_task = ScriptTask::new(id, - @compositor as @ScriptListener, - layout_chan, - port, - chan, - constellation_chan, - resource_task, - image_cache_task, - initial_size); + @compositor as @ScriptListener, + layout_chan, + port, + chan, + constellation_chan, + resource_task, + image_cache_task); script_task.start(); } } @@ -512,6 +531,7 @@ impl ScriptTask { let event = self.port.recv(); match event { ResizeMsg(id, size) => { + debug!("script got resize message"); let page = self.page_tree.find(id).expect("resize sent to nonexistent pipeline").page; page.resize_event = Some(size); } @@ -538,7 +558,10 @@ impl ScriptTask { ReflowCompleteMsg(id, reflow_id) => self.handle_reflow_complete_msg(id, reflow_id), ResizeInactiveMsg(id, new_size) => self.handle_resize_inactive_msg(id, new_size), ExitPipelineMsg(id) => if self.handle_exit_pipeline_msg(id) { return false }, - ExitWindowMsg(id) => if self.handle_exit_window_msg(id) { return false }, + ExitWindowMsg(id) => { + self.handle_exit_window_msg(id); + return false + }, ResizeMsg(*) => fail!("should have handled ResizeMsg already"), } } @@ -551,14 +574,13 @@ impl ScriptTask { let NewLayoutInfo { old_id, new_id, - layout_chan, - size_future + layout_chan } = new_layout_info; let parent_page_tree = self.page_tree.find(old_id).expect("ScriptTask: received a layout whose parent has a PipelineId which does not correspond to a pipeline in the script task's page tree. This is a bug."); - let new_page_tree = PageTree::new(new_id, layout_chan, size_future); + let new_page_tree = PageTree::new(new_id, layout_chan); parent_page_tree.inner.push(new_page_tree); } @@ -612,30 +634,30 @@ impl ScriptTask { fn handle_resize_inactive_msg(&mut self, id: PipelineId, new_size: Size2D<uint>) { let page = self.page_tree.find(id).expect("Received resize message for PipelineId not associated with a page in the page tree. This is a bug.").page; - page.window_size = Future::from_value(new_size); + page.window_size = Some(new_size); let last_loaded_url = replace(&mut page.url, None); for url in last_loaded_url.iter() { page.url = Some((url.first(), true)); } } - fn handle_exit_window_msg(&mut self, id: PipelineId) -> bool { + fn handle_exit_window_msg(&mut self, id: PipelineId) { + debug!("script task handling exit window msg"); self.handle_exit_pipeline_msg(id); // TODO(tkuehn): currently there is only one window, // so this can afford to be naive and just shut down the // compositor. In the future it'll need to be smarter. self.compositor.close(); - true } - /// Handles a request to exit the script task and shut down layout. /// Returns true if the script task should shut down and false otherwise. fn handle_exit_pipeline_msg(&mut self, id: PipelineId) -> bool { // If root is being exited, shut down all pages if self.page_tree.page.id == id { for page in self.page_tree.iter() { + debug!("shutting down layout for root page {:?}", page.id); shut_down_layout(page) } return true @@ -645,6 +667,7 @@ impl ScriptTask { match self.page_tree.remove(id) { Some(ref mut page_tree) => { for page in page_tree.iter() { + debug!("shutting down layout for page {:?}", page.id); shut_down_layout(page) } false @@ -727,7 +750,7 @@ impl ScriptTask { Some(HtmlDiscoveredStyle(sheet)) => { page.layout_chan.send(AddStylesheetMsg(sheet)); } - Some(HtmlDiscoveredIFrame((iframe_url, subpage_id, size_future, sandboxed))) => { + Some(HtmlDiscoveredIFrame((iframe_url, subpage_id, sandboxed))) => { page.next_subpage_id = SubpageId(*subpage_id + 1); let sandboxed = if sandboxed { IFrameSandboxed @@ -737,7 +760,6 @@ impl ScriptTask { self.constellation_chan.send(LoadIframeUrlMsg(iframe_url, pipeline_id, subpage_id, - size_future, sandboxed)); } None => break @@ -824,7 +846,7 @@ impl ScriptTask { ResizeEvent(new_width, new_height) => { debug!("script got resize event: {:u}, {:u}", new_width, new_height); - page.window_size = Future::from_value(Size2D(new_width, new_height)); + page.window_size = Some(Size2D(new_width, new_height)); if page.frame.is_some() { page.damage(ReflowDocumentDamage); @@ -906,7 +928,7 @@ impl ScriptTask { None => {} } } else { - self.constellation_chan.send(LoadUrlMsg(page.id, url, Future::from_value(page.window_size.get()))); + self.constellation_chan.send(LoadUrlMsg(page.id, url)); } } } diff --git a/src/test/html/summit2.html b/src/test/html/summit2.html index caac423845f..98b0d4a9b0f 100644 --- a/src/test/html/summit2.html +++ b/src/test/html/summit2.html @@ -22,6 +22,7 @@ </style> </head> <body> + <div></div> <div class="frame"> <iframe id="frameone" sandbox="allow-scripts" src="summit-two.html"> </iframe> |