decouple script from compositor

communicate via layout
refactor channel wrappers from *Task --> *Chan

fix merge fallout
This commit is contained in:
Tim Kuehn 2013-06-13 16:32:13 -07:00
parent 93eea6b2e8
commit b5dac3f426
17 changed files with 609 additions and 538 deletions

View file

@ -34,7 +34,7 @@ pub enum RenderState {
/// The interface used to by the renderer to acquire draw targets for each rendered frame and /// The interface used to by the renderer to acquire draw targets for each rendered frame and
/// submit them to be drawn to the display. /// submit them to be drawn to the display.
pub trait Compositor { pub trait RenderListener {
fn get_gl_context(&self) -> AzGLContext; fn get_gl_context(&self) -> AzGLContext;
fn paint(&self, layer_buffer_set: LayerBufferSet, new_size: Size2D<uint>); fn paint(&self, layer_buffer_set: LayerBufferSet, new_size: Size2D<uint>);
fn set_render_state(&self, render_state: RenderState); fn set_render_state(&self, render_state: RenderState);

View file

@ -5,7 +5,7 @@
// The task that handles all rendering/painting. // The task that handles all rendering/painting.
use azure::{AzFloat, AzGLContext}; use azure::{AzFloat, AzGLContext};
use compositor::{Compositor, IdleRenderState, RenderingRenderState}; use compositor::{RenderListener, IdleRenderState, RenderingRenderState};
use font_context::FontContext; use font_context::FontContext;
use geom::matrix2d::Matrix2D; use geom::matrix2d::Matrix2D;
use opts::Opts; use opts::Opts;
@ -28,18 +28,27 @@ pub enum Msg {
} }
#[deriving(Clone)] #[deriving(Clone)]
pub struct RenderTask { pub struct RenderChan {
channel: SharedChan<Msg>, chan: SharedChan<Msg>,
} }
impl RenderTask { impl RenderChan {
pub fn new<C:Compositor + Owned>(compositor: C, pub fn new(chan: Chan<Msg>) -> RenderChan {
RenderChan {
chan: SharedChan::new(chan),
}
}
pub fn send(&self, msg: Msg) {
self.chan.send(msg);
}
}
pub fn create_render_task<C: RenderListener + Owned>(port: Port<Msg>,
compositor: C,
opts: Opts, opts: Opts,
profiler_chan: ProfilerChan) profiler_chan: ProfilerChan) {
-> RenderTask {
let compositor_cell = Cell(compositor); let compositor_cell = Cell(compositor);
let opts_cell = Cell(opts); let opts_cell = Cell(opts);
let (port, chan) = comm::stream();
let port = Cell(port); let port = Cell(port);
do spawn { do spawn {
@ -84,11 +93,6 @@ impl RenderTask {
renderer.start(); renderer.start();
} }
RenderTask {
channel: SharedChan::new(chan),
}
}
} }
/// Data that needs to be kept around for each render thread. /// Data that needs to be kept around for each render thread.
@ -110,7 +114,7 @@ priv struct Renderer<C> {
share_gl_context: AzGLContext, share_gl_context: AzGLContext,
} }
impl<C: Compositor + Owned> Renderer<C> { impl<C: RenderListener + Owned> Renderer<C> {
fn start(&mut self) { fn start(&mut self) {
debug!("renderer: beginning rendering loop"); debug!("renderer: beginning rendering loop");

View file

@ -2,16 +2,15 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use compositing::resize_rate_limiter::ResizeRateLimiter;
use platform::{Application, Window}; use platform::{Application, Window};
use script::script_task::{LoadMsg, ScriptMsg, SendEventMsg}; use script::script_task::{LoadMsg, SendEventMsg};
use windowing::{ApplicationMethods, WindowMethods, WindowMouseEvent, WindowClickEvent}; use windowing::{ApplicationMethods, WindowMethods, WindowMouseEvent, WindowClickEvent};
use windowing::{WindowMouseDownEvent, WindowMouseUpEvent}; use windowing::{WindowMouseDownEvent, WindowMouseUpEvent};
use gfx::compositor::RenderState; use script::dom::event::{Event, ClickEvent, MouseDownEvent, MouseUpEvent, ResizeEvent};
use script::dom::event::{Event, ClickEvent, MouseDownEvent, MouseUpEvent}; use script::compositor_interface::{ReadyState, ScriptListener};
use script::compositor_interface::{ReadyState, CompositorInterface}; use script::script_task::{ScriptChan, SendEventMsg};
use script::compositor_interface; use script::layout_interface::{LayoutChan, RouteScriptMsg};
use azure::azure_hl::{DataSourceSurface, DrawTarget, SourceSurfaceMethods, current_gl_context}; use azure::azure_hl::{DataSourceSurface, DrawTarget, SourceSurfaceMethods, current_gl_context};
use azure::azure::AzGLContext; use azure::azure::AzGLContext;
@ -22,7 +21,7 @@ use core::util;
use geom::matrix::identity; use geom::matrix::identity;
use geom::point::Point2D; use geom::point::Point2D;
use geom::size::Size2D; use geom::size::Size2D;
use gfx::compositor::{Compositor, LayerBufferSet, RenderState}; use gfx::compositor::{RenderListener, LayerBufferSet, RenderState};
use layers::layers::{ARGB32Format, ContainerLayer, ContainerLayerKind, Format}; use layers::layers::{ARGB32Format, ContainerLayer, ContainerLayerKind, Format};
use layers::layers::{ImageData, WithDataFn}; use layers::layers::{ImageData, WithDataFn};
use layers::layers::{TextureLayerKind, TextureLayer, TextureManager}; use layers::layers::{TextureLayerKind, TextureLayer, TextureManager};
@ -32,43 +31,44 @@ use servo_util::{time, url};
use servo_util::time::profile; use servo_util::time::profile;
use servo_util::time::ProfilerChan; use servo_util::time::ProfilerChan;
mod resize_rate_limiter;
/// The implementation of the layers-based compositor. /// The implementation of the layers-based compositor.
#[deriving(Clone)] #[deriving(Clone)]
pub struct CompositorTask { pub struct CompositorChan {
/// A channel on which messages can be sent to the compositor. /// A channel on which messages can be sent to the compositor.
chan: SharedChan<Msg>, chan: SharedChan<Msg>,
} }
impl CompositorInterface for CompositorTask { /// Implementation of the abstract `ScriptListener` interface.
impl ScriptListener for CompositorChan {
fn set_ready_state(&self, ready_state: ReadyState) { fn set_ready_state(&self, ready_state: ReadyState) {
let msg = ChangeReadyState(ready_state); let msg = ChangeReadyState(ready_state);
self.chan.send(msg); self.chan.send(msg);
} }
} }
impl CompositorTask { /// Implementation of the abstract `RenderListener` interface.
/// Starts the compositor. Returns an interface that can be used to communicate with the impl RenderListener for CompositorChan {
/// compositor and a port which allows notification when the compositor shuts down. fn get_gl_context(&self) -> AzGLContext {
pub fn new(script_chan: SharedChan<ScriptMsg>, profiler_chan: ProfilerChan) let (port, chan) = comm::stream();
-> (CompositorTask, Port<()>) { self.chan.send(GetGLContext(chan));
let script_chan = Cell(script_chan); port.recv()
let (shutdown_port, shutdown_chan) = stream(); }
let shutdown_chan = Cell(shutdown_chan); fn paint(&self, layer_buffer_set: LayerBufferSet, new_size: Size2D<uint>) {
self.chan.send(Paint(layer_buffer_set, new_size))
}
fn set_render_state(&self, render_state: RenderState) {
self.chan.send(ChangeRenderState(render_state))
}
}
let chan: Chan<Msg> = do on_osmain |port| { impl CompositorChan {
debug!("preparing to enter main loop"); pub fn new(chan: Chan<Msg>) -> CompositorChan {
run_main_loop(port, CompositorChan {
script_chan.take(),
shutdown_chan.take(),
profiler_chan.clone());
};
let task = CompositorTask {
chan: SharedChan::new(chan), chan: SharedChan::new(chan),
}; }
(task, shutdown_port) }
pub fn send(&self, msg: Msg) {
self.chan.send(msg);
} }
} }
@ -84,6 +84,8 @@ pub enum Msg {
ChangeReadyState(ReadyState), ChangeReadyState(ReadyState),
/// Alerts the compositor to the current status of rendering. /// Alerts the compositor to the current status of rendering.
ChangeRenderState(RenderState), ChangeRenderState(RenderState),
/// Sets the channel to the current layout task
SetLayoutChan(LayoutChan),
} }
/// Azure surface wrapping to work with the layers infrastructure. /// Azure surface wrapping to work with the layers infrastructure.
@ -111,13 +113,43 @@ impl ImageData for AzureDrawTargetImageData {
} }
} }
fn run_main_loop(port: Port<Msg>, pub struct CompositorTask {
script_chan: SharedChan<ScriptMsg>, port: Port<Msg>,
shutdown_chan: Chan<()>, profiler_chan: ProfilerChan,
profiler_chan: ProfilerChan) { shutdown_chan: SharedChan<()>,
}
impl CompositorTask {
pub fn new(port: Port<Msg>,
profiler_chan: ProfilerChan,
shutdown_chan: Chan<()>)
-> CompositorTask {
CompositorTask {
port: port,
profiler_chan: profiler_chan,
shutdown_chan: SharedChan::new(shutdown_chan),
}
}
/// Starts the compositor. Returns an interface that can be used to communicate with the
/// compositor
pub fn create_compositor_task(port: Port<Msg>,
profiler_chan: ProfilerChan,
shutdown_chan: Chan<()>) {
let port = Cell(port);
let shutdown_chan = Cell(shutdown_chan);
do on_osmain {
let compositor_task = CompositorTask::new(port.take(),
profiler_chan.clone(),
shutdown_chan.take());
debug!("preparing to enter main loop");
compositor_task.run_main_loop();
};
}
fn run_main_loop(&self) {
let app: Application = ApplicationMethods::new(); let app: Application = ApplicationMethods::new();
let window: @mut Window = WindowMethods::new(&app); let window: @mut Window = WindowMethods::new(&app);
let resize_rate_limiter = @mut ResizeRateLimiter(script_chan.clone());
// Create an initial layer tree. // Create an initial layer tree.
// //
@ -138,9 +170,47 @@ fn run_main_loop(port: Port<Msg>,
// Keeps track of the current zoom factor // Keeps track of the current zoom factor
let world_zoom = @mut 1f32; let world_zoom = @mut 1f32;
let check_for_messages: @fn() = || { let update_layout_callbacks: @fn(LayoutChan) = |layout_chan: LayoutChan| {
// Periodically check if the script task responded to our last resize event let layout_chan_clone = layout_chan.clone();
resize_rate_limiter.check_resize_response(); // Hook the windowing system's resize callback up to the resize rate limiter.
do window.set_resize_callback |width, height| {
debug!("osmain: window resized to %ux%u", width, height);
*window_size = Size2D(width, height);
layout_chan_clone.chan.send(RouteScriptMsg(SendEventMsg(ResizeEvent(width, height))));
}
let layout_chan_clone = layout_chan.clone();
// When the user enters a new URL, load it.
do window.set_load_url_callback |url_string| {
debug!("osmain: loading URL `%s`", url_string);
layout_chan_clone.chan.send(RouteScriptMsg(LoadMsg(url::make_url(url_string.to_str(), None))));
}
let layout_chan_clone = layout_chan.clone();
// When the user triggers a mouse event, perform appropriate hit testing
do window.set_mouse_callback |window_mouse_event: WindowMouseEvent| {
let event: Event;
let world_mouse_point = |layer_mouse_point: Point2D<f32>| {
layer_mouse_point + *world_offset
};
match window_mouse_event {
WindowClickEvent(button, layer_mouse_point) => {
event = ClickEvent(button, world_mouse_point(layer_mouse_point));
}
WindowMouseDownEvent(button, layer_mouse_point) => {
event = MouseDownEvent(button, world_mouse_point(layer_mouse_point));
}
WindowMouseUpEvent(button, layer_mouse_point) => {
event = MouseUpEvent(button, world_mouse_point(layer_mouse_point));
}
}
layout_chan_clone.chan.send(RouteScriptMsg(SendEventMsg(event)));
}
};
let check_for_messages: @fn(&Port<Msg>) = |port: &Port<Msg>| {
// Handle messages // Handle messages
while port.peek() { while port.peek() {
match port.recv() { match port.recv() {
@ -149,6 +219,10 @@ fn run_main_loop(port: Port<Msg>,
ChangeReadyState(ready_state) => window.set_ready_state(ready_state), ChangeReadyState(ready_state) => window.set_ready_state(ready_state),
ChangeRenderState(render_state) => window.set_render_state(render_state), ChangeRenderState(render_state) => window.set_render_state(render_state),
SetLayoutChan(layout_chan) => {
update_layout_callbacks(layout_chan);
}
GetGLContext(chan) => chan.send(current_gl_context()), GetGLContext(chan) => chan.send(current_gl_context()),
Paint(new_layer_buffer_set, new_size) => { Paint(new_layer_buffer_set, new_size) => {
@ -211,6 +285,7 @@ fn run_main_loop(port: Port<Msg>,
} }
}; };
let profiler_chan = self.profiler_chan.clone();
do window.set_composite_callback { do window.set_composite_callback {
do profile(time::CompositingCategory, profiler_chan.clone()) { do profile(time::CompositingCategory, profiler_chan.clone()) {
debug!("compositor: compositing"); debug!("compositor: compositing");
@ -224,43 +299,6 @@ fn run_main_loop(port: Port<Msg>,
window.present(); window.present();
} }
// Hook the windowing system's resize callback up to the resize rate limiter.
do window.set_resize_callback |width, height| {
debug!("osmain: window resized to %ux%u", width, height);
*window_size = Size2D(width, height);
resize_rate_limiter.window_resized(width, height)
}
let script_chan_clone = script_chan.clone();
// When the user enters a new URL, load it.
do window.set_load_url_callback |url_string| {
debug!("osmain: loading URL `%s`", url_string);
script_chan_clone.send(LoadMsg(url::make_url(url_string.to_str(), None)))
}
let script_chan_clone = script_chan.clone();
// When the user triggers a mouse event, perform appropriate hit testing
do window.set_mouse_callback |window_mouse_event: WindowMouseEvent| {
let event: Event;
let world_mouse_point = |layer_mouse_point: Point2D<f32>| {
layer_mouse_point + *world_offset
};
match window_mouse_event {
WindowClickEvent(button, layer_mouse_point) => {
event = ClickEvent(button, world_mouse_point(layer_mouse_point));
}
WindowMouseDownEvent(button, layer_mouse_point) => {
event = MouseDownEvent(button, world_mouse_point(layer_mouse_point));
}
WindowMouseUpEvent(button, layer_mouse_point) => {
event = MouseUpEvent(button, world_mouse_point(layer_mouse_point));
}
}
script_chan_clone.send(SendEventMsg(event));
}
// When the user scrolls, move the layer around. // When the user scrolls, move the layer around.
do window.set_scroll_callback |delta| { do window.set_scroll_callback |delta| {
// FIXME (Rust #2528): Can't use `-=`. // FIXME (Rust #2528): Can't use `-=`.
@ -329,46 +367,25 @@ fn run_main_loop(port: Port<Msg>,
window.set_needs_display() window.set_needs_display()
} }
// Enter the main event loop. // Enter the main event loop.
while !*done { while !*done {
// Check for new messages coming from the rendering task. // Check for new messages coming from the rendering task.
check_for_messages(); check_for_messages(&self.port);
// Check for messages coming from the windowing system. // Check for messages coming from the windowing system.
window.check_loop(); window.check_loop();
} }
shutdown_chan.send(()) self.shutdown_chan.send(())
}
/// Implementation of the abstract `Compositor` interface.
impl Compositor for CompositorTask {
fn get_gl_context(&self) -> AzGLContext {
let (port, chan) = comm::stream();
self.chan.send(GetGLContext(chan));
port.recv()
}
fn paint(&self, layer_buffer_set: LayerBufferSet, new_size: Size2D<uint>) {
self.chan.send(Paint(layer_buffer_set, new_size))
}
fn set_render_state(&self, render_state: RenderState) {
self.chan.send(ChangeRenderState(render_state))
} }
} }
/// A function for spawning into the platform's main thread. /// A function for spawning into the platform's main thread.
fn on_osmain<T: Owned>(f: ~fn(port: Port<T>)) -> Chan<T> { fn on_osmain(f: ~fn()) {
let (setup_port, setup_chan) = comm::stream();
// FIXME: rust#6399 // FIXME: rust#6399
let mut main_task = task::task(); let mut main_task = task::task();
main_task.sched_mode(task::PlatformThread); main_task.sched_mode(task::PlatformThread);
do main_task.spawn { do main_task.spawn {
let (port, chan) = comm::stream(); f();
setup_chan.send(chan);
f(port);
} }
setup_port.recv()
} }

View file

@ -7,20 +7,20 @@
/// before sending the next. If the window is resized multiple times before an event is handled /// before sending the next. If the window is resized multiple times before an event is handled
/// then some events will never be sent. /// then some events will never be sent.
use core::comm::{Port, SharedChan}; use core::comm::{Port};
use script::dom::event::ResizeEvent; use script::dom::event::ResizeEvent;
use script::script_task::{ScriptMsg, SendEventMsg}; use script::script_task::{ScriptChan, ScriptMsg, SendEventMsg};
pub struct ResizeRateLimiter { pub struct ResizeRateLimiter {
/// The channel we send resize events on /// The channel we send resize events on
priv script_chan: SharedChan<ScriptMsg>, priv script_chan: ScriptChan,
/// The port we are waiting on for a response to the last resize event /// The port we are waiting on for a response to the last resize event
priv last_response_port: Option<Port<()>>, priv last_response_port: Option<Port<()>>,
/// The next window resize event we should fire /// The next window resize event we should fire
priv next_resize_event: Option<(uint, uint)> priv next_resize_event: Option<(uint, uint)>
} }
pub fn ResizeRateLimiter(script_chan: SharedChan<ScriptMsg>) -> ResizeRateLimiter { pub fn ResizeRateLimiter(script_chan: ScriptChan) -> ResizeRateLimiter {
ResizeRateLimiter { ResizeRateLimiter {
script_chan: script_chan, script_chan: script_chan,
last_response_port: None, last_response_port: None,

View file

@ -2,101 +2,116 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use compositing::CompositorTask; use compositing::{CompositorChan, SetLayoutChan};
use layout::layout_task; use layout::layout_task;
use core::cell::Cell; use core::cell::Cell;
use core::comm::{Port, SharedChan}; use core::comm::Port;
use gfx::opts::Opts; use gfx::opts::Opts;
use gfx::render_task::RenderTask; use gfx::render_task::RenderChan;
use gfx::render_task; use gfx::render_task;
use script::compositor_interface::{CompositorInterface, ReadyState}; use script::compositor_interface::{ScriptListener, ReadyState};
use script::engine_interface::{EngineTask, ExitMsg, LoadUrlMsg, Msg}; use script::engine_interface::{EngineChan, ExitMsg, LoadUrlMsg, Msg};
use script::layout_interface::LayoutTask; use script::layout_interface::LayoutChan;
use script::layout_interface; use script::layout_interface;
use script::script_task::{ExecuteMsg, LoadMsg, ScriptMsg, ScriptTask}; use script::script_task::{ExecuteMsg, LoadMsg, ScriptMsg, ScriptContext, ScriptChan};
use script::script_task; use script::script_task;
use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient}; use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
use servo_net::resource_task::ResourceTask; use servo_net::resource_task::ResourceTask;
use servo_net::resource_task; use servo_net::resource_task;
use servo_util::time::{ProfilerChan, ProfilerPort, ProfilerTask, ForcePrintMsg}; use servo_util::time::{ProfilerChan, ForcePrintMsg};
pub struct Engine { pub struct Engine {
request_port: Port<Msg>, request_port: Port<Msg>,
compositor: CompositorTask, compositor_chan: CompositorChan,
render_task: RenderTask, render_chan: RenderChan,
resource_task: ResourceTask, resource_task: ResourceTask,
image_cache_task: ImageCacheTask, image_cache_task: ImageCacheTask,
layout_task: LayoutTask, layout_chan: LayoutChan,
script_task: ScriptTask, script_chan: ScriptChan,
profiler_task: ProfilerTask, profiler_chan: ProfilerChan,
} }
impl Drop for Engine { impl Drop for Engine {
fn finalize(&self) { fn finalize(&self) {
self.profiler_task.chan.send(ForcePrintMsg); self.profiler_chan.send(ForcePrintMsg);
} }
} }
impl Engine { impl Engine {
pub fn start(compositor: CompositorTask, pub fn start(compositor_chan: CompositorChan,
opts: &Opts, opts: &Opts,
script_port: Port<ScriptMsg>,
script_chan: SharedChan<ScriptMsg>,
resource_task: ResourceTask, resource_task: ResourceTask,
image_cache_task: ImageCacheTask, image_cache_task: ImageCacheTask,
profiler_port: ProfilerPort,
profiler_chan: ProfilerChan) profiler_chan: ProfilerChan)
-> EngineTask { -> EngineChan {
let (script_port, script_chan) = (Cell(script_port), Cell(script_chan)); macro_rules! closure_stream(
let (engine_port, engine_chan) = comm::stream(); ($Msg:ty, $Chan:ident) => (
let (engine_port, engine_chan) = (Cell(engine_port), SharedChan::new(engine_chan)); {
let engine_chan_clone = engine_chan.clone(); let (port, chan) = comm::stream::<$Msg>();
let compositor = Cell(compositor); (Cell(port), $Chan::new(chan))
let profiler_port = Cell(profiler_port); }
);
)
// 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) = closure_stream!(render_task::Msg, RenderChan);
compositor_chan.send(SetLayoutChan(layout_chan.clone()));
let compositor_chan = Cell(compositor_chan);
let opts = Cell(copy *opts); let opts = Cell(copy *opts);
{
let engine_chan = engine_chan.clone();
do task::spawn { do task::spawn {
let compositor = compositor.take(); let compositor_chan = compositor_chan.take();
let render_task = RenderTask::new(compositor.clone(), render_task::create_render_task(render_port.take(),
compositor_chan.clone(),
opts.with_ref(|o| copy *o), opts.with_ref(|o| copy *o),
profiler_chan.clone()); profiler_chan.clone());
let opts = opts.take(); let opts = opts.take();
let profiler_task = ProfilerTask::new(profiler_port.take(), layout_task::create_layout_task(layout_port.take(),
profiler_chan.clone(), script_chan.clone(),
opts.profiler_period); render_chan.clone(),
let layout_task = layout_task::create_layout_task(render_task.clone(),
image_cache_task.clone(), image_cache_task.clone(),
opts, opts,
profiler_task.chan.clone()); profiler_chan.clone());
let compositor_clone = compositor.clone(); let compositor_chan_clone = compositor_chan.clone();
let script_task = ScriptTask::new(script_port.take(), ScriptContext::create_script_context(layout_chan.clone(),
script_chan.take(), script_port.take(),
engine_chan_clone.clone(), script_chan.clone(),
engine_chan.clone(),
|msg: ReadyState| { |msg: ReadyState| {
compositor_clone.set_ready_state(msg) compositor_chan_clone.set_ready_state(msg)
}, },
layout_task.clone(),
resource_task.clone(), resource_task.clone(),
image_cache_task.clone()); image_cache_task.clone());
Engine { Engine {
request_port: engine_port.take(), request_port: engine_port.take(),
compositor: compositor.clone(), compositor_chan: compositor_chan.clone(),
render_task: render_task, render_chan: render_chan.clone(),
resource_task: resource_task.clone(), resource_task: resource_task.clone(),
image_cache_task: image_cache_task.clone(), image_cache_task: image_cache_task.clone(),
layout_task: layout_task, layout_chan: layout_chan.clone(),
script_task: script_task, script_chan: script_chan.clone(),
profiler_task: profiler_task, profiler_chan: profiler_chan.clone(),
}.run(); }.run();
} }
engine_chan.clone() }
engine_chan
} }
fn run(&self) { fn run(&self) {
@ -109,20 +124,20 @@ impl Engine {
match request { match request {
LoadUrlMsg(url) => { LoadUrlMsg(url) => {
if url.path.ends_with(".js") { if url.path.ends_with(".js") {
self.script_task.chan.send(ExecuteMsg(url)) self.script_chan.send(ExecuteMsg(url))
} else { } else {
self.script_task.chan.send(LoadMsg(url)) self.script_chan.send(LoadMsg(url))
} }
return true return true
} }
ExitMsg(sender) => { ExitMsg(sender) => {
self.script_task.chan.send(script_task::ExitMsg); self.script_chan.send(script_task::ExitMsg);
self.layout_task.chan.send(layout_interface::ExitMsg); self.layout_chan.send(layout_interface::ExitMsg);
let (response_port, response_chan) = comm::stream(); let (response_port, response_chan) = comm::stream();
self.render_task.channel.send(render_task::ExitMsg(response_chan)); self.render_chan.send(render_task::ExitMsg(response_chan));
response_port.recv(); response_port.recv();
self.image_cache_task.exit(); self.image_cache_task.exit();

View file

@ -13,11 +13,10 @@ use layout::box_builder::LayoutTreeBuilder;
use layout::context::LayoutContext; use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, FlowDisplayListBuilderMethods}; use layout::display_list_builder::{DisplayListBuilder, FlowDisplayListBuilderMethods};
use layout::flow::FlowContext; use layout::flow::FlowContext;
use util::task::spawn_listener;
use core::cast::transmute; use core::cast::transmute;
use core::cell::Cell; use core::cell::Cell;
use core::comm::{Chan, Port, SharedChan}; use core::comm::{Chan, Port};
use geom::point::Point2D; use geom::point::Point2D;
use geom::rect::Rect; use geom::rect::Rect;
use geom::size::Size2D; use geom::size::Size2D;
@ -26,7 +25,7 @@ use gfx::font_context::FontContext;
use gfx::geometry::Au; use gfx::geometry::Au;
use gfx::opts::Opts; use gfx::opts::Opts;
use gfx::render_layers::RenderLayer; use gfx::render_layers::RenderLayer;
use gfx::render_task::{RenderMsg, RenderTask}; use gfx::render_task::{RenderMsg, RenderChan};
use newcss::select::SelectCtx; use newcss::select::SelectCtx;
use newcss::stylesheet::Stylesheet; use newcss::stylesheet::Stylesheet;
use newcss::types::OriginAuthor; use newcss::types::OriginAuthor;
@ -35,10 +34,10 @@ use script::dom::node::{AbstractNode, LayoutView};
use script::layout_interface::{AddStylesheetMsg, ContentBoxQuery}; use script::layout_interface::{AddStylesheetMsg, ContentBoxQuery};
use script::layout_interface::{HitTestQuery, ContentBoxResponse, HitTestResponse}; use script::layout_interface::{HitTestQuery, ContentBoxResponse, HitTestResponse};
use script::layout_interface::{ContentBoxesQuery, ContentBoxesResponse, ExitMsg, LayoutQuery}; use script::layout_interface::{ContentBoxesQuery, ContentBoxesResponse, ExitMsg, LayoutQuery};
use script::layout_interface::{LayoutResponse, LayoutTask, MatchSelectorsDocumentDamage, Msg}; use script::layout_interface::{LayoutResponse, MatchSelectorsDocumentDamage, Msg};
use script::layout_interface::{QueryMsg, Reflow, ReflowDocumentDamage, ReflowForDisplay}; use script::layout_interface::{QueryMsg, RouteScriptMsg, Reflow, ReflowDocumentDamage};
use script::layout_interface::{ReflowMsg}; use script::layout_interface::{ReflowForDisplay, ReflowMsg};
use script::script_task::{ReflowCompleteMsg, ScriptMsg, SendEventMsg}; use script::script_task::{ReflowCompleteMsg, ScriptChan, ScriptMsg, SendEventMsg};
use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg}; use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg};
use servo_net::local_image_cache::LocalImageCache; use servo_net::local_image_cache::LocalImageCache;
use servo_util::tree::{TreeNodeRef, TreeUtils}; use servo_util::tree::{TreeNodeRef, TreeUtils};
@ -46,30 +45,30 @@ use servo_util::time::{ProfilerChan, profile, time};
use servo_util::time; use servo_util::time;
use std::net::url::Url; use std::net::url::Url;
pub fn create_layout_task(render_task: RenderTask, pub fn create_layout_task(port: Port<Msg>,
script_chan: ScriptChan,
render_chan: RenderChan,
img_cache_task: ImageCacheTask, img_cache_task: ImageCacheTask,
opts: Opts, opts: Opts,
profiler_chan: ProfilerChan) profiler_chan: ProfilerChan) {
-> LayoutTask { let port = Cell(port);
let chan = do spawn_listener::<Msg> |from_script| { do spawn {
let mut layout = Layout::new(render_task.clone(), let mut layout = Layout::new(port.take(),
script_chan.clone(),
render_chan.clone(),
img_cache_task.clone(), img_cache_task.clone(),
from_script,
&opts, &opts,
profiler_chan.clone()); profiler_chan.clone());
layout.start(); layout.start();
}; };
LayoutTask {
chan: SharedChan::new(chan),
}
} }
struct Layout { struct Layout {
render_task: RenderTask, port: Port<Msg>,
script_chan: ScriptChan,
render_chan: RenderChan,
image_cache_task: ImageCacheTask, image_cache_task: ImageCacheTask,
local_image_cache: @mut LocalImageCache, local_image_cache: @mut LocalImageCache,
from_script: Port<Msg>,
font_ctx: @mut FontContext, font_ctx: @mut FontContext,
doc_url: Option<Url>, doc_url: Option<Url>,
screen_size: Option<Size2D<Au>>, screen_size: Option<Size2D<Au>>,
@ -82,19 +81,21 @@ struct Layout {
} }
impl Layout { impl Layout {
fn new(render_task: RenderTask, fn new(port: Port<Msg>,
script_chan: ScriptChan,
render_chan: RenderChan,
image_cache_task: ImageCacheTask, image_cache_task: ImageCacheTask,
from_script: Port<Msg>,
opts: &Opts, opts: &Opts,
profiler_chan: ProfilerChan) profiler_chan: ProfilerChan)
-> Layout { -> Layout {
let fctx = @mut FontContext::new(opts.render_backend, true, profiler_chan.clone()); let fctx = @mut FontContext::new(opts.render_backend, true, profiler_chan.clone());
Layout { Layout {
render_task: render_task, port: port,
script_chan: script_chan,
render_chan: render_chan,
image_cache_task: image_cache_task.clone(), image_cache_task: image_cache_task.clone(),
local_image_cache: @mut LocalImageCache(image_cache_task), local_image_cache: @mut LocalImageCache(image_cache_task),
from_script: from_script,
font_ctx: fctx, font_ctx: fctx,
doc_url: None, doc_url: None,
screen_size: None, screen_size: None,
@ -125,7 +126,7 @@ impl Layout {
} }
fn handle_request(&mut self) -> bool { fn handle_request(&mut self) -> bool {
match self.from_script.recv() { match self.port.recv() {
AddStylesheetMsg(sheet) => self.handle_add_stylesheet(sheet), AddStylesheetMsg(sheet) => self.handle_add_stylesheet(sheet),
ReflowMsg(data) => { ReflowMsg(data) => {
let data = Cell(data); let data = Cell(data);
@ -137,9 +138,12 @@ impl Layout {
QueryMsg(query, chan) => { QueryMsg(query, chan) => {
let chan = Cell(chan); let chan = Cell(chan);
do profile(time::LayoutQueryCategory, self.profiler_chan.clone()) { do profile(time::LayoutQueryCategory, self.profiler_chan.clone()) {
self.handle_query(query, chan.take()) self.handle_query(query, chan.take());
} }
} }
RouteScriptMsg(script_msg) => {
self.route_script_msg(script_msg);
}
ExitMsg => { ExitMsg => {
debug!("layout: ExitMsg received"); debug!("layout: ExitMsg received");
return false return false
@ -248,7 +252,7 @@ impl Layout {
size: Size2D(root_size.width.to_px() as uint, root_size.height.to_px() as uint) size: Size2D(root_size.width.to_px() as uint, root_size.height.to_px() as uint)
}; };
self.render_task.channel.send(RenderMsg(render_layer)); self.render_chan.send(RenderMsg(render_layer));
} // time(layout: display list building) } // time(layout: display list building)
} }
@ -371,12 +375,18 @@ impl Layout {
} }
} }
// TODO(tkuehn): once there are multiple script tasks, this is where the layout task will
// determine which script task should receive the message. The prototype will need to change
fn route_script_msg(&self, script_msg: ScriptMsg) {
self.script_chan.send(script_msg);
}
// When images can't be loaded in time to display they trigger // When images can't be loaded in time to display they trigger
// this callback in some task somewhere. This will send a message // this callback in some task somewhere. This will send a message
// to the script task, and ultimately cause the image to be // to the script task, and ultimately cause the image to be
// re-requested. We probably don't need to go all the way back to // re-requested. We probably don't need to go all the way back to
// the script task for this. // the script task for this.
fn make_on_image_available_cb(&self, script_chan: SharedChan<ScriptMsg>) fn make_on_image_available_cb(&self, script_chan: ScriptChan)
-> @fn() -> ~fn(ImageResponseMsg) { -> @fn() -> ~fn(ImageResponseMsg) {
// This has a crazy signature because the image cache needs to // This has a crazy signature because the image cache needs to
// make multiple copies of the callback, and the dom event // make multiple copies of the callback, and the dom event

View file

@ -33,14 +33,14 @@ extern mod core_graphics;
#[cfg(target_os="macos")] #[cfg(target_os="macos")]
extern mod core_text; extern mod core_text;
use compositing::CompositorTask; use compositing::{CompositorChan, CompositorTask};
use engine::Engine; use engine::Engine;
use script::engine_interface::{ExitMsg, LoadUrlMsg}; use script::engine_interface::{ExitMsg, LoadUrlMsg};
use core::comm::SharedChan;
use gfx::opts; use gfx::opts;
use servo_net::image_cache_task::ImageCacheTask; use servo_net::image_cache_task::ImageCacheTask;
use servo_net::resource_task::ResourceTask; use servo_net::resource_task::ResourceTask;
use servo_util::time::{Profiler, ProfilerChan};
pub use gfx::opts::Opts; pub use gfx::opts::Opts;
pub use gfx::text; pub use gfx::text;
@ -87,33 +87,31 @@ fn main() {
} }
fn run(opts: &Opts) { fn run(opts: &Opts) {
// Create the script channel. let (shutdown_port, shutdown_chan) = comm::stream();
let (script_port, script_chan) = comm::stream();
let script_chan = SharedChan::new(script_chan);
// Create the profiler channel. // Create the profiler channel.
let (profiler_port, profiler_chan) = comm::stream(); let (profiler_port, profiler_chan) = comm::stream();
let profiler_chan = SharedChan::new(profiler_chan); let profiler_chan = ProfilerChan::new(profiler_chan);
Profiler::create_profiler(profiler_port, opts.profiler_period);
// Create the compositor. // Create the compositor.
let (compositor, shutdown_port) = CompositorTask::new(script_chan.clone(), let (compositor_port, compositor_chan) = comm::stream();
profiler_chan.clone()); let compositor_chan = CompositorChan::new(compositor_chan);
CompositorTask::create_compositor_task(compositor_port, profiler_chan.clone(), shutdown_chan);
// Create a Servo instance. // Create a Servo instance.
let resource_task = ResourceTask(); let resource_task = ResourceTask();
let image_cache_task = ImageCacheTask(resource_task.clone()); let image_cache_task = ImageCacheTask(resource_task.clone());
let engine_task = Engine::start(compositor.clone(), let engine_chan = Engine::start(compositor_chan.clone(),
opts, opts,
script_port,
script_chan,
resource_task, resource_task,
image_cache_task, image_cache_task,
profiler_port, profiler_chan.clone());
profiler_chan);
// Send the URL command to the engine task. // Send the URL command to the engine task.
for opts.urls.each |filename| { for opts.urls.each |filename| {
engine_task.send(LoadUrlMsg(make_url(copy *filename, None))) engine_chan.chan.send(LoadUrlMsg(make_url(copy *filename, None)))
} }
// Wait for the compositor to shut down. // Wait for the compositor to shut down.
@ -122,7 +120,7 @@ fn run(opts: &Opts) {
// Shut the engine down. // Shut the engine down.
debug!("master: Shut down"); debug!("master: Shut down");
let (exit_response_from_engine, exit_chan) = comm::stream(); let (exit_response_from_engine, exit_chan) = comm::stream();
engine_task.send(ExitMsg(exit_chan)); engine_chan.chan.send(ExitMsg(exit_chan));
exit_response_from_engine.recv(); exit_response_from_engine.recv();
} }

View file

@ -14,6 +14,6 @@ pub enum ReadyState {
FinishedLoading, FinishedLoading,
} }
pub trait CompositorInterface : Clone { pub trait ScriptListener : Clone {
fn set_ready_state(&self, ReadyState); fn set_ready_state(&self, ReadyState);
} }

View file

@ -10,7 +10,7 @@ use dom::bindings::utils::{DOMString, ErrorResult, WrapperCache};
use geom::point::Point2D; use geom::point::Point2D;
pub enum Event { pub enum Event {
ResizeEvent(uint, uint, comm::Chan<()>), ResizeEvent(uint, uint),
ReflowEvent, ReflowEvent,
ClickEvent(uint, Point2D<f32>), ClickEvent(uint, Point2D<f32>),
MouseDownEvent(uint, Point2D<f32>), MouseDownEvent(uint, Point2D<f32>),

View file

@ -6,9 +6,9 @@ use dom::bindings::utils::WrapperCache;
use dom::bindings::window; use dom::bindings::window;
use layout_interface::ReflowForScriptQuery; use layout_interface::ReflowForScriptQuery;
use script_task::{ExitMsg, FireTimerMsg, ScriptMsg, ScriptContext}; use script_task::{ExitMsg, FireTimerMsg, ScriptChan, ScriptContext};
use core::comm::{Chan, SharedChan}; use core::comm::Chan;
use js::jsapi::JSVal; use js::jsapi::JSVal;
use std::timer; use std::timer;
use std::uv_global_loop; use std::uv_global_loop;
@ -23,7 +23,7 @@ pub enum TimerControlMsg {
// only used for querying layout from arbitrary script. // only used for querying layout from arbitrary script.
pub struct Window { pub struct Window {
timer_chan: Chan<TimerControlMsg>, timer_chan: Chan<TimerControlMsg>,
script_chan: SharedChan<ScriptMsg>, script_chan: ScriptChan,
script_context: *mut ScriptContext, script_context: *mut ScriptContext,
wrapper: WrapperCache wrapper: WrapperCache
} }
@ -88,9 +88,9 @@ pub impl Window {
} }
} }
pub fn new(script_chan: SharedChan<ScriptMsg>, script_context: *mut ScriptContext) pub fn new(script_chan: ScriptChan, script_context: *mut ScriptContext)
-> @mut Window { -> @mut Window {
let script_chan_copy = script_chan.clone(); let script_chan_clone = script_chan.clone();
let win = @mut Window { let win = @mut Window {
wrapper: WrapperCache::new(), wrapper: WrapperCache::new(),
script_chan: script_chan, script_chan: script_chan,
@ -100,8 +100,8 @@ pub impl Window {
loop { loop {
match timer_port.recv() { match timer_port.recv() {
TimerMessage_Close => break, TimerMessage_Close => break,
TimerMessage_Fire(td) => script_chan_copy.send(FireTimerMsg(td)), TimerMessage_Fire(td) => script_chan_clone.chan.send(FireTimerMsg(td)),
TimerMessage_TriggerExit => script_chan_copy.send(ExitMsg), TimerMessage_TriggerExit => script_chan_clone.chan.send(ExitMsg),
} }
} }
} }

View file

@ -8,7 +8,21 @@
use core::comm::{Chan, SharedChan}; use core::comm::{Chan, SharedChan};
use std::net::url::Url; use std::net::url::Url;
pub type EngineTask = SharedChan<Msg>; #[deriving(Clone)]
pub struct EngineChan {
chan: SharedChan<Msg>,
}
impl EngineChan {
pub fn new(chan: Chan<Msg>) -> EngineChan {
EngineChan {
chan: SharedChan::new(chan),
}
}
pub fn send(&self, msg: Msg) {
self.chan.send(msg);
}
}
pub enum Msg { pub enum Msg {
LoadUrlMsg(Url), LoadUrlMsg(Url),

View file

@ -7,7 +7,7 @@
/// from layout. /// from layout.
use dom::node::{AbstractNode, ScriptView, LayoutView}; use dom::node::{AbstractNode, ScriptView, LayoutView};
use script_task::ScriptMsg; use script_task::{ScriptMsg, ScriptChan};
use core::comm::{Chan, SharedChan}; use core::comm::{Chan, SharedChan};
use geom::rect::Rect; use geom::rect::Rect;
@ -32,6 +32,9 @@ pub enum Msg {
/// FIXME(pcwalton): As noted below, this isn't very type safe. /// FIXME(pcwalton): As noted below, this isn't very type safe.
QueryMsg(LayoutQuery, Chan<Result<LayoutResponse,()>>), QueryMsg(LayoutQuery, Chan<Result<LayoutResponse,()>>),
/// Routes a message (usually from the compositor) to the appropriate script task
RouteScriptMsg(ScriptMsg),
/// Requests that the layout task shut down and exit. /// Requests that the layout task shut down and exit.
ExitMsg, ExitMsg,
} }
@ -110,7 +113,7 @@ pub struct Reflow {
/// The URL of the page. /// The URL of the page.
url: Url, url: Url,
/// The channel through which messages can be sent back to the script task. /// The channel through which messages can be sent back to the script task.
script_chan: SharedChan<ScriptMsg>, script_chan: ScriptChan,
/// The current window size. /// The current window size.
window_size: Size2D<uint>, window_size: Size2D<uint>,
/// The channel that we send a notification to. /// The channel that we send a notification to.
@ -119,7 +122,17 @@ pub struct Reflow {
/// Encapsulates a channel to the layout task. /// Encapsulates a channel to the layout task.
#[deriving(Clone)] #[deriving(Clone)]
pub struct LayoutTask { pub struct LayoutChan {
chan: SharedChan<Msg>, chan: SharedChan<Msg>,
} }
impl LayoutChan {
pub fn new(chan: Chan<Msg>) -> LayoutChan {
LayoutChan {
chan: SharedChan::new(chan),
}
}
pub fn send(&self, msg: Msg) {
self.chan.send(msg);
}
}

View file

@ -13,11 +13,11 @@ use dom::event::{Event, ResizeEvent, ReflowEvent, ClickEvent, MouseDownEvent, Mo
use dom::node::{AbstractNode, ScriptView, define_bindings}; use dom::node::{AbstractNode, ScriptView, define_bindings};
use dom::window::Window; use dom::window::Window;
use layout_interface::{AddStylesheetMsg, DocumentDamage, DocumentDamageLevel, HitTestQuery}; use layout_interface::{AddStylesheetMsg, DocumentDamage, DocumentDamageLevel, HitTestQuery};
use layout_interface::{HitTestResponse, LayoutQuery, LayoutResponse, LayoutTask}; use layout_interface::{HitTestResponse, LayoutQuery, LayoutResponse, LayoutChan};
use layout_interface::{MatchSelectorsDocumentDamage, QueryMsg, Reflow, ReflowDocumentDamage}; use layout_interface::{MatchSelectorsDocumentDamage, QueryMsg, Reflow, ReflowDocumentDamage};
use layout_interface::{ReflowForDisplay, ReflowForScriptQuery, ReflowGoal, ReflowMsg}; use layout_interface::{ReflowForDisplay, ReflowForScriptQuery, ReflowGoal, ReflowMsg};
use layout_interface; use layout_interface;
use engine_interface::{EngineTask, LoadUrlMsg}; use engine_interface::{EngineChan, LoadUrlMsg};
use core::cast::transmute; use core::cast::transmute;
use core::cell::Cell; use core::cell::Cell;
@ -61,41 +61,21 @@ pub enum ScriptMsg {
} }
/// Encapsulates external communication with the script task. /// Encapsulates external communication with the script task.
pub struct ScriptTask { #[deriving(Clone)]
pub struct ScriptChan {
/// The channel used to send messages to the script task. /// The channel used to send messages to the script task.
chan: SharedChan<ScriptMsg>, chan: SharedChan<ScriptMsg>,
} }
impl ScriptTask { impl ScriptChan {
/// Creates a new script task. /// Creates a new script task.
pub fn new(script_port: Port<ScriptMsg>, pub fn new(chan: Chan<ScriptMsg>) -> ScriptChan {
script_chan: SharedChan<ScriptMsg>, ScriptChan {
engine_task: EngineTask, chan: SharedChan::new(chan)
//FIXME(rust #5192): workaround for lack of working ~Trait
compositor_task: ~fn(ReadyState),
layout_task: LayoutTask,
resource_task: ResourceTask,
image_cache_task: ImageCacheTask)
-> ScriptTask {
let (script_chan_copy, script_port) = (script_chan.clone(), Cell(script_port));
let compositor_task = Cell(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_task.clone(),
script_port.take(),
script_chan_copy.clone(),
engine_task.clone(),
compositor_task.take(),
resource_task.clone(),
image_cache_task.clone());
script_context.start();
} }
ScriptTask {
chan: script_chan
} }
pub fn send(&self, msg: ScriptMsg) {
self.chan.send(msg);
} }
} }
@ -112,7 +92,7 @@ pub struct Frame {
/// FIXME: Rename to `Page`, following WebKit? /// FIXME: Rename to `Page`, following WebKit?
pub struct ScriptContext { pub struct ScriptContext {
/// A handle to the layout task. /// A handle to the layout task.
layout_task: LayoutTask, layout_chan: LayoutChan,
/// A handle to the image cache task. /// A handle to the image cache task.
image_cache_task: ImageCacheTask, image_cache_task: ImageCacheTask,
/// A handle to the resource task. /// A handle to the resource task.
@ -125,10 +105,10 @@ pub struct ScriptContext {
script_port: Port<ScriptMsg>, script_port: Port<ScriptMsg>,
/// A channel for us to hand out when we want some other task to be able to send us script /// A channel for us to hand out when we want some other task to be able to send us script
/// messages. /// messages.
script_chan: SharedChan<ScriptMsg>, script_chan: ScriptChan,
/// For communicating load url messages to the engine /// For communicating load url messages to the engine
engine_task: EngineTask, engine_chan: EngineChan,
/// For communicating loading messages to the compositor /// For communicating loading messages to the compositor
compositor_task: ~fn(ReadyState), compositor_task: ~fn(ReadyState),
@ -180,10 +160,10 @@ impl Drop for ScriptContext {
impl ScriptContext { impl ScriptContext {
/// Creates a new script context. /// Creates a new script context.
pub fn new(layout_task: LayoutTask, pub fn new(layout_chan: LayoutChan,
script_port: Port<ScriptMsg>, script_port: Port<ScriptMsg>,
script_chan: SharedChan<ScriptMsg>, script_chan: ScriptChan,
engine_task: EngineTask, engine_chan: EngineChan,
compositor_task: ~fn(ReadyState), compositor_task: ~fn(ReadyState),
resource_task: ResourceTask, resource_task: ResourceTask,
img_cache_task: ImageCacheTask) img_cache_task: ImageCacheTask)
@ -200,7 +180,7 @@ impl ScriptContext {
}; };
let script_context = @mut ScriptContext { let script_context = @mut ScriptContext {
layout_task: layout_task, layout_chan: layout_chan,
image_cache_task: img_cache_task, image_cache_task: img_cache_task,
resource_task: resource_task, resource_task: resource_task,
@ -208,7 +188,7 @@ impl ScriptContext {
script_port: script_port, script_port: script_port,
script_chan: script_chan, script_chan: script_chan,
engine_task: engine_task, engine_chan: engine_chan,
compositor_task: compositor_task, compositor_task: compositor_task,
js_runtime: js_runtime, js_runtime: js_runtime,
@ -245,6 +225,30 @@ 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) {
let script_port = Cell(script_port);
let compositor_task = Cell(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();
}
}
/// Handles an incoming control message. /// Handles an incoming control message.
fn handle_msg(&mut self) -> bool { fn handle_msg(&mut self) -> bool {
match self.script_port.recv() { match self.script_port.recv() {
@ -325,7 +329,7 @@ impl ScriptContext {
frame.document.teardown(); frame.document.teardown();
} }
self.layout_task.chan.send(layout_interface::ExitMsg) self.layout_chan.send(layout_interface::ExitMsg)
} }
// tells the compositor when loading starts and finishes // tells the compositor when loading starts and finishes
@ -361,7 +365,7 @@ impl ScriptContext {
// in the script task. // in the script task.
loop { loop {
match html_parsing_result.style_port.recv() { match html_parsing_result.style_port.recv() {
Some(sheet) => self.layout_task.chan.send(AddStylesheetMsg(sheet)), Some(sheet) => self.layout_chan.send(AddStylesheetMsg(sheet)),
None => break, None => break,
} }
} }
@ -457,7 +461,7 @@ impl ScriptContext {
damage: replace(&mut self.damage, None).unwrap(), damage: replace(&mut self.damage, None).unwrap(),
}; };
self.layout_task.chan.send(ReflowMsg(reflow)) self.layout_chan.send(ReflowMsg(reflow))
} }
} }
@ -482,7 +486,7 @@ impl ScriptContext {
self.join_layout(); self.join_layout();
let (response_port, response_chan) = comm::stream(); let (response_port, response_chan) = comm::stream();
self.layout_task.chan.send(QueryMsg(query, response_chan)); self.layout_chan.send(QueryMsg(query, response_chan));
response_port.recv() response_port.recv()
} }
@ -511,7 +515,7 @@ impl ScriptContext {
/// TODO: Actually perform DOM event dispatch. /// TODO: Actually perform DOM event dispatch.
fn handle_event(&mut self, event: Event) { fn handle_event(&mut self, event: Event) {
match event { match event {
ResizeEvent(new_width, new_height, response_chan) => { ResizeEvent(new_width, new_height) => {
debug!("script got resize event: %u, %u", new_width, new_height); debug!("script got resize event: %u, %u", new_width, new_height);
self.window_size = Size2D(new_width, new_height); self.window_size = Size2D(new_width, new_height);
@ -525,8 +529,6 @@ impl ScriptContext {
if self.root_frame.is_some() { if self.root_frame.is_some() {
self.reflow(ReflowForDisplay) self.reflow(ReflowForDisplay)
} }
response_chan.send(())
} }
// FIXME(pcwalton): This reflows the entire document and is not incremental-y. // FIXME(pcwalton): This reflows the entire document and is not incremental-y.
@ -595,7 +597,7 @@ impl ScriptContext {
None => None None => None
}; };
let url = make_url(attr.value.clone(), current_url); let url = make_url(attr.value.clone(), current_url);
self.engine_task.send(LoadUrlMsg(url)); self.engine_chan.send(LoadUrlMsg(url));
} }
} }
} }

View file

@ -8,8 +8,22 @@ use core::cell::Cell;
use core::comm::{Port, SharedChan}; use core::comm::{Port, SharedChan};
use std::sort::tim_sort; use std::sort::tim_sort;
pub type ProfilerChan = SharedChan<ProfilerMsg>; // front-end representation of the profiler used to communicate with the profiler
pub type ProfilerPort = Port<ProfilerMsg>; #[deriving(Clone)]
pub struct ProfilerChan {
chan: SharedChan<ProfilerMsg>,
}
impl ProfilerChan {
pub fn new(chan: Chan<ProfilerMsg>) -> ProfilerChan {
ProfilerChan {
chan: SharedChan::new(chan),
}
}
pub fn send(&self, msg: ProfilerMsg) {
self.chan.send(msg);
}
}
#[deriving(Eq)] #[deriving(Eq)]
pub enum ProfilerCategory { pub enum ProfilerCategory {
@ -39,14 +53,9 @@ pub enum ProfilerMsg {
ForcePrintMsg, ForcePrintMsg,
} }
// front-end representation of the profiler used to communicate with the profiler context
pub struct ProfilerTask {
chan: ProfilerChan,
}
// back end of the profiler that handles data aggregation and performance metrics // back end of the profiler that handles data aggregation and performance metrics
pub struct ProfilerContext { pub struct Profiler {
port: ProfilerPort, port: Port<ProfilerMsg>,
buckets: ~[(ProfilerCategory, ~[f64])], buckets: ~[(ProfilerCategory, ~[f64])],
verbose: bool, verbose: bool,
period: f64, period: f64,
@ -54,7 +63,6 @@ pub struct ProfilerContext {
} }
impl ProfilerCategory { impl ProfilerCategory {
// convenience function to not have to cast every time // convenience function to not have to cast every time
pub fn num_buckets() -> uint { pub fn num_buckets() -> uint {
NUM_BUCKETS as uint NUM_BUCKETS as uint
@ -103,31 +111,21 @@ impl ProfilerCategory {
} }
} }
impl ProfilerTask { impl Profiler {
pub fn new(profiler_port: ProfilerPort, pub fn create_profiler(port: Port<ProfilerMsg>, period: Option<f64>) {
profiler_chan: ProfilerChan, let port = Cell(port);
period: Option<f64>)
-> ProfilerTask {
let profiler_port = Cell(profiler_port);
do spawn { do spawn {
let mut profiler_context = ProfilerContext::new(profiler_port.take(), period); let mut profiler = Profiler::new(port.take(), period);
profiler_context.start(); profiler.start();
}
} }
ProfilerTask { pub fn new(port: Port<ProfilerMsg>, period: Option<f64>) -> Profiler {
chan: profiler_chan
}
}
}
impl ProfilerContext {
pub fn new(port: ProfilerPort, period: Option<f64>) -> ProfilerContext {
let (verbose, period) = match period { let (verbose, period) = match period {
Some(period) => (true, period), Some(period) => (true, period),
None => (false, 0f64) None => (false, 0f64)
}; };
ProfilerContext { Profiler {
port: port, port: port,
buckets: ProfilerCategory::empty_buckets(), buckets: ProfilerCategory::empty_buckets(),
verbose: verbose, verbose: verbose,
@ -200,7 +198,7 @@ pub fn profile<T>(category: ProfilerCategory,
let val = callback(); let val = callback();
let end_time = precise_time_ns(); let end_time = precise_time_ns();
let ms = ((end_time - start_time) as f64 / 1000000f64); let ms = ((end_time - start_time) as f64 / 1000000f64);
profiler_chan.send(TimeMsg(category, ms)); profiler_chan.chan.send(TimeMsg(category, ms));
return val; return val;
} }

@ -1 +1 @@
Subproject commit 865f539114383a021822583801e8362faf916699 Subproject commit 09d2db847c11bcab7f1832d5daf5947a7c1384ee

@ -1 +1 @@
Subproject commit 453bf81e021008f5eba29b135f07f4529e6c8b2e Subproject commit 6f6b6fa95914fa6322f3277c803fd4921601cb90

@ -1 +1 @@
Subproject commit da248d3f5b3ed6d9e804c543563be8e34baf1673 Subproject commit d722188de3876ed748382965eb4f300fc1b78bf8