mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
Merge branch 'master' of https://github.com/mozilla/servo
This commit is contained in:
commit
def01b414f
16 changed files with 645 additions and 570 deletions
|
@ -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);
|
||||
|
|
|
@ -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,24 +22,41 @@ 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,
|
||||
impl<C: RenderListener + Owned> Clone for RenderChan<C> {
|
||||
pub fn clone(&self) -> RenderChan<C> {
|
||||
RenderChan {
|
||||
chan: self.chan.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: RenderListener + Owned> RenderChan<C> {
|
||||
pub fn new(chan: Chan<Msg<C>>) -> RenderChan<C> {
|
||||
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)
|
||||
-> RenderTask {
|
||||
profiler_chan: ProfilerChan) {
|
||||
let compositor_cell = Cell(compositor);
|
||||
let opts_cell = Cell(opts);
|
||||
let (port, chan) = comm::stream();
|
||||
let port = Cell(port);
|
||||
|
||||
do spawn {
|
||||
|
@ -84,11 +101,6 @@ impl RenderTask {
|
|||
|
||||
renderer.start();
|
||||
}
|
||||
|
||||
RenderTask {
|
||||
channel: SharedChan::new(chan),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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(());
|
||||
|
|
|
@ -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);
|
||||
/// 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 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());
|
||||
};
|
||||
|
||||
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,13 +113,42 @@ impl ImageData for AzureDrawTargetImageData {
|
|||
}
|
||||
}
|
||||
|
||||
fn run_main_loop(port: Port<Msg>,
|
||||
script_chan: SharedChan<ScriptMsg>,
|
||||
shutdown_chan: Chan<()>,
|
||||
profiler_chan: ProfilerChan) {
|
||||
pub struct CompositorTask {
|
||||
port: Port<Msg>,
|
||||
profiler_chan: ProfilerChan,
|
||||
shutdown_chan: SharedChan<()>,
|
||||
}
|
||||
|
||||
impl CompositorTask {
|
||||
pub fn new(port: Port<Msg>,
|
||||
profiler_chan: ProfilerChan,
|
||||
shutdown_chan: Chan<()>)
|
||||
-> CompositorTask {
|
||||
CompositorTask {
|
||||
port: port,
|
||||
profiler_chan: profiler_chan,
|
||||
shutdown_chan: SharedChan::new(shutdown_chan),
|
||||
}
|
||||
}
|
||||
|
||||
/// Starts the compositor, 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);
|
||||
let resize_rate_limiter = @mut ResizeRateLimiter(script_chan.clone());
|
||||
|
||||
// Create an initial layer tree.
|
||||
//
|
||||
|
@ -138,9 +169,47 @@ fn run_main_loop(port: Port<Msg>,
|
|||
// 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();
|
||||
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))));
|
||||
}
|
||||
|
||||
let layout_chan_clone = layout_chan.clone();
|
||||
|
||||
// When the user enters a new URL, load it.
|
||||
do window.set_load_url_callback |url_string| {
|
||||
debug!("osmain: loading URL `%s`", url_string);
|
||||
layout_chan_clone.chan.send(RouteScriptMsg(LoadMsg(url::make_url(url_string.to_str(), None))));
|
||||
}
|
||||
|
||||
let layout_chan_clone = layout_chan.clone();
|
||||
|
||||
// When the user triggers a mouse event, perform appropriate hit testing
|
||||
do window.set_mouse_callback |window_mouse_event: WindowMouseEvent| {
|
||||
let event: Event;
|
||||
let world_mouse_point = |layer_mouse_point: Point2D<f32>| {
|
||||
layer_mouse_point + *world_offset
|
||||
};
|
||||
match window_mouse_event {
|
||||
WindowClickEvent(button, layer_mouse_point) => {
|
||||
event = ClickEvent(button, world_mouse_point(layer_mouse_point));
|
||||
}
|
||||
WindowMouseDownEvent(button, layer_mouse_point) => {
|
||||
event = MouseDownEvent(button, world_mouse_point(layer_mouse_point));
|
||||
}
|
||||
WindowMouseUpEvent(button, layer_mouse_point) => {
|
||||
event = MouseUpEvent(button, world_mouse_point(layer_mouse_point));
|
||||
}
|
||||
}
|
||||
layout_chan_clone.chan.send(RouteScriptMsg(SendEventMsg(event)));
|
||||
}
|
||||
};
|
||||
|
||||
let check_for_messages: @fn(&Port<Msg>) = |port: &Port<Msg>| {
|
||||
// Handle messages
|
||||
while port.peek() {
|
||||
match port.recv() {
|
||||
|
@ -149,6 +218,10 @@ fn run_main_loop(port: Port<Msg>,
|
|||
ChangeReadyState(ready_state) => window.set_ready_state(ready_state),
|
||||
ChangeRenderState(render_state) => window.set_render_state(render_state),
|
||||
|
||||
SetLayoutChan(layout_chan) => {
|
||||
update_layout_callbacks(layout_chan);
|
||||
}
|
||||
|
||||
GetGLContext(chan) => chan.send(current_gl_context()),
|
||||
|
||||
Paint(new_layer_buffer_set, new_size) => {
|
||||
|
@ -211,6 +284,7 @@ fn run_main_loop(port: Port<Msg>,
|
|||
}
|
||||
};
|
||||
|
||||
let profiler_chan = self.profiler_chan.clone();
|
||||
do window.set_composite_callback {
|
||||
do profile(time::CompositingCategory, profiler_chan.clone()) {
|
||||
debug!("compositor: compositing");
|
||||
|
@ -224,43 +298,6 @@ fn run_main_loop(port: Port<Msg>,
|
|||
window.present();
|
||||
}
|
||||
|
||||
// Hook the windowing system's resize callback up to the resize rate limiter.
|
||||
do window.set_resize_callback |width, height| {
|
||||
debug!("osmain: window resized to %ux%u", width, height);
|
||||
*window_size = Size2D(width, height);
|
||||
resize_rate_limiter.window_resized(width, height)
|
||||
}
|
||||
|
||||
let script_chan_clone = script_chan.clone();
|
||||
|
||||
// When the user enters a new URL, load it.
|
||||
do window.set_load_url_callback |url_string| {
|
||||
debug!("osmain: loading URL `%s`", url_string);
|
||||
script_chan_clone.send(LoadMsg(url::make_url(url_string.to_str(), None)))
|
||||
}
|
||||
|
||||
let script_chan_clone = script_chan.clone();
|
||||
|
||||
// When the user triggers a mouse event, perform appropriate hit testing
|
||||
do window.set_mouse_callback |window_mouse_event: WindowMouseEvent| {
|
||||
let event: Event;
|
||||
let world_mouse_point = |layer_mouse_point: Point2D<f32>| {
|
||||
layer_mouse_point + *world_offset
|
||||
};
|
||||
match window_mouse_event {
|
||||
WindowClickEvent(button, layer_mouse_point) => {
|
||||
event = ClickEvent(button, world_mouse_point(layer_mouse_point));
|
||||
}
|
||||
WindowMouseDownEvent(button, layer_mouse_point) => {
|
||||
event = MouseDownEvent(button, world_mouse_point(layer_mouse_point));
|
||||
}
|
||||
WindowMouseUpEvent(button, layer_mouse_point) => {
|
||||
event = MouseUpEvent(button, world_mouse_point(layer_mouse_point));
|
||||
}
|
||||
}
|
||||
script_chan_clone.send(SendEventMsg(event));
|
||||
}
|
||||
|
||||
// When the user scrolls, move the layer around.
|
||||
do window.set_scroll_callback |delta| {
|
||||
// FIXME (Rust #2528): Can't use `-=`.
|
||||
|
@ -329,46 +366,25 @@ fn run_main_loop(port: Port<Msg>,
|
|||
|
||||
window.set_needs_display()
|
||||
}
|
||||
|
||||
// Enter the main event loop.
|
||||
while !*done {
|
||||
// Check for new messages coming from the rendering task.
|
||||
check_for_messages();
|
||||
check_for_messages(&self.port);
|
||||
|
||||
// Check for messages coming from the windowing system.
|
||||
window.check_loop();
|
||||
}
|
||||
|
||||
shutdown_chan.send(())
|
||||
}
|
||||
|
||||
/// Implementation of the abstract `Compositor` interface.
|
||||
impl Compositor for CompositorTask {
|
||||
fn get_gl_context(&self) -> AzGLContext {
|
||||
let (port, chan) = comm::stream();
|
||||
self.chan.send(GetGLContext(chan));
|
||||
port.recv()
|
||||
}
|
||||
|
||||
fn paint(&self, layer_buffer_set: LayerBufferSet, new_size: Size2D<uint>) {
|
||||
self.chan.send(Paint(layer_buffer_set, new_size))
|
||||
}
|
||||
fn set_render_state(&self, render_state: RenderState) {
|
||||
self.chan.send(ChangeRenderState(render_state))
|
||||
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()
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
{
|
||||
let engine_chan = engine_chan.clone();
|
||||
do task::spawn {
|
||||
let compositor = compositor.take();
|
||||
let render_task = RenderTask::new(compositor.clone(),
|
||||
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();
|
||||
|
||||
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(),
|
||||
layout_task::create_layout_task(layout_port.take(),
|
||||
script_chan.clone(),
|
||||
render_chan.clone(),
|
||||
image_cache_task.clone(),
|
||||
opts,
|
||||
profiler_task.chan.clone());
|
||||
profiler_chan.clone());
|
||||
|
||||
let compositor_clone = compositor.clone();
|
||||
let script_task = ScriptTask::new(script_port.take(),
|
||||
script_chan.take(),
|
||||
engine_chan_clone.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_clone.set_ready_state(msg)
|
||||
compositor_chan_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,
|
||||
compositor_chan: compositor_chan.clone(),
|
||||
render_chan: render_chan.clone(),
|
||||
resource_task: resource_task.clone(),
|
||||
image_cache_task: image_cache_task.clone(),
|
||||
layout_task: layout_task,
|
||||
script_task: script_task,
|
||||
profiler_task: profiler_task,
|
||||
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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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>),
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,41 +61,21 @@ 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();
|
||||
pub fn new(chan: Chan<ScriptMsg>) -> ScriptChan {
|
||||
ScriptChan {
|
||||
chan: SharedChan::new(chan)
|
||||
}
|
||||
|
||||
ScriptTask {
|
||||
chan: script_chan
|
||||
}
|
||||
pub fn send(&self, msg: ScriptMsg) {
|
||||
self.chan.send(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,7 +92,7 @@ pub struct Frame {
|
|||
/// FIXME: Rename to `Page`, following WebKit?
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit da248d3f5b3ed6d9e804c543563be8e34baf1673
|
||||
Subproject commit d722188de3876ed748382965eb4f300fc1b78bf8
|
Loading…
Add table
Add a link
Reference in a new issue