diff options
author | Tim Kuehn <tkuehn@cmu.edu> | 2013-06-26 22:42:01 -0700 |
---|---|---|
committer | Tim Kuehn <tkuehn@cmu.edu> | 2013-07-01 11:03:31 -0700 |
commit | fba7ec423c99a63bdcbe16029740e7ab4e38c088 (patch) | |
tree | 0e8a15014ee5bbf912153e8072c0a5505d3b4ecc | |
parent | fdb0d820a49fac9ae2df623751912adcbe7a119d (diff) | |
download | servo-fba7ec423c99a63bdcbe16029740e7ab4e38c088.tar.gz servo-fba7ec423c99a63bdcbe16029740e7ab4e38c088.zip |
add pipeline.rs, modularized pipelines communicating with constellation
-rw-r--r-- | src/components/gfx/render_task.rs | 143 | ||||
-rw-r--r-- | src/components/main/compositing/mod.rs | 5 | ||||
-rw-r--r-- | src/components/main/engine.rs | 228 | ||||
-rw-r--r-- | src/components/main/layout/layout_task.rs | 65 | ||||
-rw-r--r-- | src/components/main/macros.rs | 11 | ||||
-rw-r--r-- | src/components/main/pipeline.rs | 105 | ||||
-rwxr-xr-x | src/components/main/servo.rc | 1 | ||||
-rw-r--r-- | src/components/msg/compositor.rs | 31 | ||||
-rw-r--r-- | src/components/msg/engine.rs | 5 | ||||
-rw-r--r-- | src/components/script/dom/bindings/element.rs | 11 | ||||
-rw-r--r-- | src/components/script/dom/bindings/proxyhandler.rs | 4 | ||||
-rw-r--r-- | src/components/script/dom/bindings/utils.rs | 6 | ||||
-rw-r--r-- | src/components/script/dom/element.rs | 45 | ||||
-rw-r--r-- | src/components/script/dom/event.rs | 2 | ||||
-rw-r--r-- | src/components/script/dom/window.rs | 12 | ||||
-rw-r--r-- | src/components/script/html/hubbub_html_parser.rs | 8 | ||||
-rw-r--r-- | src/components/script/layout_interface.rs | 23 | ||||
-rw-r--r-- | src/components/script/script_task.rs | 134 | ||||
m--------- | src/support/alert/rust-alert | 0 |
19 files changed, 525 insertions, 314 deletions
diff --git a/src/components/gfx/render_task.rs b/src/components/gfx/render_task.rs index 62d2094c1e3..68a6b3874ec 100644 --- a/src/components/gfx/render_task.rs +++ b/src/components/gfx/render_task.rs @@ -8,7 +8,8 @@ use azure::{AzFloat, AzGLContext}; use azure::azure_hl::{B8G8R8A8, DrawTarget}; use display_list::DisplayList; use servo_msg::compositor::{RenderListener, IdleRenderState, RenderingRenderState, LayerBuffer}; -use servo_msg::compositor::LayerBufferSet; +use servo_msg::compositor::{CompositorToken, LayerBufferSet}; +use servo_msg::engine::{EngineChan, TokenSurrenderMsg}; use font_context::FontContext; use geom::matrix2d::Matrix2D; use geom::point::Point2D; @@ -20,6 +21,7 @@ use render_context::RenderContext; use std::cell::Cell; use std::comm::{Chan, Port, SharedChan}; use std::uint; +use std::util::replace; use servo_util::time::{ProfilerChan, profile}; use servo_util::time; @@ -29,70 +31,32 @@ pub struct RenderLayer { size: Size2D<uint> } -pub enum Msg<C> { - AttachCompositorMsg(C), +pub enum Msg { RenderMsg(RenderLayer), ReRenderMsg(f32), + TokenBestowMsg(~CompositorToken), + TokenProcureMsg, ExitMsg(Chan<()>), } -pub struct RenderChan<C> { - chan: SharedChan<Msg<C>>, +#[deriving(Clone)] +pub struct RenderChan { + chan: SharedChan<Msg>, } -impl<C: RenderListener + Owned> Clone for RenderChan<C> { - pub fn clone(&self) -> RenderChan<C> { - RenderChan { - chan: self.chan.clone(), - } - } -} - -impl<C: RenderListener + Owned> RenderChan<C> { - pub fn new(chan: Chan<Msg<C>>) -> RenderChan<C> { +impl RenderChan { + pub fn new(chan: Chan<Msg>) -> RenderChan { RenderChan { chan: SharedChan::new(chan), } } - pub fn send(&self, msg: Msg<C>) { + pub fn send(&self, msg: Msg) { self.chan.send(msg); } } -pub fn create_render_task<C: RenderListener + Owned>(port: Port<Msg<C>>, - compositor: C, - opts: Opts, - profiler_chan: ProfilerChan) { - let compositor_cell = Cell::new(compositor); - let opts_cell = Cell::new(opts); - let port = Cell::new(port); - - do spawn { - let compositor = compositor_cell.take(); - let share_gl_context = compositor.get_gl_context(); - let opts = opts_cell.with_ref(|o| copy *o); - let profiler_chan = profiler_chan.clone(); - let profiler_chan_copy = profiler_chan.clone(); - - // FIXME: rust/#5967 - let mut renderer = Renderer { - port: port.take(), - compositor: compositor, - font_ctx: @mut FontContext::new(opts.render_backend, - false, - profiler_chan), - opts: opts_cell.take(), - profiler_chan: profiler_chan_copy, - share_gl_context: share_gl_context, - render_layer: None, - }; - - renderer.start(); - } -} - -priv struct Renderer<C> { - port: Port<Msg<C>>, +priv struct RenderTask<C> { + port: Port<Msg>, compositor: C, font_ctx: @mut FontContext, opts: Opts, @@ -104,15 +68,58 @@ priv struct Renderer<C> { /// The layer to be rendered render_layer: Option<RenderLayer>, + /// A channel to the engine task for surrendering token + engine_chan: EngineChan, + /// A token that grants permission to send paint messages to compositor + compositor_token: Option<~CompositorToken>, + /// Cached copy of last layers rendered + next_paint_msg: Option<(LayerBufferSet, Size2D<uint>)>, } -impl<C: RenderListener + Owned> Renderer<C> { +impl<C: RenderListener + Owned> RenderTask<C> { + pub fn create(port: Port<Msg>, + compositor: C, + opts: Opts, + engine_chan: EngineChan, + profiler_chan: ProfilerChan) { + let compositor_cell = Cell::new(compositor); + let opts_cell = Cell::new(opts); + let port = Cell::new(port); + let engine_chan = Cell::new(engine_chan); + + do spawn { + let compositor = compositor_cell.take(); + let share_gl_context = compositor.get_gl_context(); + let opts = opts_cell.with_ref(|o| copy *o); + let profiler_chan = profiler_chan.clone(); + let profiler_chan_clone = profiler_chan.clone(); + + // FIXME: rust/#5967 + let mut render_task = RenderTask { + port: port.take(), + compositor: compositor, + font_ctx: @mut FontContext::new(opts.render_backend, + false, + profiler_chan), + opts: opts_cell.take(), + profiler_chan: profiler_chan_clone, + share_gl_context: share_gl_context, + render_layer: None, + + engine_chan: engine_chan.take(), + compositor_token: None, + next_paint_msg: None, + }; + + render_task.start(); + } + } + fn start(&mut self) { - debug!("renderer: beginning rendering loop"); + debug!("render_task: beginning rendering loop"); loop { match self.port.recv() { - AttachCompositorMsg(compositor) => self.compositor = compositor, RenderMsg(render_layer) => { self.render_layer = Some(render_layer); self.render(1.0); @@ -120,6 +127,21 @@ impl<C: RenderListener + Owned> Renderer<C> { ReRenderMsg(scale) => { self.render(scale); } + TokenBestowMsg(token) => { + self.compositor_token = Some(token); + let next_paint_msg = replace(&mut self.next_paint_msg, None); + match next_paint_msg { + Some((layer_buffer_set, layer_size)) => { + println("retrieving cached paint msg"); + self.compositor.paint(layer_buffer_set, layer_size); + self.compositor.set_render_state(IdleRenderState); + } + None => {} + } + } + TokenProcureMsg => { + self.engine_chan.send(TokenSurrenderMsg(self.compositor_token.swap_unwrap())); + } ExitMsg(response_ch) => { response_ch.send(()); break; @@ -129,7 +151,7 @@ impl<C: RenderListener + Owned> Renderer<C> { } fn render(&mut self, scale: f32) { - debug!("renderer: rendering"); + debug!("render_task: rendering"); let render_layer; match (self.render_layer) { @@ -164,7 +186,8 @@ impl<C: RenderListener + Owned> Renderer<C> { let buffer = LayerBuffer { draw_target: DrawTarget::new_with_fbo(self.opts.render_backend, self.share_gl_context, - Size2D(width as i32, height as i32), + Size2D(width as i32, + height as i32), B8G8R8A8), rect: tile_rect, screen_pos: screen_rect, @@ -210,8 +233,14 @@ impl<C: RenderListener + Owned> Renderer<C> { buffers: new_buffers, }; - debug!("renderer: returning surface"); - self.compositor.paint(layer_buffer_set, render_layer.size); + debug!("render_task: returning surface"); + if self.compositor_token.is_some() { + self.compositor.paint(layer_buffer_set, render_layer.size); + } + else { + println("caching paint msg"); + self.next_paint_msg = Some((layer_buffer_set, render_layer.size)); + } self.compositor.set_render_state(IdleRenderState); } } diff --git a/src/components/main/compositing/mod.rs b/src/components/main/compositing/mod.rs index 9e3a2a1067e..873c46a645a 100644 --- a/src/components/main/compositing/mod.rs +++ b/src/components/main/compositing/mod.rs @@ -89,7 +89,7 @@ pub enum Msg { /// Sets the channel to the current layout task SetLayoutChan(LayoutChan), /// Sets the channel to the current renderer - SetRenderChan(RenderChan<CompositorChan>), + SetRenderChan(RenderChan), } /// Azure surface wrapping to work with the layers infrastructure. @@ -176,7 +176,7 @@ impl CompositorTask { let local_zoom = @mut 1f32; // Channel to the current renderer. // FIXME: This probably shouldn't be stored like this. - let render_chan: @mut Option<RenderChan<CompositorChan>> = @mut None; + let render_chan: @mut Option<RenderChan> = @mut None; let update_layout_callbacks: @fn(LayoutChan) = |layout_chan: LayoutChan| { let layout_chan_clone = layout_chan.clone(); @@ -432,3 +432,4 @@ fn on_osmain(f: ~fn()) { f(); } } + diff --git a/src/components/main/engine.rs b/src/components/main/engine.rs index cdabbba1ae2..41e6fafe783 100644 --- a/src/components/main/engine.rs +++ b/src/components/main/engine.rs @@ -10,28 +10,69 @@ use std::comm; use std::comm::Port; use std::task; use gfx::opts::Opts; -use gfx::render_task::RenderChan; -use gfx::render_task; -use servo_msg::compositor::{ScriptListener, ReadyState}; -use servo_msg::engine::{EngineChan, ExitMsg, LoadUrlMsg, Msg}; -use script::layout_interface::LayoutChan; -use script::layout_interface; -use script::script_task::{ExecuteMsg, LoadMsg, ScriptMsg, ScriptContext, ScriptChan}; -use script::script_task; +use gfx::render_task::{TokenBestowMsg, TokenProcureMsg}; +use pipeline::Pipeline; +use servo_msg::compositor::{CompositorToken}; +use servo_msg::engine::{EngineChan, ExitMsg, LoadUrlMsg, Msg, RendererReadyMsg, TokenSurrenderMsg}; +use script::script_task::{ExecuteMsg, LoadMsg}; 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::time::ProfilerChan; +use std::hashmap::HashMap; pub struct Engine { + chan: EngineChan, request_port: Port<Msg>, compositor_chan: CompositorChan, - render_chan: RenderChan<CompositorChan>, resource_task: ResourceTask, image_cache_task: ImageCacheTask, - layout_chan: LayoutChan, - script_chan: ScriptChan, + pipelines: HashMap<uint, Pipeline>, + navigation_context: NavigationContext, + next_id: uint, + current_token_holder: Option<uint>, + loading: Option<uint>, profiler_chan: ProfilerChan, + opts: Opts, +} + +pub struct NavigationContext { + previous: ~[uint], + next: ~[uint], + current: Option<uint>, +} + +impl NavigationContext { + pub fn new() -> NavigationContext { + NavigationContext { + previous: ~[], + next: ~[], + current: None, + } + } + + pub fn back(&mut self) -> uint { + do self.current.mutate |id| { + self.next.push(id); + self.previous.pop() + } + self.current.get() + } + + pub fn forward(&mut self) -> uint { + do self.current.mutate |id| { + self.previous.push(id); + self.next.pop() + } + self.current.get() + } + + pub fn navigate(&mut self, id: uint) { + do self.current.mutate_default(id) |cur_id| { + self.previous.push(cur_id); + id + } + } } impl Engine { @@ -41,105 +82,99 @@ impl Engine { image_cache_task: ImageCacheTask, profiler_chan: ProfilerChan) -> EngineChan { - macro_rules! closure_stream( - ($Msg:ty, $Chan:ident) => ( - { - let (port, chan) = comm::stream::<$Msg>(); - (Cell::new(port), $Chan::new(chan)) - } - ); - ) - // Create the script port and channel. - let (script_port, script_chan) = closure_stream!(ScriptMsg, ScriptChan); - - // Create the engine port and channel. - let (engine_port, engine_chan) = closure_stream!(Msg, EngineChan); - - // Create the layout port and channel. - let (layout_port, layout_chan) = closure_stream!(layout_interface::Msg, LayoutChan); - - let (render_port, render_chan) = comm::stream::<render_task::Msg<CompositorChan>>(); - let (render_port, render_chan) = (Cell::new(render_port), RenderChan::new(render_chan)); - + let opts = Cell::new(copy *opts); - compositor_chan.send(SetLayoutChan(layout_chan.clone())); - compositor_chan.send(SetRenderChan(render_chan.clone())); + let (engine_port, engine_chan) = comm::stream(); + let (engine_port, engine_chan) = (Cell::new(engine_port), EngineChan::new(engine_chan)); let compositor_chan = Cell::new(compositor_chan); - - let opts = Cell::new(copy *opts); - + let engine_chan_clone = Cell::new(engine_chan.clone()); { - let engine_chan = engine_chan.clone(); do task::spawn { - let compositor_chan = compositor_chan.take(); - render_task::create_render_task(render_port.take(), - compositor_chan.clone(), - opts.with_ref(|o| copy *o), - profiler_chan.clone()); - - let opts = opts.take(); - - layout_task::create_layout_task(layout_port.take(), - script_chan.clone(), - render_chan.clone(), - image_cache_task.clone(), - opts, - profiler_chan.clone()); - - let compositor_chan_clone = compositor_chan.clone(); - ScriptContext::create_script_context(layout_chan.clone(), - script_port.take(), - script_chan.clone(), - engine_chan.clone(), - |msg: ReadyState| { - compositor_chan_clone.set_ready_state(msg) - }, - resource_task.clone(), - image_cache_task.clone()); - - Engine { + let mut engine = Engine { + chan: engine_chan_clone.take(), request_port: engine_port.take(), - compositor_chan: compositor_chan.clone(), - render_chan: render_chan.clone(), + compositor_chan: compositor_chan.take(), resource_task: resource_task.clone(), image_cache_task: image_cache_task.clone(), - layout_chan: layout_chan.clone(), - script_chan: script_chan.clone(), + pipelines: HashMap::new(), + navigation_context: NavigationContext::new(), + next_id: 0, + current_token_holder: None, + loading: None, profiler_chan: profiler_chan.clone(), - }.run(); + opts: opts.take(), + }; + engine.run(); } } engine_chan } - fn run(&self) { - while self.handle_request(self.request_port.recv()) { - // Go on... + fn run(&mut self) { + loop { + let request = self.request_port.recv(); + if !self.handle_request(request) { + break; + } } } - fn handle_request(&self, request: Msg) -> bool { + fn get_next_id(&mut self) -> uint { + let id = self.next_id; + self.next_id = id + 1; + id + } + + fn handle_request(&mut self, request: Msg) -> bool { match request { LoadUrlMsg(url) => { + let pipeline_id = self.get_next_id(); + let pipeline = Pipeline::create(pipeline_id, + self.chan.clone(), + self.compositor_chan.clone(), + self.image_cache_task.clone(), + self.resource_task.clone(), + self.profiler_chan.clone(), + copy self.opts); if url.path.ends_with(".js") { - self.script_chan.send(ExecuteMsg(url)) + pipeline.script_chan.send(ExecuteMsg(url)); } else { - self.script_chan.send(LoadMsg(url)) + pipeline.script_chan.send(LoadMsg(url)); + self.loading = Some(pipeline_id); } - return true + self.pipelines.insert(pipeline_id, pipeline); } - ExitMsg(sender) => { - self.script_chan.send(script_task::ExitMsg); - self.layout_chan.send(layout_interface::ExitMsg); - - let (response_port, response_chan) = comm::stream(); + RendererReadyMsg(pipeline_id) => { + let loading = self.loading.clone(); + do loading.map() |&id| { + if pipeline_id == id { + match self.current_token_holder { + Some(ref id) => { + let current_holder = self.pipelines.find(id).get(); + current_holder.render_chan.send(TokenProcureMsg); + } + None => self.bestow_compositor_token(id, ~CompositorToken::new()) + } + } + }; + } - self.render_chan.send(render_task::ExitMsg(response_chan)); - response_port.recv(); + TokenSurrenderMsg(token) => { + self.remove_active_pipeline(); + let loading = self.loading.clone(); + let token = Cell::new(token); + do loading.map |&id| { + self.bestow_compositor_token(id, token.take()); + }; + } + ExitMsg(sender) => { + for self.pipelines.each |_, pipeline| { + pipeline.exit(); + } self.image_cache_task.exit(); self.resource_task.send(resource_task::Exit); @@ -147,6 +182,31 @@ impl Engine { return false } } + true + } + + fn remove_active_pipeline(&mut self) { +// FIXME(tkuehn): currently, pipelines are not removed at all +// do self.current_token_holder.map |id| { +// self.pipelines.pop(id).unwrap().exit(); +// }; + + self.current_token_holder = None; + } + + fn bestow_compositor_token(&mut self, id: uint, compositor_token: ~CompositorToken) { + let pipeline = self.pipelines.find(&id); + match pipeline { + None => fail!("Id of pipeline that made token request does not have a \ + corresponding struct in Engine's pipelines. This is a bug. :-("), + Some(pipeline) => { + pipeline.render_chan.send(TokenBestowMsg(compositor_token)); + self.compositor_chan.send(SetLayoutChan(pipeline.layout_chan.clone())); + self.current_token_holder = Some(id); + self.loading = None; + self.navigation_context.navigate(id); + } + } } } diff --git a/src/components/main/layout/layout_task.rs b/src/components/main/layout/layout_task.rs index 7f91d3dce29..29c3d800902 100644 --- a/src/components/main/layout/layout_task.rs +++ b/src/components/main/layout/layout_task.rs @@ -5,7 +5,6 @@ //! The layout task. Performs layout on the DOM, builds display lists and sends them to be /// rendered. -use compositing::CompositorChan; use css::matching::MatchMethods; use css::select::new_css_select_ctx; use layout::aux::{LayoutData, LayoutAuxMethods}; @@ -34,7 +33,7 @@ use script::dom::node::{AbstractNode, LayoutView}; use script::layout_interface::{AddStylesheetMsg, ContentBoxQuery}; use script::layout_interface::{HitTestQuery, ContentBoxResponse, HitTestResponse}; use script::layout_interface::{ContentBoxesQuery, ContentBoxesResponse, ExitMsg, LayoutQuery}; -use script::layout_interface::{LayoutResponse, MatchSelectorsDocumentDamage, Msg}; +use script::layout_interface::{MatchSelectorsDocumentDamage, Msg}; use script::layout_interface::{QueryMsg, RouteScriptMsg, Reflow, ReflowDocumentDamage}; use script::layout_interface::{ReflowForDisplay, ReflowMsg}; use script::script_task::{ReflowCompleteMsg, ScriptChan, ScriptMsg, SendEventMsg}; @@ -45,28 +44,10 @@ use servo_util::time::{ProfilerChan, profile, time}; use servo_util::time; use extra::net::url::Url; -pub fn create_layout_task(port: Port<Msg>, - script_chan: ScriptChan, - render_chan: RenderChan<CompositorChan>, - img_cache_task: ImageCacheTask, - opts: Opts, - profiler_chan: ProfilerChan) { - let port = Cell::new(port); - do spawn { - let mut layout = Layout::new(port.take(), - script_chan.clone(), - render_chan.clone(), - img_cache_task.clone(), - &opts, - profiler_chan.clone()); - layout.start(); - }; -} - -struct Layout { +struct LayoutTask { port: Port<Msg>, script_chan: ScriptChan, - render_chan: RenderChan<CompositorChan>, + render_chan: RenderChan, image_cache_task: ImageCacheTask, local_image_cache: @mut LocalImageCache, font_ctx: @mut FontContext, @@ -80,17 +61,35 @@ struct Layout { profiler_chan: ProfilerChan, } -impl Layout { +impl LayoutTask { + pub fn create(port: Port<Msg>, + script_chan: ScriptChan, + render_chan: RenderChan, + img_cache_task: ImageCacheTask, + opts: Opts, + profiler_chan: ProfilerChan) { + let port = Cell::new(port); + do spawn { + let mut layout = LayoutTask::new(port.take(), + script_chan.clone(), + render_chan.clone(), + img_cache_task.clone(), + &opts, + profiler_chan.clone()); + layout.start(); + }; + } + fn new(port: Port<Msg>, script_chan: ScriptChan, - render_chan: RenderChan<CompositorChan>, + render_chan: RenderChan, image_cache_task: ImageCacheTask, opts: &Opts, profiler_chan: ProfilerChan) - -> Layout { + -> LayoutTask { let fctx = @mut FontContext::new(opts.render_backend, true, profiler_chan.clone()); - Layout { + LayoutTask { port: port, script_chan: script_chan, render_chan: render_chan, @@ -135,10 +134,10 @@ impl Layout { self.handle_reflow(data.take()); } } - QueryMsg(query, chan) => { - let chan = Cell::new(chan); + QueryMsg(query) => { + let query = Cell::new(query); do profile(time::LayoutQueryCategory, self.profiler_chan.clone()) { - self.handle_query(query, chan.take()); + self.handle_query(query.take()); } } RouteScriptMsg(script_msg) => { @@ -268,9 +267,9 @@ impl Layout { /// Handles a query from the script task. This is the main routine that DOM functions like /// `getClientRects()` or `getBoundingClientRect()` ultimately invoke. - fn handle_query(&self, query: LayoutQuery, reply_chan: Chan<Result<LayoutResponse,()>>) { + fn handle_query(&self, query: LayoutQuery) { match query { - ContentBoxQuery(node) => { + ContentBoxQuery(node, reply_chan) => { // FIXME: Isolate this transmutation into a single "bridge" module. let node: AbstractNode<LayoutView> = unsafe { transmute(node) @@ -302,7 +301,7 @@ impl Layout { reply_chan.send(response) } - ContentBoxesQuery(node) => { + ContentBoxesQuery(node, reply_chan) => { // FIXME: Isolate this transmutation into a single "bridge" module. let node: AbstractNode<LayoutView> = unsafe { transmute(node) @@ -322,7 +321,7 @@ impl Layout { reply_chan.send(response) } - HitTestQuery(node, point) => { + HitTestQuery(node, point, reply_chan) => { // FIXME: Isolate this transmutation into a single "bridge" module. let node: AbstractNode<LayoutView> = unsafe { transmute(node) diff --git a/src/components/main/macros.rs b/src/components/main/macros.rs index 8fe65bccfb6..169e0a0a201 100644 --- a/src/components/main/macros.rs +++ b/src/components/main/macros.rs @@ -1,7 +1,7 @@ /* 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/. */ - +#[macro_escape]; { macro_rules! move_ref( { $x:expr } => { unsafe { let y <- *ptr::to_unsafe_ptr(*$x); y } } @@ -68,4 +68,13 @@ ])+) } ) + + macro_rules! closure_stream( + ($Msg:ty, $Chan:ident) => ( + { + let (port, chan) = comm::stream::<$Msg>(); + (Cell(port), $Chan::new(chan)) + } + ); + ) } diff --git a/src/components/main/pipeline.rs b/src/components/main/pipeline.rs new file mode 100644 index 00000000000..95a247cca3b --- /dev/null +++ b/src/components/main/pipeline.rs @@ -0,0 +1,105 @@ +/* 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 compositing::CompositorChan; +use gfx::render_task::{RenderChan, RenderTask}; +use gfx::render_task; +use gfx::opts::Opts; +use layout::layout_task::LayoutTask; +use script::layout_interface::LayoutChan; +use script::layout_interface; +use servo_msg::engine::{EngineChan}; +use script::script_task::{ScriptTask, ScriptChan, ScriptMsg}; +use script::script_task; +use servo_net::image_cache_task::ImageCacheTask; +use servo_net::resource_task::ResourceTask; +use servo_util::time::ProfilerChan; +use std::comm; + +/// A uniquely-identifiable pipeline of stript task, layout task, and render task. +pub struct Pipeline { + id: uint, + script_chan: ScriptChan, + layout_chan: LayoutChan, + render_chan: RenderChan, +} + +impl Pipeline { + /// Starts a render task, layout task, and script task. Returns the channels wrapped in a struct. + pub fn create(id: uint, + engine_chan: EngineChan, + compositor_chan: CompositorChan, + image_cache_task: ImageCacheTask, + resource_task: ResourceTask, + profiler_chan: ProfilerChan, + opts: Opts) -> Pipeline { + + macro_rules! closure_stream( + ($Msg:ty, $Chan:ident) => ( + { + let (port, chan) = comm::stream::<$Msg>(); + (port, $Chan::new(chan)) + } + ); + ) + // Create the script port and channel. + let (script_port, script_chan) = closure_stream!(ScriptMsg, ScriptChan); + + // Create the layout port and channel. + let (layout_port, layout_chan) = closure_stream!(layout_interface::Msg, LayoutChan); + + let (render_port, render_chan) = comm::stream::<render_task::Msg>(); + let render_chan = RenderChan::new(render_chan); + + RenderTask::create(render_port, + compositor_chan.clone(), + copy opts, + engine_chan.clone(), + profiler_chan.clone()); + + LayoutTask::create(layout_port, + script_chan.clone(), + render_chan.clone(), + image_cache_task.clone(), + copy opts, + profiler_chan.clone()); + + ScriptTask::create(id, + compositor_chan.clone(), + layout_chan.clone(), + script_port, + script_chan.clone(), + engine_chan, + resource_task.clone(), + image_cache_task.clone()); + + Pipeline::new(id, + script_chan, + layout_chan, + render_chan) + } + + pub fn new(id: uint, + script_chan: ScriptChan, + layout_chan: LayoutChan, + render_chan: RenderChan) + -> Pipeline { + Pipeline { + id: id, + script_chan: script_chan, + layout_chan: layout_chan, + render_chan: render_chan, + } + } + + pub fn exit(&self) { + self.script_chan.send(script_task::ExitMsg); + self.layout_chan.send(layout_interface::ExitMsg); + + let (response_port, response_chan) = comm::stream(); + self.render_chan.send(render_task::ExitMsg(response_chan)); + response_port.recv(); + } +} + diff --git a/src/components/main/servo.rc b/src/components/main/servo.rc index d2b3ae08c41..73ac4fa0a1d 100755 --- a/src/components/main/servo.rc +++ b/src/components/main/servo.rc @@ -63,6 +63,7 @@ pub mod css { } pub mod engine; +pub mod pipeline; pub mod layout { pub mod block; diff --git a/src/components/msg/compositor.rs b/src/components/msg/compositor.rs index 6b6311fd1ba..6d8fe2ecc50 100644 --- a/src/components/msg/compositor.rs +++ b/src/components/msg/compositor.rs @@ -6,6 +6,7 @@ use azure::azure_hl::DrawTarget; use azure::azure::AzGLContext; use geom::rect::Rect; use geom::size::Size2D; +use std::util::NonCopyable; pub struct LayerBuffer { draw_target: DrawTarget, @@ -33,14 +34,6 @@ pub enum RenderState { RenderingRenderState, } -/// The interface used by the renderer to acquire draw targets for each rendered frame and -/// submit them to be drawn to the display. -pub trait RenderListener { - fn get_gl_context(&self) -> AzGLContext; - fn paint(&self, layer_buffer_set: LayerBufferSet, new_size: Size2D<uint>); - fn set_render_state(&self, render_state: RenderState); -} - pub enum ReadyState { /// Informs the compositor that a page is loading. Used for setting status Loading, @@ -50,8 +43,30 @@ pub enum ReadyState { FinishedLoading, } +/// The interface used by the renderer to acquire draw targets for each render frame and +/// submit them to be drawn to the display. +pub trait RenderListener { + fn get_gl_context(&self) -> AzGLContext; + fn paint(&self, layer_buffer_set: LayerBufferSet, new_size: Size2D<uint>); + fn set_render_state(&self, render_state: RenderState); +} + /// The interface used by the script task to tell the compositor to update its ready state, /// which is used in displaying the appropriate message in the window's title. pub trait ScriptListener : Clone { fn set_ready_state(&self, ReadyState); } + +/// Signifies control of the compositor. Only the render task controlling +/// the compositor token may send paint messages to the compositor +pub struct CompositorToken { + construction_restrictor: NonCopyable, +} + +impl CompositorToken { + pub fn new() -> CompositorToken { + CompositorToken { + construction_restrictor: NonCopyable::new(), + } + } +} diff --git a/src/components/msg/engine.rs b/src/components/msg/engine.rs index 83e0f085ee0..b03893d14ca 100644 --- a/src/components/msg/engine.rs +++ b/src/components/msg/engine.rs @@ -7,6 +7,9 @@ use std::comm::{Chan, SharedChan}; use extra::net::url::Url; +use compositor::CompositorToken; + +pub use compositor; #[deriving(Clone)] pub struct EngineChan { @@ -27,5 +30,7 @@ impl EngineChan { pub enum Msg { LoadUrlMsg(Url), ExitMsg(Chan<()>), + RendererReadyMsg(uint), + TokenSurrenderMsg(~CompositorToken), } diff --git a/src/components/script/dom/bindings/element.rs b/src/components/script/dom/bindings/element.rs index 9a34f7c5dc6..b79daf75db7 100644 --- a/src/components/script/dom/bindings/element.rs +++ b/src/components/script/dom/bindings/element.rs @@ -16,6 +16,7 @@ use std::cast; use std::i32; use std::libc; use std::libc::c_uint; +use std::comm; use std::ptr; use std::ptr::null; use std::result; @@ -229,13 +230,9 @@ extern fn HTMLImageElement_getWidth(cx: *JSContext, _argc: c_uint, vp: *mut JSVa let width = match node.type_id() { ElementNodeTypeId(HTMLImageElementTypeId) => { let script_context = task_from_context(cx); - match (*script_context).query_layout(ContentBoxQuery(node)) { - Ok(rect) => { - match rect { - ContentBoxResponse(rect) => rect.size.width.to_px(), - _ => fail!(~"unexpected layout reply") - } - } + let (port, chan) = comm::stream(); + match (*script_context).query_layout(ContentBoxQuery(node, chan), port) { + Ok(ContentBoxResponse(rect)) => rect.size.width.to_px(), Err(()) => 0 } // TODO: if nothing is being rendered(?), return zero dimensions diff --git a/src/components/script/dom/bindings/proxyhandler.rs b/src/components/script/dom/bindings/proxyhandler.rs index 2780a969eb2..cbbc4f1525d 100644 --- a/src/components/script/dom/bindings/proxyhandler.rs +++ b/src/components/script/dom/bindings/proxyhandler.rs @@ -71,7 +71,7 @@ pub fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString { return ptr::null(); } - let result = ~"[object " + name + ~"]"; + let result = ~"[object " + name + "]"; for result.iter().enumerate().advance |(i, c)| { *chars.offset(i) = c as jschar; } @@ -86,4 +86,4 @@ pub fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString { pub fn GetExpandoObject(_proxy: *JSObject) -> *JSObject { ptr::null() -}
\ No newline at end of file +} diff --git a/src/components/script/dom/bindings/utils.rs b/src/components/script/dom/bindings/utils.rs index 9d3105fefca..5a42e109268 100644 --- a/src/components/script/dom/bindings/utils.rs +++ b/src/components/script/dom/bindings/utils.rs @@ -21,12 +21,12 @@ use js::glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB, ENUMERATE_STUB, CONVERT_STUB use js::jsapi::{JS_AlreadyHasOwnProperty, JS_NewObject, JS_NewFunction}; use js::jsapi::{JS_DefineProperties, JS_WrapValue, JS_ForwardGetPropertyTo}; use js::jsapi::{JS_EncodeString, JS_free, JS_GetStringCharsAndLength}; -use js::jsapi::{JS_GetClass, JS_GetPrototype, JS_LinkConstructorAndPrototype}; +use js::jsapi::{JS_GetClass, JS_LinkConstructorAndPrototype}; use js::jsapi::{JS_GetFunctionPrototype, JS_InternString, JS_GetFunctionObject}; use js::jsapi::{JS_HasPropertyById, JS_GetPrototype, JS_GetGlobalForObject}; use js::jsapi::{JS_NewStringCopyN, JS_DefineFunctions, JS_DefineProperty}; use js::jsapi::{JS_ValueToString, JS_GetReservedSlot, JS_SetReservedSlot}; -use js::jsapi::{JSContext, JSVal, JSObject, JSBool, jsid, JSClass, JSNative}; +use js::jsapi::{JSContext, JSObject, JSBool, jsid, JSClass, JSNative}; use js::jsapi::{JSFunctionSpec, JSPropertySpec, JSVal, JSPropertyDescriptor}; use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType; use js::rust::Compartment; @@ -83,7 +83,7 @@ extern fn InterfaceObjectToString(cx: *JSContext, _argc: uint, vp: *mut JSVal) - } let name = jsval_to_str(cx, *v).get(); - let retval = str(~"function " + name + ~"() {\n [native code]\n}"); + let retval = str(~"function " + name + "() {\n [native code]\n}"); *vp = domstring_to_jsval(cx, &retval); return 1; } diff --git a/src/components/script/dom/element.rs b/src/components/script/dom/element.rs index e707a95ebb9..2595a68657d 100644 --- a/src/components/script/dom/element.rs +++ b/src/components/script/dom/element.rs @@ -12,6 +12,7 @@ use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery}; use layout_interface::{ContentBoxesResponse}; use std::cell::Cell; +use std::comm; use std::uint; use std::str::eq_slice; use extra::net::url::Url; @@ -165,20 +166,19 @@ impl<'self> Element { Some(win) => { let node = self.parent.abstract.get(); assert!(node.is_element()); - let script_context = unsafe { - &mut *win.script_context + let script_task = unsafe { + &mut *win.script_task }; - match script_context.query_layout(ContentBoxesQuery(node)) { - Ok(rects) => match rects { - ContentBoxesResponse(rects) => - do rects.map |r| { - ClientRect::new( - r.origin.y.to_f32(), - (r.origin.y + r.size.height).to_f32(), - r.origin.x.to_f32(), - (r.origin.x + r.size.width).to_f32()) - }, - _ => fail!(~"unexpected layout reply") + let (port, chan) = comm::stream(); + match script_task.query_layout(ContentBoxesQuery(node, chan), port) { + Ok(ContentBoxesResponse(rects)) => { + do rects.map |r| { + ClientRect::new( + r.origin.y.to_f32(), + (r.origin.y + r.size.height).to_f32(), + r.origin.x.to_f32(), + (r.origin.x + r.size.width).to_f32()) + } }, Err(()) => { debug!("layout query error"); @@ -207,16 +207,15 @@ impl<'self> Element { Some(win) => { let node = self.parent.abstract.get(); assert!(node.is_element()); - let script_context = unsafe { &mut *win.script_context }; - match script_context.query_layout(ContentBoxQuery(node)) { - Ok(rect) => match rect { - ContentBoxResponse(rect) => - Some(ClientRect::new( - rect.origin.y.to_f32(), - (rect.origin.y + rect.size.height).to_f32(), - rect.origin.x.to_f32(), - (rect.origin.x + rect.size.width).to_f32())), - _ => fail!(~"unexpected layout result") + let script_task = unsafe { &mut *win.script_task }; + let (port, chan) = comm::stream(); + match script_task.query_layout(ContentBoxQuery(node, chan), port) { + Ok(ContentBoxResponse(rect)) => { + Some(ClientRect::new( + rect.origin.y.to_f32(), + (rect.origin.y + rect.size.height).to_f32(), + rect.origin.x.to_f32(), + (rect.origin.x + rect.size.width).to_f32())) }, Err(()) => { debug!("error querying layout"); diff --git a/src/components/script/dom/event.rs b/src/components/script/dom/event.rs index 047b734e6b4..6b4be15b701 100644 --- a/src/components/script/dom/event.rs +++ b/src/components/script/dom/event.rs @@ -9,8 +9,6 @@ use dom::bindings::utils::{DOMString, ErrorResult, WrapperCache}; use geom::point::Point2D; -use std::comm; - pub enum Event { ResizeEvent(uint, uint), ReflowEvent, diff --git a/src/components/script/dom/window.rs b/src/components/script/dom/window.rs index 5fb07c66f07..41f99eaa9e9 100644 --- a/src/components/script/dom/window.rs +++ b/src/components/script/dom/window.rs @@ -6,7 +6,7 @@ use dom::bindings::utils::WrapperCache; use dom::bindings::window; use layout_interface::ReflowForScriptQuery; -use script_task::{ExitMsg, FireTimerMsg, ScriptChan, ScriptContext}; +use script_task::{ExitMsg, FireTimerMsg, ScriptChan, ScriptTask}; use std::comm; use std::comm::Chan; @@ -29,7 +29,7 @@ pub enum TimerControlMsg { pub struct Window { timer_chan: Chan<TimerControlMsg>, script_chan: ScriptChan, - script_context: *mut ScriptContext, + script_task: *mut ScriptTask, wrapper: WrapperCache } @@ -89,11 +89,11 @@ impl Window { pub fn content_changed(&self) { unsafe { - (*self.script_context).reflow_all(ReflowForScriptQuery) + (*self.script_task).reflow_all(ReflowForScriptQuery) } } - pub fn new(script_chan: ScriptChan, script_context: *mut ScriptContext) + pub fn new(script_chan: ScriptChan, script_task: *mut ScriptTask) -> @mut Window { let script_chan_clone = script_chan.clone(); let win = @mut Window { @@ -112,11 +112,11 @@ impl Window { } timer_chan }, - script_context: script_context, + script_task: script_task, }; unsafe { - let compartment = (*script_context).js_compartment; + let compartment = (*script_task).js_compartment; window::create(compartment, win); } win diff --git a/src/components/script/html/hubbub_html_parser.rs b/src/components/script/html/hubbub_html_parser.rs index 6309e488d7e..9540fcc87d4 100644 --- a/src/components/script/html/hubbub_html_parser.rs +++ b/src/components/script/html/hubbub_html_parser.rs @@ -303,9 +303,9 @@ pub fn parse_html(url: Url, // Handle CSS style sheets from <link> elements ElementNodeTypeId(HTMLLinkElementTypeId) => { do node.with_imm_element |element| { - match (element.get_attr(~"rel"), element.get_attr(~"href")) { + match (element.get_attr("rel"), element.get_attr("href")) { (Some(rel), Some(href)) => { - if rel == ~"stylesheet" { + if rel == "stylesheet" { debug!("found CSS stylesheet: %s", href); let url = make_url(href.to_str(), Some(url2.clone())); css_chan2.send(CSSTaskNewFile(UrlProvenance(url))); @@ -317,7 +317,7 @@ pub fn parse_html(url: Url, }, ElementNodeTypeId(HTMLImageElementTypeId) => { do node.with_mut_image_element |image_element| { - let src_opt = image_element.parent.get_attr(~"src").map(|x| x.to_str()); + let src_opt = image_element.parent.get_attr("src").map(|x| x.to_str()); match src_opt { None => {} Some(src) => { @@ -401,7 +401,7 @@ pub fn parse_html(url: Url, unsafe { let script: AbstractNode<ScriptView> = NodeWrapping::from_hubbub_node(script); do script.with_imm_element |script| { - match script.get_attr(~"src") { + match script.get_attr("src") { Some(src) => { debug!("found script: %s", src); let new_url = make_url(src.to_str(), Some(url.clone())); diff --git a/src/components/script/layout_interface.rs b/src/components/script/layout_interface.rs index 3a1531b83e6..766c728067b 100644 --- a/src/components/script/layout_interface.rs +++ b/src/components/script/layout_interface.rs @@ -30,7 +30,7 @@ pub enum Msg { /// Performs a synchronous layout request. /// /// FIXME(pcwalton): As noted below, this isn't very type safe. - QueryMsg(LayoutQuery, Chan<Result<LayoutResponse,()>>), + QueryMsg(LayoutQuery), /// Routes a message (usually from the compositor) to the appropriate script task RouteScriptMsg(ScriptMsg), @@ -42,25 +42,16 @@ pub enum Msg { /// Synchronous messages that script can send to layout. pub enum LayoutQuery { /// Requests the dimensions of the content box, as in the `getBoundingClientRect()` call. - ContentBoxQuery(AbstractNode<ScriptView>), + ContentBoxQuery(AbstractNode<ScriptView>, Chan<Result<ContentBoxResponse, ()>>), /// Requests the dimensions of all the content boxes, as in the `getClientRects()` call. - ContentBoxesQuery(AbstractNode<ScriptView>), + ContentBoxesQuery(AbstractNode<ScriptView>, Chan<Result<ContentBoxesResponse, ()>>), /// Requests the node containing the point of interest - HitTestQuery(AbstractNode<ScriptView>, Point2D<f32>), + HitTestQuery(AbstractNode<ScriptView>, Point2D<f32>, Chan<Result<HitTestResponse, ()>>), } -/// The reply of a synchronous message from script to layout. -/// -/// FIXME(pcwalton): This isn't very type safe. Maybe `LayoutQuery` objects should include -/// response channels? -pub enum LayoutResponse { - /// A response to the `ContentBoxQuery` message. - ContentBoxResponse(Rect<Au>), - /// A response to the `ContentBoxesQuery` message. - ContentBoxesResponse(~[Rect<Au>]), - /// A response to the `HitTestQuery` message. - HitTestResponse(AbstractNode<LayoutView>), -} +pub struct ContentBoxResponse(Rect<Au>); +pub struct ContentBoxesResponse(~[Rect<Au>]); +pub struct HitTestResponse(AbstractNode<LayoutView>); /// Determines which part of the pub enum DocumentDamageLevel { diff --git a/src/components/script/script_task.rs b/src/components/script/script_task.rs index 7ef0b0035e1..ce89ef5efd7 100644 --- a/src/components/script/script_task.rs +++ b/src/components/script/script_task.rs @@ -5,19 +5,21 @@ /// The script task is the task that owns the DOM in memory, runs JavaScript, and spawns parsing /// and layout tasks. -use servo_msg::compositor::{ReadyState, Loading, PerformingLayout, FinishedLoading}; +use servo_msg::compositor::{ScriptListener, Loading, PerformingLayout}; +use servo_msg::compositor::FinishedLoading; use dom::bindings::utils::GlobalStaticData; use dom::document::Document; use dom::element::Element; use dom::event::{Event, ResizeEvent, ReflowEvent, ClickEvent, MouseDownEvent, MouseUpEvent}; use dom::node::{AbstractNode, ScriptView, define_bindings}; use dom::window::Window; -use layout_interface::{AddStylesheetMsg, DocumentDamage, DocumentDamageLevel, HitTestQuery}; -use layout_interface::{HitTestResponse, LayoutQuery, LayoutResponse, LayoutChan}; -use layout_interface::{MatchSelectorsDocumentDamage, QueryMsg, Reflow, ReflowDocumentDamage}; -use layout_interface::{ReflowForDisplay, ReflowForScriptQuery, ReflowGoal, ReflowMsg}; +use layout_interface::{AddStylesheetMsg, DocumentDamage}; +use layout_interface::{DocumentDamageLevel, HitTestQuery, HitTestResponse, LayoutQuery}; +use layout_interface::{LayoutChan, MatchSelectorsDocumentDamage, QueryMsg, Reflow}; +use layout_interface::{ReflowDocumentDamage, ReflowForDisplay, ReflowForScriptQuery, ReflowGoal}; +use layout_interface::ReflowMsg; use layout_interface; -use servo_msg::engine::{EngineChan, LoadUrlMsg}; +use servo_msg::engine::{EngineChan, LoadUrlMsg, RendererReadyMsg}; use std::cast::transmute; use std::cell::Cell; @@ -91,7 +93,9 @@ pub struct Frame { /// frames. /// /// FIXME: Rename to `Page`, following WebKit? -pub struct ScriptContext { +pub struct ScriptTask { + /// A unique identifier to the script's pipeline + id: uint, /// A handle to the layout task. layout_chan: LayoutChan, /// A handle to the image cache task. @@ -110,8 +114,8 @@ pub struct ScriptContext { /// For communicating load url messages to the engine engine_chan: EngineChan, - /// For communicating loading messages to the compositor - compositor_task: ~fn(ReadyState), + /// For permission to communicate ready state messages to the compositor + compositor: @ScriptListener, /// The JavaScript runtime. js_runtime: js::rust::rt, @@ -134,26 +138,26 @@ pub struct ScriptContext { damage: Option<DocumentDamage>, } -fn global_script_context_key(_: @ScriptContext) {} +fn global_script_context_key(_: @ScriptTask) {} /// Returns this task's script context singleton. -pub fn global_script_context() -> @ScriptContext { +pub fn global_script_context() -> @ScriptTask { unsafe { local_data::local_data_get(global_script_context_key).get() } } -/// Returns the script context from the JS Context. +/// Returns the script task from the JS Context. /// /// FIXME: Rename to `script_context_from_js_context`. -pub fn task_from_context(js_context: *JSContext) -> *mut ScriptContext { +pub fn task_from_context(js_context: *JSContext) -> *mut ScriptTask { unsafe { - JS_GetContextPrivate(js_context) as *mut ScriptContext + JS_GetContextPrivate(js_context) as *mut ScriptTask } } #[unsafe_destructor] -impl Drop for ScriptContext { +impl Drop for ScriptTask { fn finalize(&self) { unsafe { let _ = local_data::local_data_pop(global_script_context_key); @@ -161,16 +165,17 @@ impl Drop for ScriptContext { } } -impl ScriptContext { - /// Creates a new script context. - pub fn new(layout_chan: LayoutChan, +impl ScriptTask { + /// Creates a new script task. + pub fn new(id: uint, + compositor: @ScriptListener, + layout_chan: LayoutChan, script_port: Port<ScriptMsg>, script_chan: ScriptChan, engine_chan: EngineChan, - compositor_task: ~fn(ReadyState), resource_task: ResourceTask, img_cache_task: ImageCacheTask) - -> @mut ScriptContext { + -> @mut ScriptTask { let js_runtime = js::rust::rt(); let js_context = js_runtime.cx(); @@ -182,7 +187,10 @@ impl ScriptContext { Err(()) => fail!("Failed to create a compartment"), }; - let script_context = @mut ScriptContext { + let script_task = @mut ScriptTask { + id: id, + compositor: compositor, + layout_chan: layout_chan, image_cache_task: img_cache_task, resource_task: resource_task, @@ -192,7 +200,6 @@ impl ScriptContext { script_chan: script_chan, engine_chan: engine_chan, - compositor_task: compositor_task, js_runtime: js_runtime, js_context: js_context, @@ -207,17 +214,17 @@ impl ScriptContext { damage: None, }; // Indirection for Rust Issue #6248, dynamic freeze scope artifically extended - let script_context_ptr = { - let borrowed_ctx= &mut *script_context; - borrowed_ctx as *mut ScriptContext + let script_task_ptr = { + let borrowed_ctx= &mut *script_task; + borrowed_ctx as *mut ScriptTask }; unsafe { - js_context.set_cx_private(script_context_ptr as *()); - local_data::local_data_set(global_script_context_key, transmute(script_context)) + js_context.set_cx_private(script_task_ptr as *()); + local_data::local_data_set(global_script_context_key, transmute(script_task)) } - script_context + script_task } /// Starts the script task. After calling this method, the script task will loop receiving @@ -228,27 +235,29 @@ impl ScriptContext { } } - pub fn create_script_context(layout_chan: LayoutChan, - script_port: Port<ScriptMsg>, - script_chan: ScriptChan, - engine_chan: EngineChan, - compositor_task: ~fn(ReadyState), - resource_task: ResourceTask, - image_cache_task: ImageCacheTask) { + pub fn create<C: ScriptListener + Owned>(id: uint, + compositor: C, + layout_chan: LayoutChan, + script_port: Port<ScriptMsg>, + script_chan: ScriptChan, + engine_chan: EngineChan, + resource_task: ResourceTask, + image_cache_task: ImageCacheTask) { + let compositor = Cell::new(compositor); let script_port = Cell::new(script_port); - let compositor_task = Cell::new(compositor_task); // FIXME: rust#6399 let mut the_task = task(); the_task.sched_mode(SingleThreaded); - do the_task.spawn { - let script_context = ScriptContext::new(layout_chan.clone(), - script_port.take(), - script_chan.clone(), - engine_chan.clone(), - compositor_task.take(), - resource_task.clone(), - image_cache_task.clone()); - script_context.start(); + do spawn { + let script_task = ScriptTask::new(id, + @compositor.take() as @ScriptListener, + layout_chan.clone(), + script_port.take(), + script_chan.clone(), + engine_chan.clone(), + resource_task.clone(), + image_cache_task.clone()); + script_task.start(); } } @@ -324,7 +333,8 @@ impl ScriptContext { /// Handles a notification that reflow completed. fn handle_reflow_complete_msg(&mut self) { self.layout_join_port = None; - self.set_ready_state(FinishedLoading) + self.engine_chan.send(RendererReadyMsg(self.id)); + self.compositor.set_ready_state(FinishedLoading); } /// Handles a request to exit the script task and shut down layout. @@ -337,12 +347,6 @@ impl ScriptContext { self.layout_chan.send(layout_interface::ExitMsg) } - // tells the compositor when loading starts and finishes - // FIXME ~compositor_interface doesn't work right now, which is why this is necessary - fn set_ready_state(&self, msg: ReadyState) { - (self.compositor_task)(msg); - } - /// The entry point to document loading. Defines bindings, sets up the window and document /// objects, parses HTML and CSS, and kicks off initial layout. fn load(&mut self, url: Url) { @@ -354,7 +358,7 @@ impl ScriptContext { self.bindings_initialized = true } - self.set_ready_state(Loading); + self.compositor.set_ready_state(Loading); // Parse HTML. // // Note: We can parse the next document in parallel with any previous documents. @@ -446,7 +450,7 @@ impl ScriptContext { self.join_layout(); // Tell the user that we're performing layout. - self.set_ready_state(PerformingLayout); + self.compositor.set_ready_state(PerformingLayout); // Layout will let us know when it's done. let (join_port, join_chan) = comm::stream(); @@ -478,7 +482,7 @@ impl ScriptContext { /// FIXME: This should basically never be used. pub fn reflow_all(&mut self, goal: ReflowGoal) { for self.root_frame.iter().advance |root_frame| { - ScriptContext::damage(&mut self.damage, + ScriptTask::damage(&mut self.damage, root_frame.document.root, MatchSelectorsDocumentDamage) } @@ -487,12 +491,10 @@ impl ScriptContext { } /// Sends the given query to layout. - pub fn query_layout(&mut self, query: LayoutQuery) -> Result<LayoutResponse,()> { - self.join_layout(); - - let (response_port, response_chan) = comm::stream(); - self.layout_chan.send(QueryMsg(query, response_chan)); - response_port.recv() + pub fn query_layout<T: Owned>(&mut self, query: LayoutQuery, response_port: Port<Result<T, ()>>) -> Result<T,()> { + self.join_layout(); + self.layout_chan.send(QueryMsg(query)); + response_port.recv() } /// Adds the given damage. @@ -526,7 +528,7 @@ impl ScriptContext { self.window_size = Size2D(new_width, new_height); for self.root_frame.iter().advance |root_frame| { - ScriptContext::damage(&mut self.damage, + ScriptTask::damage(&mut self.damage, root_frame.document.root, ReflowDocumentDamage); } @@ -541,7 +543,7 @@ impl ScriptContext { debug!("script got reflow event"); for self.root_frame.iter().advance |root_frame| { - ScriptContext::damage(&mut self.damage, + ScriptTask::damage(&mut self.damage, root_frame.document.root, MatchSelectorsDocumentDamage); } @@ -557,7 +559,8 @@ impl ScriptContext { Some(ref frame) => frame.document.root, None => fail!("root frame is None") }; - match self.query_layout(HitTestQuery(root, point)) { + let (port, chan) = comm::stream(); + match self.query_layout(HitTestQuery(root, point, chan), port) { Ok(node) => match node { HitTestResponse(node) => { debug!("clicked on %?", node.debug_str()); @@ -580,7 +583,6 @@ impl ScriptContext { } } } - _ => fail!(~"unexpected layout reply") }, Err(()) => { debug!(fmt!("layout query error")); @@ -594,7 +596,7 @@ impl ScriptContext { priv fn load_url_from_element(&self, element: &Element) { // if the node's element is "a," load url from href attr - for element.attrs.each |attr| { + for element.attrs.iter().advance |attr| { if attr.name == ~"href" { debug!("clicked on link to %?", attr.value); let current_url = match self.root_frame { diff --git a/src/support/alert/rust-alert b/src/support/alert/rust-alert -Subproject 68875af396cb583e670dd5caad99431dac62f8d +Subproject 502ec156da38860a4dff911cf8f33f388a0a188 |