aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/components/gfx/compositor.rs4
-rw-r--r--src/components/gfx/render_task.rs133
-rw-r--r--src/components/main/compositing/mod.rs502
-rw-r--r--src/components/main/compositing/resize_rate_limiter.rs8
-rw-r--r--src/components/main/engine.rs161
-rw-r--r--src/components/main/layout/layout_task.rs65
-rw-r--r--src/components/main/platform/common/glut_windowing.rs1
-rwxr-xr-xsrc/components/main/servo.rc40
-rw-r--r--src/components/script/compositor_interface.rs4
-rw-r--r--src/components/script/dom/event.rs2
-rw-r--r--src/components/script/dom/window.rs14
-rw-r--r--src/components/script/engine_interface.rs16
-rw-r--r--src/components/script/layout_interface.rs19
-rw-r--r--src/components/script/script_task.rs96
-rw-r--r--src/components/util/time.rs90
m---------src/support/netsurfcss/libcss0
16 files changed, 615 insertions, 540 deletions
diff --git a/src/components/gfx/compositor.rs b/src/components/gfx/compositor.rs
index 91b03989da6..46e09800685 100644
--- a/src/components/gfx/compositor.rs
+++ b/src/components/gfx/compositor.rs
@@ -32,9 +32,9 @@ pub enum RenderState {
RenderingRenderState,
}
-/// The interface used to by the renderer to acquire draw targets for each rendered frame and
+/// 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 Compositor {
+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);
diff --git a/src/components/gfx/render_task.rs b/src/components/gfx/render_task.rs
index 1b5aa289f53..8cb63f885f1 100644
--- a/src/components/gfx/render_task.rs
+++ b/src/components/gfx/render_task.rs
@@ -5,7 +5,7 @@
// The task that handles all rendering/painting.
use azure::{AzFloat, AzGLContext};
-use compositor::{Compositor, IdleRenderState, RenderingRenderState};
+use compositor::{RenderListener, IdleRenderState, RenderingRenderState};
use font_context::FontContext;
use geom::matrix2d::Matrix2D;
use opts::Opts;
@@ -22,73 +22,85 @@ use servo_net::util::spawn_listener;
use servo_util::time::{ProfilerChan, profile};
use servo_util::time;
-pub enum Msg {
+pub enum Msg<C> {
+ AttachCompositorMsg(C),
RenderMsg(RenderLayer),
ExitMsg(Chan<()>),
}
-#[deriving(Clone)]
-pub struct RenderTask {
- channel: SharedChan<Msg>,
+pub struct RenderChan<C> {
+ chan: SharedChan<Msg<C>>,
}
-impl RenderTask {
- pub fn new<C:Compositor + Owned>(compositor: C,
- opts: Opts,
- profiler_chan: ProfilerChan)
- -> RenderTask {
- let compositor_cell = Cell(compositor);
- let opts_cell = Cell(opts);
- let (port, chan) = comm::stream();
- let port = Cell(port);
-
- do spawn {
- let compositor = compositor_cell.take();
- let share_gl_context = compositor.get_gl_context();
-
- // FIXME: Annoying three-cell dance here. We need one-shot closures.
- let opts = opts_cell.with_ref(|o| copy *o);
- let n_threads = opts.n_render_threads;
- let new_opts_cell = Cell(opts);
-
- let profiler_chan = profiler_chan.clone();
- let profiler_chan_copy = profiler_chan.clone();
-
- let thread_pool = do TaskPool::new(n_threads, Some(SingleThreaded)) {
- let opts_cell = Cell(new_opts_cell.with_ref(|o| copy *o));
- let profiler_chan = Cell(profiler_chan.clone());
-
- let f: ~fn(uint) -> ThreadRenderContext = |thread_index| {
- let opts = opts_cell.with_ref(|opts| copy *opts);
-
- ThreadRenderContext {
- thread_index: thread_index,
- font_ctx: @mut FontContext::new(opts.render_backend,
- false,
- profiler_chan.take()),
- opts: opts,
- }
- };
- f
- };
-
- // FIXME: rust/#5967
- let mut renderer = Renderer {
- port: port.take(),
- compositor: compositor,
- thread_pool: thread_pool,
- opts: opts_cell.take(),
- profiler_chan: profiler_chan_copy,
- share_gl_context: share_gl_context,
- };
-
- renderer.start();
+impl<C: RenderListener + Owned> Clone for RenderChan<C> {
+ pub fn clone(&self) -> RenderChan<C> {
+ RenderChan {
+ chan: self.chan.clone(),
}
+ }
+}
- RenderTask {
- channel: SharedChan::new(chan),
+impl<C: RenderListener + Owned> RenderChan<C> {
+ pub fn new(chan: Chan<Msg<C>>) -> RenderChan<C> {
+ RenderChan {
+ chan: SharedChan::new(chan),
}
}
+ pub fn send(&self, msg: Msg<C>) {
+ 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(compositor);
+ let opts_cell = Cell(opts);
+ let port = Cell(port);
+
+ do spawn {
+ let compositor = compositor_cell.take();
+ let share_gl_context = compositor.get_gl_context();
+
+ // FIXME: Annoying three-cell dance here. We need one-shot closures.
+ let opts = opts_cell.with_ref(|o| copy *o);
+ let n_threads = opts.n_render_threads;
+ let new_opts_cell = Cell(opts);
+
+ let profiler_chan = profiler_chan.clone();
+ let profiler_chan_copy = profiler_chan.clone();
+
+ let thread_pool = do TaskPool::new(n_threads, Some(SingleThreaded)) {
+ let opts_cell = Cell(new_opts_cell.with_ref(|o| copy *o));
+ let profiler_chan = Cell(profiler_chan.clone());
+
+ let f: ~fn(uint) -> ThreadRenderContext = |thread_index| {
+ let opts = opts_cell.with_ref(|opts| copy *opts);
+
+ ThreadRenderContext {
+ thread_index: thread_index,
+ font_ctx: @mut FontContext::new(opts.render_backend,
+ false,
+ profiler_chan.take()),
+ opts: opts,
+ }
+ };
+ f
+ };
+
+ // FIXME: rust/#5967
+ let mut renderer = Renderer {
+ port: port.take(),
+ compositor: compositor,
+ thread_pool: thread_pool,
+ opts: opts_cell.take(),
+ profiler_chan: profiler_chan_copy,
+ share_gl_context: share_gl_context,
+ };
+
+ renderer.start();
+ }
}
/// Data that needs to be kept around for each render thread.
@@ -99,7 +111,7 @@ priv struct ThreadRenderContext {
}
priv struct Renderer<C> {
- port: Port<Msg>,
+ port: Port<Msg<C>>,
compositor: C,
thread_pool: TaskPool<ThreadRenderContext>,
opts: Opts,
@@ -110,12 +122,13 @@ priv struct Renderer<C> {
share_gl_context: AzGLContext,
}
-impl<C: Compositor + Owned> Renderer<C> {
+impl<C: RenderListener + Owned> Renderer<C> {
fn start(&mut self) {
debug!("renderer: beginning rendering loop");
loop {
match self.port.recv() {
+ AttachCompositorMsg(compositor) => self.compositor = compositor,
RenderMsg(render_layer) => self.render(render_layer),
ExitMsg(response_ch) => {
response_ch.send(());
diff --git a/src/components/main/compositing/mod.rs b/src/components/main/compositing/mod.rs
index f7049f2d131..ba32b706c41 100644
--- a/src/components/main/compositing/mod.rs
+++ b/src/components/main/compositing/mod.rs
@@ -2,16 +2,15 @@
* 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::resize_rate_limiter::ResizeRateLimiter;
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::{WindowMouseDownEvent, WindowMouseUpEvent};
-use gfx::compositor::RenderState;
-use script::dom::event::{Event, ClickEvent, MouseDownEvent, MouseUpEvent};
-use script::compositor_interface::{ReadyState, CompositorInterface};
-use script::compositor_interface;
+use script::dom::event::{Event, ClickEvent, MouseDownEvent, MouseUpEvent, ResizeEvent};
+use script::compositor_interface::{ReadyState, ScriptListener};
+use script::script_task::{ScriptChan, SendEventMsg};
+use script::layout_interface::{LayoutChan, RouteScriptMsg};
use azure::azure_hl::{DataSourceSurface, DrawTarget, SourceSurfaceMethods, current_gl_context};
use azure::azure::AzGLContext;
@@ -22,7 +21,7 @@ use core::util;
use geom::matrix::identity;
use geom::point::Point2D;
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::{ImageData, WithDataFn};
use layers::layers::{TextureLayerKind, TextureLayer, TextureManager};
@@ -32,43 +31,44 @@ use servo_util::{time, url};
use servo_util::time::profile;
use servo_util::time::ProfilerChan;
-mod resize_rate_limiter;
-
/// The implementation of the layers-based compositor.
#[deriving(Clone)]
-pub struct CompositorTask {
+pub struct CompositorChan {
/// A channel on which messages can be sent to the compositor.
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) {
let msg = ChangeReadyState(ready_state);
self.chan.send(msg);
}
}
-impl CompositorTask {
- /// Starts the compositor. Returns an interface that can be used to communicate with the
- /// compositor and a port which allows notification when the compositor shuts down.
- pub fn new(script_chan: SharedChan<ScriptMsg>, profiler_chan: ProfilerChan)
- -> (CompositorTask, Port<()>) {
- let script_chan = Cell(script_chan);
- let (shutdown_port, shutdown_chan) = stream();
- let shutdown_chan = Cell(shutdown_chan);
-
- let chan: Chan<Msg> = do on_osmain |port| {
- debug!("preparing to enter main loop");
- run_main_loop(port,
- script_chan.take(),
- shutdown_chan.take(),
- profiler_chan.clone());
- };
+/// Implementation of the abstract `RenderListener` interface.
+impl RenderListener for CompositorChan {
+ 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))
+ }
+}
- let task = CompositorTask {
+impl CompositorChan {
+ pub fn new(chan: Chan<Msg>) -> CompositorChan {
+ CompositorChan {
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),
/// Alerts the compositor to the current status of rendering.
ChangeRenderState(RenderState),
+ /// Sets the channel to the current layout task
+ SetLayoutChan(LayoutChan),
}
/// Azure surface wrapping to work with the layers infrastructure.
@@ -111,264 +113,278 @@ impl ImageData for AzureDrawTargetImageData {
}
}
-fn run_main_loop(port: Port<Msg>,
- script_chan: SharedChan<ScriptMsg>,
- shutdown_chan: Chan<()>,
- profiler_chan: ProfilerChan) {
- let app: Application = ApplicationMethods::new();
- let window: @mut Window = WindowMethods::new(&app);
- let resize_rate_limiter = @mut ResizeRateLimiter(script_chan.clone());
-
- // Create an initial layer tree.
- //
- // TODO: There should be no initial layer tree until the renderer creates one from the display
- // list. This is only here because we don't have that logic in the renderer yet.
- let context = rendergl::init_render_context();
- let root_layer = @mut ContainerLayer();
- let scene = @mut Scene(ContainerLayerKind(root_layer), Size2D(800.0, 600.0), identity());
- let done = @mut false;
-
- // FIXME: This should not be a separate offset applied after the fact but rather should be
- // applied to the layers themselves on a per-layer basis. However, this won't work until scroll
- // positions are sent to content.
- let world_offset = @mut Point2D(0f32, 0f32);
- let page_size = @mut Size2D(0f32, 0f32);
- let window_size = @mut Size2D(800, 600);
-
- // Keeps track of the current zoom factor
- let world_zoom = @mut 1f32;
-
- let check_for_messages: @fn() = || {
- // Periodically check if the script task responded to our last resize event
- resize_rate_limiter.check_resize_response();
- // Handle messages
- while port.peek() {
- match port.recv() {
- Exit => *done = true,
-
- ChangeReadyState(ready_state) => window.set_ready_state(ready_state),
- ChangeRenderState(render_state) => window.set_render_state(render_state),
-
- GetGLContext(chan) => chan.send(current_gl_context()),
-
- Paint(new_layer_buffer_set, new_size) => {
- debug!("osmain: received new frame");
-
- *page_size = Size2D(new_size.width as f32, new_size.height as f32);
-
- let mut new_layer_buffer_set = new_layer_buffer_set;
-
- // Iterate over the children of the container layer.
- let mut current_layer_child = root_layer.first_child;
-
- // Replace the image layer data with the buffer data. Also compute the page
- // size here.
- let buffers = util::replace(&mut new_layer_buffer_set.buffers, ~[]);
-
- for buffers.each |buffer| {
- let width = buffer.rect.size.width as uint;
- let height = buffer.rect.size.height as uint;
-
- debug!("osmain: compositing buffer rect %?", &buffer.rect);
-
- // Find or create a texture layer.
- let texture_layer;
- current_layer_child = match current_layer_child {
- None => {
- debug!("osmain: adding new texture layer");
- texture_layer = @mut TextureLayer::new(@buffer.draw_target.clone() as @TextureManager,
- buffer.rect.size);
- root_layer.add_child(TextureLayerKind(texture_layer));
- None
- }
- Some(TextureLayerKind(existing_texture_layer)) => {
- texture_layer = existing_texture_layer;
- texture_layer.manager = @buffer.draw_target.clone() as @TextureManager;
-
- // Move on to the next sibling.
- do current_layer_child.get().with_common |common| {
- common.next_sibling
- }
- }
- Some(_) => fail!(~"found unexpected layer kind"),
- };
+pub struct CompositorTask {
+ port: Port<Msg>,
+ profiler_chan: ProfilerChan,
+ shutdown_chan: SharedChan<()>,
+}
- let origin = buffer.screen_pos.origin;
- let origin = Point2D(origin.x as f32, origin.y as f32);
+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),
+ }
+ }
- // Set the layer's transform.
- let transform = identity().translate(origin.x, origin.y, 0.0);
- let transform = transform.scale(width as f32, height as f32, 1.0);
- texture_layer.common.set_transform(transform);
- }
+ /// Starts the compositor, which listens for messages on the specified port.
+ pub fn create(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 window: @mut Window = WindowMethods::new(&app);
+
+ // Create an initial layer tree.
+ //
+ // TODO: There should be no initial layer tree until the renderer creates one from the display
+ // list. This is only here because we don't have that logic in the renderer yet.
+ let context = rendergl::init_render_context();
+ let root_layer = @mut ContainerLayer();
+ let scene = @mut Scene(ContainerLayerKind(root_layer), Size2D(800.0, 600.0), identity());
+ let done = @mut false;
+
+ // FIXME: This should not be a separate offset applied after the fact but rather should be
+ // applied to the layers themselves on a per-layer basis. However, this won't work until scroll
+ // positions are sent to content.
+ let world_offset = @mut Point2D(0f32, 0f32);
+ let page_size = @mut Size2D(0f32, 0f32);
+ let window_size = @mut Size2D(800, 600);
+
+ // Keeps track of the current zoom factor
+ let world_zoom = @mut 1f32;
+
+ let update_layout_callbacks: @fn(LayoutChan) = |layout_chan: LayoutChan| {
+ let layout_chan_clone = layout_chan.clone();
+ // 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))));
+ }
- // TODO: Recycle the old buffers; send them back to the renderer to reuse if
- // it wishes.
+ let layout_chan_clone = layout_chan.clone();
- window.set_needs_display();
+ // 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)));
}
- }
- };
+ };
- do window.set_composite_callback {
- do profile(time::CompositingCategory, profiler_chan.clone()) {
- debug!("compositor: compositing");
- // Adjust the layer dimensions as necessary to correspond to the size of the window.
- scene.size = window.size();
+ let check_for_messages: @fn(&Port<Msg>) = |port: &Port<Msg>| {
+ // Handle messages
+ while port.peek() {
+ match port.recv() {
+ Exit => *done = true,
- // Render the scene.
- rendergl::render_scene(context, scene);
- }
+ ChangeReadyState(ready_state) => window.set_ready_state(ready_state),
+ ChangeRenderState(render_state) => window.set_render_state(render_state),
- window.present();
- }
+ SetLayoutChan(layout_chan) => {
+ update_layout_callbacks(layout_chan);
+ }
- // 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)
- }
+ GetGLContext(chan) => chan.send(current_gl_context()),
- let script_chan_clone = script_chan.clone();
+ Paint(new_layer_buffer_set, new_size) => {
+ debug!("osmain: received new frame");
- // 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)))
- }
+ *page_size = Size2D(new_size.width as f32, new_size.height as f32);
- let script_chan_clone = script_chan.clone();
+ let mut new_layer_buffer_set = new_layer_buffer_set;
- // 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));
+ // Iterate over the children of the container layer.
+ let mut current_layer_child = root_layer.first_child;
+
+ // Replace the image layer data with the buffer data. Also compute the page
+ // size here.
+ let buffers = util::replace(&mut new_layer_buffer_set.buffers, ~[]);
+
+ for buffers.each |buffer| {
+ let width = buffer.rect.size.width as uint;
+ let height = buffer.rect.size.height as uint;
+
+ debug!("osmain: compositing buffer rect %?", &buffer.rect);
+
+ // Find or create a texture layer.
+ let texture_layer;
+ current_layer_child = match current_layer_child {
+ None => {
+ debug!("osmain: adding new texture layer");
+ texture_layer = @mut TextureLayer::new(@buffer.draw_target.clone() as @TextureManager,
+ buffer.rect.size);
+ root_layer.add_child(TextureLayerKind(texture_layer));
+ None
+ }
+ Some(TextureLayerKind(existing_texture_layer)) => {
+ texture_layer = existing_texture_layer;
+ texture_layer.manager = @buffer.draw_target.clone() as @TextureManager;
+
+ // Move on to the next sibling.
+ do current_layer_child.get().with_common |common| {
+ common.next_sibling
+ }
+ }
+ Some(_) => fail!(~"found unexpected layer kind"),
+ };
+
+ let origin = buffer.screen_pos.origin;
+ let origin = Point2D(origin.x as f32, origin.y as f32);
+
+ // Set the layer's transform.
+ let transform = identity().translate(origin.x, origin.y, 0.0);
+ let transform = transform.scale(width as f32, height as f32, 1.0);
+ texture_layer.common.set_transform(transform);
+ }
+
+ // TODO: Recycle the old buffers; send them back to the renderer to reuse if
+ // it wishes.
+
+ window.set_needs_display();
+ }
+ }
}
- }
- script_chan_clone.send(SendEventMsg(event));
- }
+ };
- // When the user scrolls, move the layer around.
- do window.set_scroll_callback |delta| {
- // FIXME (Rust #2528): Can't use `-=`.
- let world_offset_copy = *world_offset;
- *world_offset = world_offset_copy - delta;
+ let profiler_chan = self.profiler_chan.clone();
+ do window.set_composite_callback {
+ do profile(time::CompositingCategory, profiler_chan.clone()) {
+ debug!("compositor: compositing");
+ // Adjust the layer dimensions as necessary to correspond to the size of the window.
+ scene.size = window.size();
- // Clamp the world offset to the screen size.
- let max_x = (page_size.width * *world_zoom - window_size.width as f32).max(&0.0);
- world_offset.x = world_offset.x.clamp(&0.0, &max_x);
- let max_y = (page_size.height * *world_zoom - window_size.height as f32).max(&0.0);
- world_offset.y = world_offset.y.clamp(&0.0, &max_y);
+ // Render the scene.
+ rendergl::render_scene(context, scene);
+ }
- debug!("compositor: scrolled to %?", *world_offset);
+ window.present();
+ }
- let mut scroll_transform = identity();
+ // When the user scrolls, move the layer around.
+ do window.set_scroll_callback |delta| {
+ // FIXME (Rust #2528): Can't use `-=`.
+ let world_offset_copy = *world_offset;
+ *world_offset = world_offset_copy - delta;
- scroll_transform = scroll_transform.translate(window_size.width as f32 / 2f32 * *world_zoom - world_offset.x,
- window_size.height as f32 / 2f32 * *world_zoom - world_offset.y,
- 0.0);
- scroll_transform = scroll_transform.scale(*world_zoom, *world_zoom, 1f32);
- scroll_transform = scroll_transform.translate(window_size.width as f32 / -2f32,
- window_size.height as f32 / -2f32,
- 0.0);
+ // Clamp the world offset to the screen size.
+ let max_x = (page_size.width * *world_zoom - window_size.width as f32).max(&0.0);
+ world_offset.x = world_offset.x.clamp(&0.0, &max_x);
+ let max_y = (page_size.height * *world_zoom - window_size.height as f32).max(&0.0);
+ world_offset.y = world_offset.y.clamp(&0.0, &max_y);
- root_layer.common.set_transform(scroll_transform);
+ debug!("compositor: scrolled to %?", *world_offset);
- window.set_needs_display()
- }
+ let mut scroll_transform = identity();
+ scroll_transform = scroll_transform.translate(window_size.width as f32 / 2f32 * *world_zoom - world_offset.x,
+ window_size.height as f32 / 2f32 * *world_zoom - world_offset.y,
+ 0.0);
+ scroll_transform = scroll_transform.scale(*world_zoom, *world_zoom, 1f32);
+ scroll_transform = scroll_transform.translate(window_size.width as f32 / -2f32,
+ window_size.height as f32 / -2f32,
+ 0.0);
+ root_layer.common.set_transform(scroll_transform);
- // When the user pinch-zooms, scale the layer
- do window.set_zoom_callback |magnification| {
- let old_world_zoom = *world_zoom;
+ window.set_needs_display()
+ }
- // Determine zoom amount
- *world_zoom = (*world_zoom * magnification).max(&1.0);
- // Update world offset
- let corner_to_center_x = world_offset.x + window_size.width as f32 / 2f32;
- let new_corner_to_center_x = corner_to_center_x * *world_zoom / old_world_zoom;
- world_offset.x = world_offset.x + new_corner_to_center_x - corner_to_center_x;
- let corner_to_center_y = world_offset.y + window_size.height as f32 / 2f32;
- let new_corner_to_center_y = corner_to_center_y * *world_zoom / old_world_zoom;
- world_offset.y = world_offset.y + new_corner_to_center_y - corner_to_center_y;
+ // When the user pinch-zooms, scale the layer
+ do window.set_zoom_callback |magnification| {
+ let old_world_zoom = *world_zoom;
- // Clamp to page bounds when zooming out
- let max_x = (page_size.width * *world_zoom - window_size.width as f32).max(&0.0);
- world_offset.x = world_offset.x.clamp(&0.0, &max_x);
- let max_y = (page_size.height * *world_zoom - window_size.height as f32).max(&0.0);
- world_offset.y = world_offset.y.clamp(&0.0, &max_y);
+ // Determine zoom amount
+ *world_zoom = (*world_zoom * magnification).max(&1.0);
+ // Update world offset
+ let corner_to_center_x = world_offset.x + window_size.width as f32 / 2f32;
+ let new_corner_to_center_x = corner_to_center_x * *world_zoom / old_world_zoom;
+ world_offset.x = world_offset.x + new_corner_to_center_x - corner_to_center_x;
- // Apply transformations
- let mut zoom_transform = identity();
- zoom_transform = zoom_transform.translate(window_size.width as f32 / 2f32 * *world_zoom - world_offset.x,
- window_size.height as f32 / 2f32 * *world_zoom - world_offset.y,
- 0.0);
- zoom_transform = zoom_transform.scale(*world_zoom, *world_zoom, 1f32);
- zoom_transform = zoom_transform.translate(window_size.width as f32 / -2f32,
- window_size.height as f32 / -2f32,
- 0.0);
- root_layer.common.set_transform(zoom_transform);
+ let corner_to_center_y = world_offset.y + window_size.height as f32 / 2f32;
+ let new_corner_to_center_y = corner_to_center_y * *world_zoom / old_world_zoom;
+ world_offset.y = world_offset.y + new_corner_to_center_y - corner_to_center_y;
+ // Clamp to page bounds when zooming out
+ let max_x = (page_size.width * *world_zoom - window_size.width as f32).max(&0.0);
+ world_offset.x = world_offset.x.clamp(&0.0, &max_x);
+ let max_y = (page_size.height * *world_zoom - window_size.height as f32).max(&0.0);
+ world_offset.y = world_offset.y.clamp(&0.0, &max_y);
- window.set_needs_display()
- }
- // Enter the main event loop.
- while !*done {
- // Check for new messages coming from the rendering task.
- check_for_messages();
+ // Apply transformations
+ let mut zoom_transform = identity();
+ zoom_transform = zoom_transform.translate(window_size.width as f32 / 2f32 * *world_zoom - world_offset.x,
+ window_size.height as f32 / 2f32 * *world_zoom - world_offset.y,
+ 0.0);
+ zoom_transform = zoom_transform.scale(*world_zoom, *world_zoom, 1f32);
+ zoom_transform = zoom_transform.translate(window_size.width as f32 / -2f32,
+ window_size.height as f32 / -2f32,
+ 0.0);
+ root_layer.common.set_transform(zoom_transform);
- // Check for messages coming from the windowing system.
- window.check_loop();
- }
- shutdown_chan.send(())
-}
+ window.set_needs_display()
+ }
+ // Enter the main event loop.
+ while !*done {
+ // Check for new messages coming from the rendering task.
+ check_for_messages(&self.port);
-/// 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()
- }
+ // Check for messages coming from the windowing system.
+ window.check_loop();
+ }
- 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))
+ self.shutdown_chan.send(())
}
}
/// A function for spawning into the platform's main thread.
-fn on_osmain<T: Owned>(f: ~fn(port: Port<T>)) -> Chan<T> {
- let (setup_port, setup_chan) = comm::stream();
+fn on_osmain(f: ~fn()) {
// FIXME: rust#6399
let mut main_task = task::task();
main_task.sched_mode(task::PlatformThread);
do main_task.spawn {
- let (port, chan) = comm::stream();
- setup_chan.send(chan);
- f(port);
+ f();
}
- setup_port.recv()
}
-
diff --git a/src/components/main/compositing/resize_rate_limiter.rs b/src/components/main/compositing/resize_rate_limiter.rs
index 2e358423a63..94c54640836 100644
--- a/src/components/main/compositing/resize_rate_limiter.rs
+++ b/src/components/main/compositing/resize_rate_limiter.rs
@@ -7,20 +7,20 @@
/// before sending the next. If the window is resized multiple times before an event is handled
/// then some events will never be sent.
-use core::comm::{Port, SharedChan};
+use core::comm::{Port};
use script::dom::event::ResizeEvent;
-use script::script_task::{ScriptMsg, SendEventMsg};
+use script::script_task::{ScriptChan, ScriptMsg, SendEventMsg};
pub struct ResizeRateLimiter {
/// 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
priv last_response_port: Option<Port<()>>,
/// The next window resize event we should fire
priv next_resize_event: Option<(uint, uint)>
}
-pub fn ResizeRateLimiter(script_chan: SharedChan<ScriptMsg>) -> ResizeRateLimiter {
+pub fn ResizeRateLimiter(script_chan: ScriptChan) -> ResizeRateLimiter {
ResizeRateLimiter {
script_chan: script_chan,
last_response_port: None,
diff --git a/src/components/main/engine.rs b/src/components/main/engine.rs
index 921688bd061..1abc00537c4 100644
--- a/src/components/main/engine.rs
+++ b/src/components/main/engine.rs
@@ -2,101 +2,112 @@
* 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::CompositorTask;
+use compositing::{CompositorChan, SetLayoutChan};
use layout::layout_task;
use core::cell::Cell;
-use core::comm::{Port, SharedChan};
+use core::comm::Port;
use gfx::opts::Opts;
-use gfx::render_task::RenderTask;
+use gfx::render_task::RenderChan;
use gfx::render_task;
-use script::compositor_interface::{CompositorInterface, ReadyState};
-use script::engine_interface::{EngineTask, ExitMsg, LoadUrlMsg, Msg};
-use script::layout_interface::LayoutTask;
+use script::compositor_interface::{ScriptListener, ReadyState};
+use script::engine_interface::{EngineChan, ExitMsg, LoadUrlMsg, Msg};
+use script::layout_interface::LayoutChan;
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 servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
use servo_net::resource_task::ResourceTask;
use servo_net::resource_task;
-use servo_util::time::{ProfilerChan, ProfilerPort, ProfilerTask, ForcePrintMsg};
+use servo_util::time::{ProfilerChan};
pub struct Engine {
request_port: Port<Msg>,
- compositor: CompositorTask,
- render_task: RenderTask,
+ compositor_chan: CompositorChan,
+ render_chan: RenderChan<CompositorChan>,
resource_task: ResourceTask,
image_cache_task: ImageCacheTask,
- layout_task: LayoutTask,
- script_task: ScriptTask,
- profiler_task: ProfilerTask,
-}
-
-impl Drop for Engine {
- fn finalize(&self) {
- self.profiler_task.chan.send(ForcePrintMsg);
- }
+ layout_chan: LayoutChan,
+ script_chan: ScriptChan,
+ profiler_chan: ProfilerChan,
}
impl Engine {
- pub fn start(compositor: CompositorTask,
+ pub fn start(compositor_chan: CompositorChan,
opts: &Opts,
- script_port: Port<ScriptMsg>,
- script_chan: SharedChan<ScriptMsg>,
resource_task: ResourceTask,
image_cache_task: ImageCacheTask,
- profiler_port: ProfilerPort,
profiler_chan: ProfilerChan)
- -> EngineTask {
- let (script_port, script_chan) = (Cell(script_port), Cell(script_chan));
- let (engine_port, engine_chan) = comm::stream();
- let (engine_port, engine_chan) = (Cell(engine_port), SharedChan::new(engine_chan));
- let engine_chan_clone = engine_chan.clone();
- let compositor = Cell(compositor);
- let profiler_port = Cell(profiler_port);
+ -> EngineChan {
+ macro_rules! closure_stream(
+ ($Msg:ty, $Chan:ident) => (
+ {
+ let (port, chan) = comm::stream::<$Msg>();
+ (Cell(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(render_port), RenderChan::new(render_chan));
+
+
+ compositor_chan.send(SetLayoutChan(layout_chan.clone()));
+ let compositor_chan = Cell(compositor_chan);
+
let opts = Cell(copy *opts);
- do task::spawn {
- let compositor = compositor.take();
- let render_task = RenderTask::new(compositor.clone(),
- opts.with_ref(|o| copy *o),
- profiler_chan.clone());
-
- let opts = opts.take();
-
- let profiler_task = ProfilerTask::new(profiler_port.take(),
- profiler_chan.clone(),
- opts.profiler_period);
-
- let layout_task = layout_task::create_layout_task(render_task.clone(),
- image_cache_task.clone(),
- opts,
- profiler_task.chan.clone());
-
- let compositor_clone = compositor.clone();
- let script_task = ScriptTask::new(script_port.take(),
- script_chan.take(),
- engine_chan_clone.clone(),
- |msg: ReadyState| {
- compositor_clone.set_ready_state(msg)
- },
- layout_task.clone(),
- resource_task.clone(),
- image_cache_task.clone());
-
-
- Engine {
- request_port: engine_port.take(),
- compositor: compositor.clone(),
- render_task: render_task,
- resource_task: resource_task.clone(),
- image_cache_task: image_cache_task.clone(),
- layout_task: layout_task,
- script_task: script_task,
- profiler_task: profiler_task,
- }.run();
+ {
+ 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 {
+ request_port: engine_port.take(),
+ compositor_chan: compositor_chan.clone(),
+ render_chan: render_chan.clone(),
+ resource_task: resource_task.clone(),
+ image_cache_task: image_cache_task.clone(),
+ layout_chan: layout_chan.clone(),
+ script_chan: script_chan.clone(),
+ profiler_chan: profiler_chan.clone(),
+ }.run();
+ }
}
- engine_chan.clone()
+ engine_chan
}
fn run(&self) {
@@ -109,20 +120,20 @@ impl Engine {
match request {
LoadUrlMsg(url) => {
if url.path.ends_with(".js") {
- self.script_task.chan.send(ExecuteMsg(url))
+ self.script_chan.send(ExecuteMsg(url))
} else {
- self.script_task.chan.send(LoadMsg(url))
+ self.script_chan.send(LoadMsg(url))
}
return true
}
ExitMsg(sender) => {
- self.script_task.chan.send(script_task::ExitMsg);
- self.layout_task.chan.send(layout_interface::ExitMsg);
+ self.script_chan.send(script_task::ExitMsg);
+ self.layout_chan.send(layout_interface::ExitMsg);
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();
self.image_cache_task.exit();
diff --git a/src/components/main/layout/layout_task.rs b/src/components/main/layout/layout_task.rs
index 9b896c1253e..fcdc8cc6b24 100644
--- a/src/components/main/layout/layout_task.rs
+++ b/src/components/main/layout/layout_task.rs
@@ -5,6 +5,7 @@
//! 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};
@@ -13,11 +14,10 @@ use layout::box_builder::LayoutTreeBuilder;
use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, FlowDisplayListBuilderMethods};
use layout::flow::FlowContext;
-use util::task::spawn_listener;
use core::cast::transmute;
use core::cell::Cell;
-use core::comm::{Chan, Port, SharedChan};
+use core::comm::{Chan, Port};
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
@@ -26,7 +26,7 @@ use gfx::font_context::FontContext;
use gfx::geometry::Au;
use gfx::opts::Opts;
use gfx::render_layers::RenderLayer;
-use gfx::render_task::{RenderMsg, RenderTask};
+use gfx::render_task::{RenderMsg, RenderChan};
use newcss::select::SelectCtx;
use newcss::stylesheet::Stylesheet;
use newcss::types::OriginAuthor;
@@ -35,10 +35,10 @@ 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, LayoutTask, MatchSelectorsDocumentDamage, Msg};
-use script::layout_interface::{QueryMsg, Reflow, ReflowDocumentDamage, ReflowForDisplay};
-use script::layout_interface::{ReflowMsg};
-use script::script_task::{ReflowCompleteMsg, ScriptMsg, SendEventMsg};
+use script::layout_interface::{LayoutResponse, MatchSelectorsDocumentDamage, Msg};
+use script::layout_interface::{QueryMsg, RouteScriptMsg, Reflow, ReflowDocumentDamage};
+use script::layout_interface::{ReflowForDisplay, ReflowMsg};
+use script::script_task::{ReflowCompleteMsg, ScriptChan, ScriptMsg, SendEventMsg};
use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg};
use servo_net::local_image_cache::LocalImageCache;
use servo_util::tree::{TreeNodeRef, TreeUtils};
@@ -46,30 +46,30 @@ use servo_util::time::{ProfilerChan, profile, time};
use servo_util::time;
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<CompositorChan>,
img_cache_task: ImageCacheTask,
opts: Opts,
- profiler_chan: ProfilerChan)
- -> LayoutTask {
- let chan = do spawn_listener::<Msg> |from_script| {
- let mut layout = Layout::new(render_task.clone(),
+ profiler_chan: ProfilerChan) {
+ let port = Cell(port);
+ do spawn {
+ let mut layout = Layout::new(port.take(),
+ script_chan.clone(),
+ render_chan.clone(),
img_cache_task.clone(),
- from_script,
&opts,
profiler_chan.clone());
layout.start();
};
-
- LayoutTask {
- chan: SharedChan::new(chan),
- }
}
struct Layout {
- render_task: RenderTask,
+ port: Port<Msg>,
+ script_chan: ScriptChan,
+ render_chan: RenderChan<CompositorChan>,
image_cache_task: ImageCacheTask,
local_image_cache: @mut LocalImageCache,
- from_script: Port<Msg>,
font_ctx: @mut FontContext,
doc_url: Option<Url>,
screen_size: Option<Size2D<Au>>,
@@ -82,19 +82,21 @@ struct Layout {
}
impl Layout {
- fn new(render_task: RenderTask,
+ fn new(port: Port<Msg>,
+ script_chan: ScriptChan,
+ render_chan: RenderChan<CompositorChan>,
image_cache_task: ImageCacheTask,
- from_script: Port<Msg>,
opts: &Opts,
profiler_chan: ProfilerChan)
-> Layout {
let fctx = @mut FontContext::new(opts.render_backend, true, profiler_chan.clone());
Layout {
- render_task: render_task,
+ port: port,
+ script_chan: script_chan,
+ render_chan: render_chan,
image_cache_task: image_cache_task.clone(),
local_image_cache: @mut LocalImageCache(image_cache_task),
- from_script: from_script,
font_ctx: fctx,
doc_url: None,
screen_size: None,
@@ -125,7 +127,7 @@ impl Layout {
}
fn handle_request(&mut self) -> bool {
- match self.from_script.recv() {
+ match self.port.recv() {
AddStylesheetMsg(sheet) => self.handle_add_stylesheet(sheet),
ReflowMsg(data) => {
let data = Cell(data);
@@ -137,9 +139,12 @@ impl Layout {
QueryMsg(query, chan) => {
let chan = Cell(chan);
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 => {
debug!("layout: ExitMsg received");
return false
@@ -248,7 +253,7 @@ impl Layout {
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)
}
@@ -371,12 +376,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
// this callback in some task somewhere. This will send a message
// 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
// 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) {
// This has a crazy signature because the image cache needs to
// make multiple copies of the callback, and the dom event
diff --git a/src/components/main/platform/common/glut_windowing.rs b/src/components/main/platform/common/glut_windowing.rs
index a6ee264437c..50e67d6e541 100644
--- a/src/components/main/platform/common/glut_windowing.rs
+++ b/src/components/main/platform/common/glut_windowing.rs
@@ -12,7 +12,6 @@ use windowing::{ResizeCallback, ScrollCallback, WindowMethods, WindowMouseEvent,
use windowing::{WindowMouseDownEvent, WindowMouseUpEvent, ZoomCallback};
use alert::{Alert, AlertMethods};
-use core::cell::Cell;
use core::libc::c_int;
use geom::point::Point2D;
use geom::size::Size2D;
diff --git a/src/components/main/servo.rc b/src/components/main/servo.rc
index b092d4b30a6..8357d4136d1 100755
--- a/src/components/main/servo.rc
+++ b/src/components/main/servo.rc
@@ -33,14 +33,15 @@ extern mod core_graphics;
#[cfg(target_os="macos")]
extern mod core_text;
-use compositing::CompositorTask;
+use compositing::{CompositorChan, CompositorTask};
use engine::Engine;
use script::engine_interface::{ExitMsg, LoadUrlMsg};
-use core::comm::SharedChan;
use gfx::opts;
use servo_net::image_cache_task::ImageCacheTask;
use servo_net::resource_task::ResourceTask;
+use servo_util::time::{Profiler, ProfilerChan, PrintMsg};
+use std::uv_global_loop;
pub use gfx::opts::Opts;
pub use gfx::text;
@@ -87,33 +88,42 @@ fn main() {
}
fn run(opts: &Opts) {
- // Create the script channel.
- let (script_port, script_chan) = comm::stream();
- let script_chan = SharedChan::new(script_chan);
+ let (shutdown_port, shutdown_chan) = comm::stream();
// Create the profiler channel.
let (profiler_port, profiler_chan) = comm::stream();
- let profiler_chan = SharedChan::new(profiler_chan);
+ let profiler_chan = ProfilerChan::new(profiler_chan);
+ Profiler::create(profiler_port);
+ do opts.profiler_period.map |period| {
+ let profiler_chan = profiler_chan.clone();
+ let period = *period;
+ do spawn {
+ loop {
+ std::timer::sleep(&uv_global_loop::get(),
+ (period * 1000f64) as uint);
+ profiler_chan.send(PrintMsg);
+ }
+ }
+ };
// Create the compositor.
- let (compositor, shutdown_port) = CompositorTask::new(script_chan.clone(),
- profiler_chan.clone());
+ let (compositor_port, compositor_chan) = comm::stream();
+ let compositor_chan = CompositorChan::new(compositor_chan);
+ CompositorTask::create(compositor_port, profiler_chan.clone(), shutdown_chan);
// Create a Servo instance.
+
let resource_task = ResourceTask();
let image_cache_task = ImageCacheTask(resource_task.clone());
- let engine_task = Engine::start(compositor.clone(),
+ let engine_chan = Engine::start(compositor_chan.clone(),
opts,
- script_port,
- script_chan,
resource_task,
image_cache_task,
- profiler_port,
- profiler_chan);
+ profiler_chan.clone());
// Send the URL command to the engine task.
for opts.urls.each |filename| {
- engine_task.send(LoadUrlMsg(make_url(copy *filename, None)))
+ engine_chan.send(LoadUrlMsg(make_url(copy *filename, None)))
}
// Wait for the compositor to shut down.
@@ -122,7 +132,7 @@ fn run(opts: &Opts) {
// Shut the engine down.
debug!("master: Shut down");
let (exit_response_from_engine, exit_chan) = comm::stream();
- engine_task.send(ExitMsg(exit_chan));
+ engine_chan.send(ExitMsg(exit_chan));
exit_response_from_engine.recv();
}
diff --git a/src/components/script/compositor_interface.rs b/src/components/script/compositor_interface.rs
index 8e48e9f1492..b0041e49298 100644
--- a/src/components/script/compositor_interface.rs
+++ b/src/components/script/compositor_interface.rs
@@ -14,6 +14,8 @@ pub enum ReadyState {
FinishedLoading,
}
-pub trait CompositorInterface : Clone {
+/// 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);
}
diff --git a/src/components/script/dom/event.rs b/src/components/script/dom/event.rs
index 6c11bcd3411..6b4be15b701 100644
--- a/src/components/script/dom/event.rs
+++ b/src/components/script/dom/event.rs
@@ -10,7 +10,7 @@ use dom::bindings::utils::{DOMString, ErrorResult, WrapperCache};
use geom::point::Point2D;
pub enum Event {
- ResizeEvent(uint, uint, comm::Chan<()>),
+ ResizeEvent(uint, uint),
ReflowEvent,
ClickEvent(uint, Point2D<f32>),
MouseDownEvent(uint, Point2D<f32>),
diff --git a/src/components/script/dom/window.rs b/src/components/script/dom/window.rs
index aa375a4d614..0c48008827d 100644
--- a/src/components/script/dom/window.rs
+++ b/src/components/script/dom/window.rs
@@ -6,9 +6,9 @@ use dom::bindings::utils::WrapperCache;
use dom::bindings::window;
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 std::timer;
use std::uv_global_loop;
@@ -23,7 +23,7 @@ pub enum TimerControlMsg {
// only used for querying layout from arbitrary script.
pub struct Window {
timer_chan: Chan<TimerControlMsg>,
- script_chan: SharedChan<ScriptMsg>,
+ script_chan: ScriptChan,
script_context: *mut ScriptContext,
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 {
- let script_chan_copy = script_chan.clone();
+ let script_chan_clone = script_chan.clone();
let win = @mut Window {
wrapper: WrapperCache::new(),
script_chan: script_chan,
@@ -100,8 +100,8 @@ pub impl Window {
loop {
match timer_port.recv() {
TimerMessage_Close => break,
- TimerMessage_Fire(td) => script_chan_copy.send(FireTimerMsg(td)),
- TimerMessage_TriggerExit => script_chan_copy.send(ExitMsg),
+ TimerMessage_Fire(td) => script_chan_clone.chan.send(FireTimerMsg(td)),
+ TimerMessage_TriggerExit => script_chan_clone.chan.send(ExitMsg),
}
}
}
diff --git a/src/components/script/engine_interface.rs b/src/components/script/engine_interface.rs
index 2705ebdb137..c7a33334c97 100644
--- a/src/components/script/engine_interface.rs
+++ b/src/components/script/engine_interface.rs
@@ -8,7 +8,21 @@
use core::comm::{Chan, SharedChan};
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 {
LoadUrlMsg(Url),
diff --git a/src/components/script/layout_interface.rs b/src/components/script/layout_interface.rs
index f9ab0a8eb2e..d4d0aef7cf3 100644
--- a/src/components/script/layout_interface.rs
+++ b/src/components/script/layout_interface.rs
@@ -7,7 +7,7 @@
/// from layout.
use dom::node::{AbstractNode, ScriptView, LayoutView};
-use script_task::ScriptMsg;
+use script_task::{ScriptMsg, ScriptChan};
use core::comm::{Chan, SharedChan};
use geom::rect::Rect;
@@ -32,6 +32,9 @@ pub enum Msg {
/// FIXME(pcwalton): As noted below, this isn't very type safe.
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.
ExitMsg,
}
@@ -110,7 +113,7 @@ pub struct Reflow {
/// The URL of the page.
url: Url,
/// The channel through which messages can be sent back to the script task.
- script_chan: SharedChan<ScriptMsg>,
+ script_chan: ScriptChan,
/// The current window size.
window_size: Size2D<uint>,
/// The channel that we send a notification to.
@@ -119,7 +122,17 @@ pub struct Reflow {
/// Encapsulates a channel to the layout task.
#[deriving(Clone)]
-pub struct LayoutTask {
+pub struct LayoutChan {
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);
+ }
+}
diff --git a/src/components/script/script_task.rs b/src/components/script/script_task.rs
index 69890abb5cb..39ef337b2f1 100644
--- a/src/components/script/script_task.rs
+++ b/src/components/script/script_task.rs
@@ -13,11 +13,11 @@ use dom::event::{Event, ResizeEvent, ReflowEvent, ClickEvent, MouseDownEvent, Mo
use dom::node::{AbstractNode, ScriptView, define_bindings};
use dom::window::Window;
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::{ReflowForDisplay, ReflowForScriptQuery, ReflowGoal, ReflowMsg};
use layout_interface;
-use engine_interface::{EngineTask, LoadUrlMsg};
+use engine_interface::{EngineChan, LoadUrlMsg};
use core::cast::transmute;
use core::cell::Cell;
@@ -61,42 +61,22 @@ pub enum ScriptMsg {
}
/// 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.
chan: SharedChan<ScriptMsg>,
}
-impl ScriptTask {
+impl ScriptChan {
/// Creates a new script task.
- pub fn new(script_port: Port<ScriptMsg>,
- script_chan: SharedChan<ScriptMsg>,
- engine_task: EngineTask,
- //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 new(chan: Chan<ScriptMsg>) -> ScriptChan {
+ ScriptChan {
+ chan: SharedChan::new(chan)
}
}
+ pub fn send(&self, msg: ScriptMsg) {
+ self.chan.send(msg);
+ }
}
/// Information for one frame in the browsing context.
@@ -112,7 +92,7 @@ pub struct Frame {
/// FIXME: Rename to `Page`, following WebKit?
pub struct ScriptContext {
/// A handle to the layout task.
- layout_task: LayoutTask,
+ layout_chan: LayoutChan,
/// A handle to the image cache task.
image_cache_task: ImageCacheTask,
/// A handle to the resource task.
@@ -125,10 +105,10 @@ pub struct ScriptContext {
script_port: Port<ScriptMsg>,
/// A channel for us to hand out when we want some other task to be able to send us script
/// messages.
- script_chan: SharedChan<ScriptMsg>,
+ script_chan: ScriptChan,
/// For communicating load url messages to the engine
- engine_task: EngineTask,
+ engine_chan: EngineChan,
/// For communicating loading messages to the compositor
compositor_task: ~fn(ReadyState),
@@ -180,10 +160,10 @@ impl Drop for ScriptContext {
impl ScriptContext {
/// Creates a new script context.
- pub fn new(layout_task: LayoutTask,
+ pub fn new(layout_chan: LayoutChan,
script_port: Port<ScriptMsg>,
- script_chan: SharedChan<ScriptMsg>,
- engine_task: EngineTask,
+ script_chan: ScriptChan,
+ engine_chan: EngineChan,
compositor_task: ~fn(ReadyState),
resource_task: ResourceTask,
img_cache_task: ImageCacheTask)
@@ -200,7 +180,7 @@ impl ScriptContext {
};
let script_context = @mut ScriptContext {
- layout_task: layout_task,
+ layout_chan: layout_chan,
image_cache_task: img_cache_task,
resource_task: resource_task,
@@ -208,7 +188,7 @@ impl ScriptContext {
script_port: script_port,
script_chan: script_chan,
- engine_task: engine_task,
+ engine_chan: engine_chan,
compositor_task: compositor_task,
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.
fn handle_msg(&mut self) -> bool {
match self.script_port.recv() {
@@ -325,7 +329,7 @@ impl ScriptContext {
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
@@ -361,7 +365,7 @@ impl ScriptContext {
// in the script task.
loop {
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,
}
}
@@ -457,7 +461,7 @@ impl ScriptContext {
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();
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()
}
@@ -511,7 +515,7 @@ impl ScriptContext {
/// TODO: Actually perform DOM event dispatch.
fn handle_event(&mut self, event: 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);
self.window_size = Size2D(new_width, new_height);
@@ -525,8 +529,6 @@ impl ScriptContext {
if self.root_frame.is_some() {
self.reflow(ReflowForDisplay)
}
-
- response_chan.send(())
}
// FIXME(pcwalton): This reflows the entire document and is not incremental-y.
@@ -595,7 +597,7 @@ impl ScriptContext {
None => None
};
let url = make_url(attr.value.clone(), current_url);
- self.engine_task.send(LoadUrlMsg(url));
+ self.engine_chan.send(LoadUrlMsg(url));
}
}
}
diff --git a/src/components/util/time.rs b/src/components/util/time.rs
index 4ea5828e892..95bdc207e34 100644
--- a/src/components/util/time.rs
+++ b/src/components/util/time.rs
@@ -8,8 +8,22 @@ use core::cell::Cell;
use core::comm::{Port, SharedChan};
use std::sort::tim_sort;
-pub type ProfilerChan = SharedChan<ProfilerMsg>;
-pub type ProfilerPort = Port<ProfilerMsg>;
+// front-end representation of the profiler used to communicate with the profiler
+#[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)]
pub enum ProfilerCategory {
@@ -36,25 +50,17 @@ pub enum ProfilerMsg {
// Normal message used for reporting time
TimeMsg(ProfilerCategory, f64),
// Message used to force print the profiling metrics
- ForcePrintMsg,
-}
-
-// front-end representation of the profiler used to communicate with the profiler context
-pub struct ProfilerTask {
- chan: ProfilerChan,
+ PrintMsg,
}
// back end of the profiler that handles data aggregation and performance metrics
-pub struct ProfilerContext {
- port: ProfilerPort,
+pub struct Profiler {
+ port: Port<ProfilerMsg>,
buckets: ~[(ProfilerCategory, ~[f64])],
- verbose: bool,
- period: f64,
- last_print: f64,
+ last_msg: Option<ProfilerMsg>,
}
impl ProfilerCategory {
-
// convenience function to not have to cast every time
pub fn num_buckets() -> uint {
NUM_BUCKETS as uint
@@ -103,36 +109,20 @@ impl ProfilerCategory {
}
}
-impl ProfilerTask {
- pub fn new(profiler_port: ProfilerPort,
- profiler_chan: ProfilerChan,
- period: Option<f64>)
- -> ProfilerTask {
- let profiler_port = Cell(profiler_port);
-
+impl Profiler {
+ pub fn create(port: Port<ProfilerMsg>) {
+ let port = Cell(port);
do spawn {
- let mut profiler_context = ProfilerContext::new(profiler_port.take(), period);
- profiler_context.start();
- }
-
- ProfilerTask {
- chan: profiler_chan
+ let mut profiler = Profiler::new(port.take());
+ profiler.start();
}
}
-}
-impl ProfilerContext {
- pub fn new(port: ProfilerPort, period: Option<f64>) -> ProfilerContext {
- let (verbose, period) = match period {
- Some(period) => (true, period),
- None => (false, 0f64)
- };
- ProfilerContext {
+ pub fn new(port: Port<ProfilerMsg>) -> Profiler {
+ Profiler {
port: port,
buckets: ProfilerCategory::empty_buckets(),
- verbose: verbose,
- period: period,
- last_print: 0f64,
+ last_msg: None,
}
}
@@ -145,25 +135,19 @@ impl ProfilerContext {
priv fn handle_msg(&mut self, msg: ProfilerMsg) {
match msg {
- TimeMsg(category, t) => {
+ TimeMsg(category, t) => match self.buckets[category as uint] {
// FIXME(#3874): this should be a let (cat, ref mut bucket) = ...,
// not a match
- match self.buckets[category as uint] {
- (_, ref mut data) => {
- data.push(t);
- }
+ (_, ref mut data) => {
+ data.push(t);
}
-
- if self.verbose {
- let cur_time = precise_time_ns() as f64 / 1000000000f64;
- if cur_time - self.last_print > self.period {
- self.last_print = cur_time;
- self.print_buckets();
- }
- }
- }
- ForcePrintMsg => self.print_buckets(),
+ },
+ PrintMsg => match self.last_msg {
+ Some(TimeMsg(*)) => self.print_buckets(),
+ _ => {}
+ },
};
+ self.last_msg = Some(msg);
}
priv fn print_buckets(&mut self) {
diff --git a/src/support/netsurfcss/libcss b/src/support/netsurfcss/libcss
-Subproject da248d3f5b3ed6d9e804c543563be8e34baf167
+Subproject d722188de3876ed748382965eb4f300fc1b78bf