diff options
-rw-r--r-- | src/components/gfx/compositor.rs | 4 | ||||
-rw-r--r-- | src/components/gfx/render_task.rs | 133 | ||||
-rw-r--r-- | src/components/main/compositing/mod.rs | 502 | ||||
-rw-r--r-- | src/components/main/compositing/resize_rate_limiter.rs | 8 | ||||
-rw-r--r-- | src/components/main/engine.rs | 161 | ||||
-rw-r--r-- | src/components/main/layout/layout_task.rs | 65 | ||||
-rw-r--r-- | src/components/main/platform/common/glut_windowing.rs | 1 | ||||
-rwxr-xr-x | src/components/main/servo.rc | 40 | ||||
-rw-r--r-- | src/components/script/compositor_interface.rs | 4 | ||||
-rw-r--r-- | src/components/script/dom/event.rs | 2 | ||||
-rw-r--r-- | src/components/script/dom/window.rs | 14 | ||||
-rw-r--r-- | src/components/script/engine_interface.rs | 16 | ||||
-rw-r--r-- | src/components/script/layout_interface.rs | 19 | ||||
-rw-r--r-- | src/components/script/script_task.rs | 96 | ||||
-rw-r--r-- | src/components/util/time.rs | 90 | ||||
m--------- | src/support/netsurfcss/libcss | 0 |
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 |