mirror of
https://github.com/servo/servo.git
synced 2025-08-07 06:25:32 +01:00
auto merge of #550 : tkuehn/servo/master, r=metajack
When loading pages, the constellation spawns a new script<-->layout<-->renderer pipeline that loads in the background while scripts continue executing on the currently loaded page.
This commit is contained in:
commit
213d9a011a
33 changed files with 828 additions and 569 deletions
|
@ -2,7 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use servo_msg::compositor::LayerBuffer;
|
use servo_msg::compositor_msg::LayerBuffer;
|
||||||
use font_context::FontContext;
|
use font_context::FontContext;
|
||||||
use geometry::Au;
|
use geometry::Au;
|
||||||
use opts::Opts;
|
use opts::Opts;
|
||||||
|
|
|
@ -7,8 +7,9 @@
|
||||||
use azure::{AzFloat, AzGLContext};
|
use azure::{AzFloat, AzGLContext};
|
||||||
use azure::azure_hl::{B8G8R8A8, DrawTarget};
|
use azure::azure_hl::{B8G8R8A8, DrawTarget};
|
||||||
use display_list::DisplayList;
|
use display_list::DisplayList;
|
||||||
use servo_msg::compositor::{RenderListener, IdleRenderState, RenderingRenderState, LayerBuffer};
|
use servo_msg::compositor_msg::{RenderListener, IdleRenderState, RenderingRenderState, LayerBuffer};
|
||||||
use servo_msg::compositor::LayerBufferSet;
|
use servo_msg::compositor_msg::{CompositorToken, LayerBufferSet};
|
||||||
|
use servo_msg::constellation_msg::{ConstellationChan};
|
||||||
use font_context::FontContext;
|
use font_context::FontContext;
|
||||||
use geom::matrix2d::Matrix2D;
|
use geom::matrix2d::Matrix2D;
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
|
@ -29,70 +30,33 @@ pub struct RenderLayer {
|
||||||
size: Size2D<uint>
|
size: Size2D<uint>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Msg<C> {
|
pub enum Msg {
|
||||||
AttachCompositorMsg(C),
|
|
||||||
RenderMsg(RenderLayer),
|
RenderMsg(RenderLayer),
|
||||||
ReRenderMsg(f32),
|
ReRenderMsg(f32),
|
||||||
|
TokenBestowMsg(CompositorToken),
|
||||||
|
TokenInvalidateMsg,
|
||||||
ExitMsg(Chan<()>),
|
ExitMsg(Chan<()>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RenderChan<C> {
|
#[deriving(Clone)]
|
||||||
chan: SharedChan<Msg<C>>,
|
pub struct RenderChan {
|
||||||
|
chan: SharedChan<Msg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: RenderListener + Owned> Clone for RenderChan<C> {
|
impl RenderChan {
|
||||||
pub fn clone(&self) -> RenderChan<C> {
|
pub fn new(chan: Chan<Msg>) -> RenderChan {
|
||||||
RenderChan {
|
|
||||||
chan: self.chan.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C: RenderListener + Owned> RenderChan<C> {
|
|
||||||
pub fn new(chan: Chan<Msg<C>>) -> RenderChan<C> {
|
|
||||||
RenderChan {
|
RenderChan {
|
||||||
chan: SharedChan::new(chan),
|
chan: SharedChan::new(chan),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn send(&self, msg: Msg<C>) {
|
pub fn send(&self, msg: Msg) {
|
||||||
self.chan.send(msg);
|
self.chan.send(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_render_task<C: RenderListener + Owned>(port: Port<Msg<C>>,
|
priv struct RenderTask<C> {
|
||||||
compositor: C,
|
id: uint,
|
||||||
opts: Opts,
|
port: Port<Msg>,
|
||||||
profiler_chan: ProfilerChan) {
|
|
||||||
let compositor_cell = Cell::new(compositor);
|
|
||||||
let opts_cell = Cell::new(opts);
|
|
||||||
let port = Cell::new(port);
|
|
||||||
|
|
||||||
do spawn {
|
|
||||||
let compositor = compositor_cell.take();
|
|
||||||
let share_gl_context = compositor.get_gl_context();
|
|
||||||
let opts = opts_cell.with_ref(|o| copy *o);
|
|
||||||
let profiler_chan = profiler_chan.clone();
|
|
||||||
let profiler_chan_copy = profiler_chan.clone();
|
|
||||||
|
|
||||||
// FIXME: rust/#5967
|
|
||||||
let mut renderer = Renderer {
|
|
||||||
port: port.take(),
|
|
||||||
compositor: compositor,
|
|
||||||
font_ctx: @mut FontContext::new(opts.render_backend,
|
|
||||||
false,
|
|
||||||
profiler_chan),
|
|
||||||
opts: opts_cell.take(),
|
|
||||||
profiler_chan: profiler_chan_copy,
|
|
||||||
share_gl_context: share_gl_context,
|
|
||||||
render_layer: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
renderer.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
priv struct Renderer<C> {
|
|
||||||
port: Port<Msg<C>>,
|
|
||||||
compositor: C,
|
compositor: C,
|
||||||
font_ctx: @mut FontContext,
|
font_ctx: @mut FontContext,
|
||||||
opts: Opts,
|
opts: Opts,
|
||||||
|
@ -104,15 +68,60 @@ priv struct Renderer<C> {
|
||||||
|
|
||||||
/// The layer to be rendered
|
/// The layer to be rendered
|
||||||
render_layer: Option<RenderLayer>,
|
render_layer: Option<RenderLayer>,
|
||||||
|
/// A channel to the constellation for surrendering token
|
||||||
|
constellation_chan: ConstellationChan,
|
||||||
|
/// A token that grants permission to send paint messages to compositor
|
||||||
|
compositor_token: Option<CompositorToken>,
|
||||||
|
/// Cached copy of last layers rendered
|
||||||
|
last_paint_msg: Option<(LayerBufferSet, Size2D<uint>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: RenderListener + Owned> Renderer<C> {
|
impl<C: RenderListener + Owned> RenderTask<C> {
|
||||||
|
pub fn create(id: uint,
|
||||||
|
port: Port<Msg>,
|
||||||
|
compositor: C,
|
||||||
|
opts: Opts,
|
||||||
|
constellation_chan: ConstellationChan,
|
||||||
|
profiler_chan: ProfilerChan) {
|
||||||
|
let compositor_cell = Cell::new(compositor);
|
||||||
|
let opts_cell = Cell::new(opts);
|
||||||
|
let port = Cell::new(port);
|
||||||
|
let constellation_chan = Cell::new(constellation_chan);
|
||||||
|
|
||||||
|
do spawn {
|
||||||
|
let compositor = compositor_cell.take();
|
||||||
|
let share_gl_context = compositor.get_gl_context();
|
||||||
|
let opts = opts_cell.with_ref(|o| copy *o);
|
||||||
|
let profiler_chan = profiler_chan.clone();
|
||||||
|
let profiler_chan_clone = profiler_chan.clone();
|
||||||
|
|
||||||
|
// FIXME: rust/#5967
|
||||||
|
let mut render_task = RenderTask {
|
||||||
|
id: id,
|
||||||
|
port: port.take(),
|
||||||
|
compositor: compositor,
|
||||||
|
font_ctx: @mut FontContext::new(opts.render_backend,
|
||||||
|
false,
|
||||||
|
profiler_chan),
|
||||||
|
opts: opts_cell.take(),
|
||||||
|
profiler_chan: profiler_chan_clone,
|
||||||
|
share_gl_context: share_gl_context,
|
||||||
|
render_layer: None,
|
||||||
|
|
||||||
|
constellation_chan: constellation_chan.take(),
|
||||||
|
compositor_token: None,
|
||||||
|
last_paint_msg: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
render_task.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn start(&mut self) {
|
fn start(&mut self) {
|
||||||
debug!("renderer: beginning rendering loop");
|
debug!("render_task: beginning rendering loop");
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match self.port.recv() {
|
match self.port.recv() {
|
||||||
AttachCompositorMsg(compositor) => self.compositor = compositor,
|
|
||||||
RenderMsg(render_layer) => {
|
RenderMsg(render_layer) => {
|
||||||
self.render_layer = Some(render_layer);
|
self.render_layer = Some(render_layer);
|
||||||
self.render(1.0);
|
self.render(1.0);
|
||||||
|
@ -120,6 +129,19 @@ impl<C: RenderListener + Owned> Renderer<C> {
|
||||||
ReRenderMsg(scale) => {
|
ReRenderMsg(scale) => {
|
||||||
self.render(scale);
|
self.render(scale);
|
||||||
}
|
}
|
||||||
|
TokenBestowMsg(token) => {
|
||||||
|
self.compositor_token = Some(token);
|
||||||
|
match self.last_paint_msg {
|
||||||
|
Some((ref layer_buffer_set, ref layer_size)) => {
|
||||||
|
self.compositor.paint(self.id, layer_buffer_set.clone(), *layer_size);
|
||||||
|
self.compositor.set_render_state(IdleRenderState);
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TokenInvalidateMsg => {
|
||||||
|
self.compositor_token = None;
|
||||||
|
}
|
||||||
ExitMsg(response_ch) => {
|
ExitMsg(response_ch) => {
|
||||||
response_ch.send(());
|
response_ch.send(());
|
||||||
break;
|
break;
|
||||||
|
@ -129,7 +151,7 @@ impl<C: RenderListener + Owned> Renderer<C> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(&mut self, scale: f32) {
|
fn render(&mut self, scale: f32) {
|
||||||
debug!("renderer: rendering");
|
debug!("render_task: rendering");
|
||||||
|
|
||||||
let render_layer;
|
let render_layer;
|
||||||
match (self.render_layer) {
|
match (self.render_layer) {
|
||||||
|
@ -140,7 +162,7 @@ impl<C: RenderListener + Owned> Renderer<C> {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.compositor.set_render_state(RenderingRenderState);
|
self.compositor.set_render_state(RenderingRenderState);
|
||||||
do profile(time::RenderingCategory, self.profiler_chan.clone()) {
|
do time::profile(time::RenderingCategory, self.profiler_chan.clone()) {
|
||||||
let tile_size = self.opts.tile_size;
|
let tile_size = self.opts.tile_size;
|
||||||
|
|
||||||
// FIXME: Try not to create a new array here.
|
// FIXME: Try not to create a new array here.
|
||||||
|
@ -164,7 +186,8 @@ impl<C: RenderListener + Owned> Renderer<C> {
|
||||||
let buffer = LayerBuffer {
|
let buffer = LayerBuffer {
|
||||||
draw_target: DrawTarget::new_with_fbo(self.opts.render_backend,
|
draw_target: DrawTarget::new_with_fbo(self.opts.render_backend,
|
||||||
self.share_gl_context,
|
self.share_gl_context,
|
||||||
Size2D(width as i32, height as i32),
|
Size2D(width as i32,
|
||||||
|
height as i32),
|
||||||
B8G8R8A8),
|
B8G8R8A8),
|
||||||
rect: tile_rect,
|
rect: tile_rect,
|
||||||
screen_pos: screen_rect,
|
screen_pos: screen_rect,
|
||||||
|
@ -210,8 +233,12 @@ impl<C: RenderListener + Owned> Renderer<C> {
|
||||||
buffers: new_buffers,
|
buffers: new_buffers,
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("renderer: returning surface");
|
debug!("render_task: returning surface");
|
||||||
self.compositor.paint(layer_buffer_set, render_layer.size);
|
if self.compositor_token.is_some() {
|
||||||
|
self.compositor.paint(self.id, layer_buffer_set.clone(), render_layer.size);
|
||||||
|
}
|
||||||
|
debug!("caching paint msg");
|
||||||
|
self.last_paint_msg = Some((layer_buffer_set, render_layer.size));
|
||||||
self.compositor.set_render_state(IdleRenderState);
|
self.compositor.set_render_state(IdleRenderState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,16 @@
|
||||||
|
|
||||||
use platform::{Application, Window};
|
use platform::{Application, Window};
|
||||||
use script::dom::event::{Event, ClickEvent, MouseDownEvent, MouseUpEvent, ResizeEvent};
|
use script::dom::event::{Event, ClickEvent, MouseDownEvent, MouseUpEvent, ResizeEvent};
|
||||||
use script::script_task::{LoadMsg, SendEventMsg};
|
use script::script_task::{LoadMsg, NavigateMsg, SendEventMsg};
|
||||||
use script::layout_interface::{LayoutChan, RouteScriptMsg};
|
use script::layout_interface::{LayoutChan, RouteScriptMsg};
|
||||||
use windowing::{ApplicationMethods, WindowMethods, WindowMouseEvent, WindowClickEvent};
|
use windowing::{ApplicationMethods, WindowMethods, WindowMouseEvent, WindowClickEvent};
|
||||||
use windowing::{WindowMouseDownEvent, WindowMouseUpEvent};
|
use windowing::{WindowMouseDownEvent, WindowMouseUpEvent};
|
||||||
use servo_msg::compositor::{RenderListener, LayerBufferSet, RenderState};
|
|
||||||
use servo_msg::compositor::{ReadyState, ScriptListener};
|
|
||||||
|
use servo_msg::compositor_msg::{RenderListener, LayerBufferSet, RenderState};
|
||||||
|
use servo_msg::compositor_msg::{ReadyState, ScriptListener};
|
||||||
|
use servo_msg::constellation_msg::{CompositorAck, ConstellationChan};
|
||||||
|
use servo_msg::constellation_msg;
|
||||||
use gfx::render_task::{RenderChan, ReRenderMsg};
|
use gfx::render_task::{RenderChan, ReRenderMsg};
|
||||||
|
|
||||||
use azure::azure_hl::{DataSourceSurface, DrawTarget, SourceSurfaceMethods, current_gl_context};
|
use azure::azure_hl::{DataSourceSurface, DrawTarget, SourceSurfaceMethods, current_gl_context};
|
||||||
|
@ -32,6 +36,7 @@ use servo_util::{time, url};
|
||||||
use servo_util::time::profile;
|
use servo_util::time::profile;
|
||||||
use servo_util::time::ProfilerChan;
|
use servo_util::time::ProfilerChan;
|
||||||
|
|
||||||
|
pub use windowing;
|
||||||
|
|
||||||
/// The implementation of the layers-based compositor.
|
/// The implementation of the layers-based compositor.
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
|
@ -55,8 +60,8 @@ impl RenderListener for CompositorChan {
|
||||||
self.chan.send(GetGLContext(chan));
|
self.chan.send(GetGLContext(chan));
|
||||||
port.recv()
|
port.recv()
|
||||||
}
|
}
|
||||||
fn paint(&self, layer_buffer_set: LayerBufferSet, new_size: Size2D<uint>) {
|
fn paint(&self, id: uint, layer_buffer_set: LayerBufferSet, new_size: Size2D<uint>) {
|
||||||
self.chan.send(Paint(layer_buffer_set, new_size))
|
self.chan.send(Paint(id, layer_buffer_set, new_size))
|
||||||
}
|
}
|
||||||
fn set_render_state(&self, render_state: RenderState) {
|
fn set_render_state(&self, render_state: RenderState) {
|
||||||
self.chan.send(ChangeRenderState(render_state))
|
self.chan.send(ChangeRenderState(render_state))
|
||||||
|
@ -81,15 +86,13 @@ pub enum Msg {
|
||||||
/// Requests the compositors GL context.
|
/// Requests the compositors GL context.
|
||||||
GetGLContext(Chan<AzGLContext>),
|
GetGLContext(Chan<AzGLContext>),
|
||||||
/// Requests that the compositor paint the given layer buffer set for the given page size.
|
/// Requests that the compositor paint the given layer buffer set for the given page size.
|
||||||
Paint(LayerBufferSet, Size2D<uint>),
|
Paint(uint, LayerBufferSet, Size2D<uint>),
|
||||||
/// Alerts the compositor to the current status of page loading.
|
/// Alerts the compositor to the current status of page loading.
|
||||||
ChangeReadyState(ReadyState),
|
ChangeReadyState(ReadyState),
|
||||||
/// Alerts the compositor to the current status of rendering.
|
/// Alerts the compositor to the current status of rendering.
|
||||||
ChangeRenderState(RenderState),
|
ChangeRenderState(RenderState),
|
||||||
/// Sets the channel to the current layout task
|
/// Sets the channel to the current layout and render tasks, along with their id
|
||||||
SetLayoutChan(LayoutChan),
|
SetLayoutRenderChans(LayoutChan, RenderChan , uint, ConstellationChan)
|
||||||
/// Sets the channel to the current renderer
|
|
||||||
SetRenderChan(RenderChan<CompositorChan>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Azure surface wrapping to work with the layers infrastructure.
|
/// Azure surface wrapping to work with the layers infrastructure.
|
||||||
|
@ -176,9 +179,19 @@ impl CompositorTask {
|
||||||
let local_zoom = @mut 1f32;
|
let local_zoom = @mut 1f32;
|
||||||
// Channel to the current renderer.
|
// Channel to the current renderer.
|
||||||
// FIXME: This probably shouldn't be stored like this.
|
// FIXME: This probably shouldn't be stored like this.
|
||||||
let render_chan: @mut Option<RenderChan<CompositorChan>> = @mut None;
|
let render_chan: @mut Option<RenderChan> = @mut None;
|
||||||
|
let pipeline_id: @mut Option<uint> = @mut None;
|
||||||
|
|
||||||
let update_layout_callbacks: @fn(LayoutChan) = |layout_chan: LayoutChan| {
|
let update_layout_callbacks: @fn(LayoutChan) = |layout_chan: LayoutChan| {
|
||||||
|
let layout_chan_clone = layout_chan.clone();
|
||||||
|
do window.set_navigation_callback |direction| {
|
||||||
|
let direction = match direction {
|
||||||
|
windowing::Forward => constellation_msg::Forward,
|
||||||
|
windowing::Back => constellation_msg::Back,
|
||||||
|
};
|
||||||
|
layout_chan_clone.send(RouteScriptMsg(NavigateMsg(direction)));
|
||||||
|
}
|
||||||
|
|
||||||
let layout_chan_clone = layout_chan.clone();
|
let layout_chan_clone = layout_chan.clone();
|
||||||
// Hook the windowing system's resize callback up to the resize rate limiter.
|
// Hook the windowing system's resize callback up to the resize rate limiter.
|
||||||
do window.set_resize_callback |width, height| {
|
do window.set_resize_callback |width, height| {
|
||||||
|
@ -186,7 +199,7 @@ impl CompositorTask {
|
||||||
if *window_size != new_size {
|
if *window_size != new_size {
|
||||||
debug!("osmain: window resized to %ux%u", width, height);
|
debug!("osmain: window resized to %ux%u", width, height);
|
||||||
*window_size = new_size;
|
*window_size = new_size;
|
||||||
layout_chan_clone.chan.send(RouteScriptMsg(SendEventMsg(ResizeEvent(width, height))));
|
layout_chan_clone.send(RouteScriptMsg(SendEventMsg(ResizeEvent(width, height))));
|
||||||
} else {
|
} else {
|
||||||
debug!("osmain: dropping window resize since size is still %ux%u", width, height);
|
debug!("osmain: dropping window resize since size is still %ux%u", width, height);
|
||||||
}
|
}
|
||||||
|
@ -197,7 +210,7 @@ impl CompositorTask {
|
||||||
// When the user enters a new URL, load it.
|
// When the user enters a new URL, load it.
|
||||||
do window.set_load_url_callback |url_string| {
|
do window.set_load_url_callback |url_string| {
|
||||||
debug!("osmain: loading URL `%s`", url_string);
|
debug!("osmain: loading URL `%s`", url_string);
|
||||||
layout_chan_clone.chan.send(RouteScriptMsg(LoadMsg(url::make_url(url_string.to_str(), None))));
|
layout_chan_clone.send(RouteScriptMsg(LoadMsg(url::make_url(url_string.to_str(), None))));
|
||||||
}
|
}
|
||||||
|
|
||||||
let layout_chan_clone = layout_chan.clone();
|
let layout_chan_clone = layout_chan.clone();
|
||||||
|
@ -229,7 +242,7 @@ impl CompositorTask {
|
||||||
event = MouseUpEvent(button, world_mouse_point(layer_mouse_point));
|
event = MouseUpEvent(button, world_mouse_point(layer_mouse_point));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
layout_chan_clone.chan.send(RouteScriptMsg(SendEventMsg(event)));
|
layout_chan_clone.send(RouteScriptMsg(SendEventMsg(event)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -242,17 +255,24 @@ impl CompositorTask {
|
||||||
ChangeReadyState(ready_state) => window.set_ready_state(ready_state),
|
ChangeReadyState(ready_state) => window.set_ready_state(ready_state),
|
||||||
ChangeRenderState(render_state) => window.set_render_state(render_state),
|
ChangeRenderState(render_state) => window.set_render_state(render_state),
|
||||||
|
|
||||||
SetLayoutChan(layout_chan) => {
|
SetLayoutRenderChans(new_layout_chan,
|
||||||
update_layout_callbacks(layout_chan);
|
new_render_chan,
|
||||||
}
|
new_pipeline_id,
|
||||||
|
response_chan) => {
|
||||||
SetRenderChan(new_render_chan) => {
|
update_layout_callbacks(new_layout_chan);
|
||||||
*render_chan = Some(new_render_chan);
|
*render_chan = Some(new_render_chan);
|
||||||
|
*pipeline_id = Some(new_pipeline_id);
|
||||||
|
response_chan.send(CompositorAck(new_pipeline_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
GetGLContext(chan) => chan.send(current_gl_context()),
|
GetGLContext(chan) => chan.send(current_gl_context()),
|
||||||
|
|
||||||
Paint(new_layer_buffer_set, new_size) => {
|
Paint(id, new_layer_buffer_set, new_size) => {
|
||||||
|
match *pipeline_id {
|
||||||
|
Some(pipeline_id) => if id != pipeline_id { loop; },
|
||||||
|
None => { loop; },
|
||||||
|
}
|
||||||
|
|
||||||
debug!("osmain: received new frame");
|
debug!("osmain: received new frame");
|
||||||
|
|
||||||
*page_size = Size2D(new_size.width as f32, new_size.height as f32);
|
*page_size = Size2D(new_size.width as f32, new_size.height as f32);
|
||||||
|
@ -410,6 +430,7 @@ impl CompositorTask {
|
||||||
|
|
||||||
window.set_needs_display()
|
window.set_needs_display()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enter the main event loop.
|
// Enter the main event loop.
|
||||||
while !*done {
|
while !*done {
|
||||||
// Check for new messages coming from the rendering task.
|
// Check for new messages coming from the rendering task.
|
||||||
|
@ -432,3 +453,4 @@ fn on_osmain(f: ~fn()) {
|
||||||
f();
|
f();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
255
src/components/main/constellation.rs
Normal file
255
src/components/main/constellation.rs
Normal file
|
@ -0,0 +1,255 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use compositing::{CompositorChan, SetLayoutRenderChans};
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::comm;
|
||||||
|
use std::comm::Port;
|
||||||
|
use std::task;
|
||||||
|
use gfx::opts::Opts;
|
||||||
|
use gfx::render_task::{TokenBestowMsg, TokenInvalidateMsg};
|
||||||
|
use pipeline::Pipeline;
|
||||||
|
use servo_msg::compositor_msg::{CompositorToken};
|
||||||
|
use servo_msg::constellation_msg::{CompositorAck, ConstellationChan, ExitMsg};
|
||||||
|
use servo_msg::constellation_msg::{LoadUrlMsg, Msg, NavigateMsg, RendererReadyMsg};
|
||||||
|
use servo_msg::constellation_msg;
|
||||||
|
use script::script_task::ExecuteMsg;
|
||||||
|
use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
|
||||||
|
use servo_net::resource_task::ResourceTask;
|
||||||
|
use servo_net::resource_task;
|
||||||
|
use servo_util::time::ProfilerChan;
|
||||||
|
use std::hashmap::HashMap;
|
||||||
|
use std::util::replace;
|
||||||
|
|
||||||
|
/// Maintains the pipelines and navigation context and grants permission to composite
|
||||||
|
pub struct Constellation {
|
||||||
|
chan: ConstellationChan,
|
||||||
|
request_port: Port<Msg>,
|
||||||
|
compositor_chan: CompositorChan,
|
||||||
|
resource_task: ResourceTask,
|
||||||
|
image_cache_task: ImageCacheTask,
|
||||||
|
pipelines: HashMap<uint, Pipeline>,
|
||||||
|
navigation_context: NavigationContext,
|
||||||
|
next_id: uint,
|
||||||
|
current_token_bearer: Option<uint>,
|
||||||
|
next_token_bearer: Option<uint>,
|
||||||
|
profiler_chan: ProfilerChan,
|
||||||
|
opts: Opts,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stores the ID's of the pipelines previous and next in the browser's history
|
||||||
|
pub struct NavigationContext {
|
||||||
|
previous: ~[uint],
|
||||||
|
next: ~[uint],
|
||||||
|
current: Option<uint>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NavigationContext {
|
||||||
|
pub fn new() -> NavigationContext {
|
||||||
|
NavigationContext {
|
||||||
|
previous: ~[],
|
||||||
|
next: ~[],
|
||||||
|
current: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note that the following two methods can fail. They should only be called *
|
||||||
|
* when it is known that, e.g., there exists a previous page or a next page. */
|
||||||
|
|
||||||
|
pub fn back(&mut self) -> uint {
|
||||||
|
self.next.push(self.current.get());
|
||||||
|
self.current = Some(self.previous.pop());
|
||||||
|
debug!("previous: %? next: %? current: %?", self.previous, self.next, self.current);
|
||||||
|
self.current.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn forward(&mut self) -> uint {
|
||||||
|
self.previous.push(self.current.get());
|
||||||
|
self.current = Some(self.next.pop());
|
||||||
|
debug!("previous: %? next: %? current: %?", self.previous, self.next, self.current);
|
||||||
|
self.current.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Navigates to a new id, returning all id's evicted from next
|
||||||
|
pub fn navigate(&mut self, id: uint) -> ~[uint] {
|
||||||
|
let evicted = replace(&mut self.next, ~[]);
|
||||||
|
do self.current.mutate_default(id) |cur_id| {
|
||||||
|
self.previous.push(cur_id);
|
||||||
|
id
|
||||||
|
}
|
||||||
|
evicted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Constellation {
|
||||||
|
pub fn start(compositor_chan: CompositorChan,
|
||||||
|
opts: &Opts,
|
||||||
|
resource_task: ResourceTask,
|
||||||
|
image_cache_task: ImageCacheTask,
|
||||||
|
profiler_chan: ProfilerChan)
|
||||||
|
-> ConstellationChan {
|
||||||
|
|
||||||
|
let opts = Cell::new(copy *opts);
|
||||||
|
|
||||||
|
let (constellation_port, constellation_chan) = special_stream!(ConstellationChan);
|
||||||
|
let constellation_port = Cell::new(constellation_port);
|
||||||
|
|
||||||
|
let compositor_chan = Cell::new(compositor_chan);
|
||||||
|
let constellation_chan_clone = Cell::new(constellation_chan.clone());
|
||||||
|
|
||||||
|
let resource_task = Cell::new(resource_task);
|
||||||
|
let image_cache_task = Cell::new(image_cache_task);
|
||||||
|
let profiler_chan = Cell::new(profiler_chan);
|
||||||
|
|
||||||
|
do task::spawn {
|
||||||
|
let mut constellation = Constellation {
|
||||||
|
chan: constellation_chan_clone.take(),
|
||||||
|
request_port: constellation_port.take(),
|
||||||
|
compositor_chan: compositor_chan.take(),
|
||||||
|
resource_task: resource_task.take(),
|
||||||
|
image_cache_task: image_cache_task.take(),
|
||||||
|
pipelines: HashMap::new(),
|
||||||
|
navigation_context: NavigationContext::new(),
|
||||||
|
next_id: 0,
|
||||||
|
current_token_bearer: None,
|
||||||
|
next_token_bearer: None,
|
||||||
|
profiler_chan: profiler_chan.take(),
|
||||||
|
opts: opts.take(),
|
||||||
|
};
|
||||||
|
constellation.run();
|
||||||
|
}
|
||||||
|
constellation_chan
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&mut self) {
|
||||||
|
loop {
|
||||||
|
let request = self.request_port.recv();
|
||||||
|
if !self.handle_request(request) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper function for getting a unique pipeline ID
|
||||||
|
fn get_next_id(&mut self) -> uint {
|
||||||
|
let id = self.next_id;
|
||||||
|
self.next_id = id + 1;
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handles loading pages, navigation, and granting access to the compositor
|
||||||
|
fn handle_request(&mut self, request: Msg) -> bool {
|
||||||
|
match request {
|
||||||
|
// Load a new page, usually either from a mouse click or typed url
|
||||||
|
LoadUrlMsg(url) => {
|
||||||
|
let pipeline_id = self.get_next_id();
|
||||||
|
let mut pipeline = Pipeline::create(pipeline_id,
|
||||||
|
self.chan.clone(),
|
||||||
|
self.compositor_chan.clone(),
|
||||||
|
self.image_cache_task.clone(),
|
||||||
|
self.resource_task.clone(),
|
||||||
|
self.profiler_chan.clone(),
|
||||||
|
copy self.opts);
|
||||||
|
if url.path.ends_with(".js") {
|
||||||
|
pipeline.script_chan.send(ExecuteMsg(url));
|
||||||
|
} else {
|
||||||
|
pipeline.load(url);
|
||||||
|
pipeline.navigation_type = Some(constellation_msg::Load);
|
||||||
|
self.next_token_bearer = Some(pipeline_id);
|
||||||
|
}
|
||||||
|
self.pipelines.insert(pipeline_id, pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle a forward or back request
|
||||||
|
NavigateMsg(direction) => {
|
||||||
|
debug!("received message to navigate %?", direction);
|
||||||
|
let destination_id = match direction {
|
||||||
|
constellation_msg::Forward => {
|
||||||
|
if self.navigation_context.next.is_empty() {
|
||||||
|
debug!("no next page to navigate to");
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
self.navigation_context.forward()
|
||||||
|
}
|
||||||
|
constellation_msg::Back => {
|
||||||
|
if self.navigation_context.previous.is_empty() {
|
||||||
|
debug!("no previous page to navigate to");
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
self.navigation_context.back()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
debug!("navigating to pipeline %u", destination_id);
|
||||||
|
let mut pipeline = self.pipelines.pop(&destination_id).unwrap();
|
||||||
|
pipeline.navigation_type = Some(constellation_msg::Navigate);
|
||||||
|
pipeline.reload();
|
||||||
|
self.pipelines.insert(destination_id, pipeline);
|
||||||
|
self.next_token_bearer = Some(destination_id);
|
||||||
|
self.update_token_bearer();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notification that rendering has finished and is requesting permission to paint.
|
||||||
|
RendererReadyMsg(pipeline_id) => {
|
||||||
|
let next_token_bearer = self.next_token_bearer;
|
||||||
|
for next_token_bearer.iter().advance |&id| {
|
||||||
|
if pipeline_id == id {
|
||||||
|
self.update_token_bearer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Acknowledgement from the compositor that it has updated its active pipeline id
|
||||||
|
CompositorAck(id) => {
|
||||||
|
self.bestow_compositor_token(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExitMsg(sender) => {
|
||||||
|
for self.pipelines.each |_, pipeline| {
|
||||||
|
pipeline.exit();
|
||||||
|
}
|
||||||
|
self.image_cache_task.exit();
|
||||||
|
self.resource_task.send(resource_task::Exit);
|
||||||
|
|
||||||
|
sender.send(());
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_token_bearer(&mut self) {
|
||||||
|
let current_token_bearer = replace(&mut self.current_token_bearer, None);
|
||||||
|
for current_token_bearer.iter().advance |id| {
|
||||||
|
self.pipelines.get(id).render_chan.send(TokenInvalidateMsg);
|
||||||
|
}
|
||||||
|
let id = self.next_token_bearer.get();
|
||||||
|
let pipeline = self.pipelines.get(&id);
|
||||||
|
self.compositor_chan.send(SetLayoutRenderChans(pipeline.layout_chan.clone(),
|
||||||
|
pipeline.render_chan.clone(),
|
||||||
|
id,
|
||||||
|
self.chan.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sends a compositor token to a renderer; optionally updates navigation to reflect a new page
|
||||||
|
fn bestow_compositor_token(&mut self, id: uint) {
|
||||||
|
let pipeline = self.pipelines.get(&id);
|
||||||
|
pipeline.render_chan.send(TokenBestowMsg(CompositorToken::new()));
|
||||||
|
self.current_token_bearer = Some(id);
|
||||||
|
self.next_token_bearer = None;
|
||||||
|
// Don't navigate on Navigate type, because that is handled by forward/back
|
||||||
|
match pipeline.navigation_type.get() {
|
||||||
|
constellation_msg::Load => {
|
||||||
|
let evicted = self.navigation_context.navigate(id);
|
||||||
|
/* FIXME(tkuehn): the following code causes a segfault
|
||||||
|
for evicted.iter().advance |id| {
|
||||||
|
self.pipelines.get(id).exit();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ use extra::net::url::Url;
|
||||||
use url_from_str = extra::net::url::from_str;
|
use url_from_str = extra::net::url::from_str;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::str;
|
|
||||||
use newcss::stylesheet::Stylesheet;
|
use newcss::stylesheet::Stylesheet;
|
||||||
use newcss::select::SelectCtx;
|
use newcss::select::SelectCtx;
|
||||||
use newcss::types::OriginUA;
|
use newcss::types::OriginUA;
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
/// Implementation of the callbacks that the CSS selector engine uses to query the DOM.
|
/// Implementation of the callbacks that the CSS selector engine uses to query the DOM.
|
||||||
///
|
///
|
||||||
|
|
||||||
use std::str;
|
|
||||||
use std::str::eq_slice;
|
use std::str::eq_slice;
|
||||||
use newcss::select::SelectHandler;
|
use newcss::select::SelectHandler;
|
||||||
use script::dom::node::{AbstractNode, LayoutView};
|
use script::dom::node::{AbstractNode, LayoutView};
|
||||||
|
|
|
@ -1,152 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
use compositing::{CompositorChan, SetLayoutChan, SetRenderChan};
|
|
||||||
use layout::layout_task;
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::comm;
|
|
||||||
use std::comm::Port;
|
|
||||||
use std::task;
|
|
||||||
use gfx::opts::Opts;
|
|
||||||
use gfx::render_task::RenderChan;
|
|
||||||
use gfx::render_task;
|
|
||||||
use servo_msg::compositor::{ScriptListener, ReadyState};
|
|
||||||
use servo_msg::engine::{EngineChan, ExitMsg, LoadUrlMsg, Msg};
|
|
||||||
use script::layout_interface::LayoutChan;
|
|
||||||
use script::layout_interface;
|
|
||||||
use script::script_task::{ExecuteMsg, LoadMsg, ScriptMsg, ScriptContext, ScriptChan};
|
|
||||||
use script::script_task;
|
|
||||||
use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
|
|
||||||
use servo_net::resource_task::ResourceTask;
|
|
||||||
use servo_net::resource_task;
|
|
||||||
use servo_util::time::{ProfilerChan};
|
|
||||||
|
|
||||||
pub struct Engine {
|
|
||||||
request_port: Port<Msg>,
|
|
||||||
compositor_chan: CompositorChan,
|
|
||||||
render_chan: RenderChan<CompositorChan>,
|
|
||||||
resource_task: ResourceTask,
|
|
||||||
image_cache_task: ImageCacheTask,
|
|
||||||
layout_chan: LayoutChan,
|
|
||||||
script_chan: ScriptChan,
|
|
||||||
profiler_chan: ProfilerChan,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Engine {
|
|
||||||
pub fn start(compositor_chan: CompositorChan,
|
|
||||||
opts: &Opts,
|
|
||||||
resource_task: ResourceTask,
|
|
||||||
image_cache_task: ImageCacheTask,
|
|
||||||
profiler_chan: ProfilerChan)
|
|
||||||
-> EngineChan {
|
|
||||||
macro_rules! closure_stream(
|
|
||||||
($Msg:ty, $Chan:ident) => (
|
|
||||||
{
|
|
||||||
let (port, chan) = comm::stream::<$Msg>();
|
|
||||||
(Cell::new(port), $Chan::new(chan))
|
|
||||||
}
|
|
||||||
);
|
|
||||||
)
|
|
||||||
|
|
||||||
// Create the script port and channel.
|
|
||||||
let (script_port, script_chan) = closure_stream!(ScriptMsg, ScriptChan);
|
|
||||||
|
|
||||||
// Create the engine port and channel.
|
|
||||||
let (engine_port, engine_chan) = closure_stream!(Msg, EngineChan);
|
|
||||||
|
|
||||||
// Create the layout port and channel.
|
|
||||||
let (layout_port, layout_chan) = closure_stream!(layout_interface::Msg, LayoutChan);
|
|
||||||
|
|
||||||
let (render_port, render_chan) = comm::stream::<render_task::Msg<CompositorChan>>();
|
|
||||||
let (render_port, render_chan) = (Cell::new(render_port), RenderChan::new(render_chan));
|
|
||||||
|
|
||||||
|
|
||||||
compositor_chan.send(SetLayoutChan(layout_chan.clone()));
|
|
||||||
compositor_chan.send(SetRenderChan(render_chan.clone()));
|
|
||||||
|
|
||||||
let compositor_chan = Cell::new(compositor_chan);
|
|
||||||
|
|
||||||
let opts = Cell::new(copy *opts);
|
|
||||||
|
|
||||||
{
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self) {
|
|
||||||
while self.handle_request(self.request_port.recv()) {
|
|
||||||
// Go on...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_request(&self, request: Msg) -> bool {
|
|
||||||
match request {
|
|
||||||
LoadUrlMsg(url) => {
|
|
||||||
if url.path.ends_with(".js") {
|
|
||||||
self.script_chan.send(ExecuteMsg(url))
|
|
||||||
} else {
|
|
||||||
self.script_chan.send(LoadMsg(url))
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
ExitMsg(sender) => {
|
|
||||||
self.script_chan.send(script_task::ExitMsg);
|
|
||||||
self.layout_chan.send(layout_interface::ExitMsg);
|
|
||||||
|
|
||||||
let (response_port, response_chan) = comm::stream();
|
|
||||||
|
|
||||||
self.render_chan.send(render_task::ExitMsg(response_chan));
|
|
||||||
response_port.recv();
|
|
||||||
|
|
||||||
self.image_cache_task.exit();
|
|
||||||
self.resource_task.send(resource_task::Exit);
|
|
||||||
|
|
||||||
sender.send(());
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -840,7 +840,7 @@ impl RenderBox {
|
||||||
pub fn dump_indent(&self, indent: uint) {
|
pub fn dump_indent(&self, indent: uint) {
|
||||||
let mut string = ~"";
|
let mut string = ~"";
|
||||||
for uint::range(0u, indent) |_i| {
|
for uint::range(0u, indent) |_i| {
|
||||||
string += ~" ";
|
string += " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
string += self.debug_str();
|
string += self.debug_str();
|
||||||
|
|
|
@ -394,7 +394,7 @@ impl<'self> FlowContext {
|
||||||
pub fn dump_indent(&self, indent: uint) {
|
pub fn dump_indent(&self, indent: uint) {
|
||||||
let mut s = ~"|";
|
let mut s = ~"|";
|
||||||
for uint::range(0, indent) |_i| {
|
for uint::range(0, indent) |_i| {
|
||||||
s += ~"---- ";
|
s += "---- ";
|
||||||
}
|
}
|
||||||
|
|
||||||
s += self.debug_str();
|
s += self.debug_str();
|
||||||
|
@ -412,7 +412,7 @@ impl<'self> FlowContext {
|
||||||
let mut s = inline.boxes.foldl(~"InlineFlow(children=", |s, box| {
|
let mut s = inline.boxes.foldl(~"InlineFlow(children=", |s, box| {
|
||||||
fmt!("%s b%d", *s, box.id())
|
fmt!("%s b%d", *s, box.id())
|
||||||
});
|
});
|
||||||
s += ~")";
|
s += ")";
|
||||||
s
|
s
|
||||||
},
|
},
|
||||||
BlockFlow(block) => {
|
BlockFlow(block) => {
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
//! The layout task. Performs layout on the DOM, builds display lists and sends them to be
|
//! The layout task. Performs layout on the DOM, builds display lists and sends them to be
|
||||||
/// rendered.
|
/// rendered.
|
||||||
|
|
||||||
use compositing::CompositorChan;
|
|
||||||
use css::matching::MatchMethods;
|
use css::matching::MatchMethods;
|
||||||
use css::select::new_css_select_ctx;
|
use css::select::new_css_select_ctx;
|
||||||
use layout::aux::{LayoutData, LayoutAuxMethods};
|
use layout::aux::{LayoutData, LayoutAuxMethods};
|
||||||
|
@ -17,7 +16,7 @@ use layout::flow::FlowContext;
|
||||||
|
|
||||||
use std::cast::transmute;
|
use std::cast::transmute;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::comm::{Chan, Port};
|
use std::comm::{Port};
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
use geom::rect::Rect;
|
use geom::rect::Rect;
|
||||||
use geom::size::Size2D;
|
use geom::size::Size2D;
|
||||||
|
@ -34,39 +33,21 @@ use script::dom::node::{AbstractNode, LayoutView};
|
||||||
use script::layout_interface::{AddStylesheetMsg, ContentBoxQuery};
|
use script::layout_interface::{AddStylesheetMsg, ContentBoxQuery};
|
||||||
use script::layout_interface::{HitTestQuery, ContentBoxResponse, HitTestResponse};
|
use script::layout_interface::{HitTestQuery, ContentBoxResponse, HitTestResponse};
|
||||||
use script::layout_interface::{ContentBoxesQuery, ContentBoxesResponse, ExitMsg, LayoutQuery};
|
use script::layout_interface::{ContentBoxesQuery, ContentBoxesResponse, ExitMsg, LayoutQuery};
|
||||||
use script::layout_interface::{LayoutResponse, MatchSelectorsDocumentDamage, Msg};
|
use script::layout_interface::{MatchSelectorsDocumentDamage, Msg};
|
||||||
use script::layout_interface::{QueryMsg, RouteScriptMsg, Reflow, ReflowDocumentDamage};
|
use script::layout_interface::{QueryMsg, RouteScriptMsg, Reflow, ReflowDocumentDamage};
|
||||||
use script::layout_interface::{ReflowForDisplay, ReflowMsg};
|
use script::layout_interface::{ReflowForDisplay, ReflowMsg};
|
||||||
use script::script_task::{ReflowCompleteMsg, ScriptChan, ScriptMsg, SendEventMsg};
|
use script::script_task::{ReflowCompleteMsg, ScriptChan, ScriptMsg, SendEventMsg};
|
||||||
use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg};
|
use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg};
|
||||||
use servo_net::local_image_cache::LocalImageCache;
|
use servo_net::local_image_cache::LocalImageCache;
|
||||||
use servo_util::tree::{TreeNodeRef, TreeUtils};
|
use servo_util::tree::{TreeNodeRef, TreeUtils};
|
||||||
use servo_util::time::{ProfilerChan, profile, time};
|
use servo_util::time::{ProfilerChan, profile};
|
||||||
use servo_util::time;
|
use servo_util::time;
|
||||||
use extra::net::url::Url;
|
use extra::net::url::Url;
|
||||||
|
|
||||||
pub fn create_layout_task(port: Port<Msg>,
|
struct LayoutTask {
|
||||||
script_chan: ScriptChan,
|
|
||||||
render_chan: RenderChan<CompositorChan>,
|
|
||||||
img_cache_task: ImageCacheTask,
|
|
||||||
opts: Opts,
|
|
||||||
profiler_chan: ProfilerChan) {
|
|
||||||
let port = Cell::new(port);
|
|
||||||
do spawn {
|
|
||||||
let mut layout = Layout::new(port.take(),
|
|
||||||
script_chan.clone(),
|
|
||||||
render_chan.clone(),
|
|
||||||
img_cache_task.clone(),
|
|
||||||
&opts,
|
|
||||||
profiler_chan.clone());
|
|
||||||
layout.start();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Layout {
|
|
||||||
port: Port<Msg>,
|
port: Port<Msg>,
|
||||||
script_chan: ScriptChan,
|
script_chan: ScriptChan,
|
||||||
render_chan: RenderChan<CompositorChan>,
|
render_chan: RenderChan,
|
||||||
image_cache_task: ImageCacheTask,
|
image_cache_task: ImageCacheTask,
|
||||||
local_image_cache: @mut LocalImageCache,
|
local_image_cache: @mut LocalImageCache,
|
||||||
font_ctx: @mut FontContext,
|
font_ctx: @mut FontContext,
|
||||||
|
@ -80,17 +61,35 @@ struct Layout {
|
||||||
profiler_chan: ProfilerChan,
|
profiler_chan: ProfilerChan,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Layout {
|
impl LayoutTask {
|
||||||
|
pub fn create(port: Port<Msg>,
|
||||||
|
script_chan: ScriptChan,
|
||||||
|
render_chan: RenderChan,
|
||||||
|
img_cache_task: ImageCacheTask,
|
||||||
|
opts: Opts,
|
||||||
|
profiler_chan: ProfilerChan) {
|
||||||
|
let port = Cell::new(port);
|
||||||
|
do spawn {
|
||||||
|
let mut layout = LayoutTask::new(port.take(),
|
||||||
|
script_chan.clone(),
|
||||||
|
render_chan.clone(),
|
||||||
|
img_cache_task.clone(),
|
||||||
|
&opts,
|
||||||
|
profiler_chan.clone());
|
||||||
|
layout.start();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn new(port: Port<Msg>,
|
fn new(port: Port<Msg>,
|
||||||
script_chan: ScriptChan,
|
script_chan: ScriptChan,
|
||||||
render_chan: RenderChan<CompositorChan>,
|
render_chan: RenderChan,
|
||||||
image_cache_task: ImageCacheTask,
|
image_cache_task: ImageCacheTask,
|
||||||
opts: &Opts,
|
opts: &Opts,
|
||||||
profiler_chan: ProfilerChan)
|
profiler_chan: ProfilerChan)
|
||||||
-> Layout {
|
-> LayoutTask {
|
||||||
let fctx = @mut FontContext::new(opts.render_backend, true, profiler_chan.clone());
|
let fctx = @mut FontContext::new(opts.render_backend, true, profiler_chan.clone());
|
||||||
|
|
||||||
Layout {
|
LayoutTask {
|
||||||
port: port,
|
port: port,
|
||||||
script_chan: script_chan,
|
script_chan: script_chan,
|
||||||
render_chan: render_chan,
|
render_chan: render_chan,
|
||||||
|
@ -135,13 +134,14 @@ impl Layout {
|
||||||
self.handle_reflow(data.take());
|
self.handle_reflow(data.take());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QueryMsg(query, chan) => {
|
QueryMsg(query) => {
|
||||||
let chan = Cell::new(chan);
|
let query = Cell::new(query);
|
||||||
do profile(time::LayoutQueryCategory, self.profiler_chan.clone()) {
|
do profile(time::LayoutQueryCategory, self.profiler_chan.clone()) {
|
||||||
self.handle_query(query, chan.take());
|
self.handle_query(query.take());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RouteScriptMsg(script_msg) => {
|
RouteScriptMsg(script_msg) => {
|
||||||
|
debug!("layout: routing %? to script task", script_msg);
|
||||||
self.route_script_msg(script_msg);
|
self.route_script_msg(script_msg);
|
||||||
}
|
}
|
||||||
ExitMsg => {
|
ExitMsg => {
|
||||||
|
@ -268,9 +268,9 @@ impl Layout {
|
||||||
|
|
||||||
/// Handles a query from the script task. This is the main routine that DOM functions like
|
/// Handles a query from the script task. This is the main routine that DOM functions like
|
||||||
/// `getClientRects()` or `getBoundingClientRect()` ultimately invoke.
|
/// `getClientRects()` or `getBoundingClientRect()` ultimately invoke.
|
||||||
fn handle_query(&self, query: LayoutQuery, reply_chan: Chan<Result<LayoutResponse,()>>) {
|
fn handle_query(&self, query: LayoutQuery) {
|
||||||
match query {
|
match query {
|
||||||
ContentBoxQuery(node) => {
|
ContentBoxQuery(node, reply_chan) => {
|
||||||
// FIXME: Isolate this transmutation into a single "bridge" module.
|
// FIXME: Isolate this transmutation into a single "bridge" module.
|
||||||
let node: AbstractNode<LayoutView> = unsafe {
|
let node: AbstractNode<LayoutView> = unsafe {
|
||||||
transmute(node)
|
transmute(node)
|
||||||
|
@ -302,7 +302,7 @@ impl Layout {
|
||||||
|
|
||||||
reply_chan.send(response)
|
reply_chan.send(response)
|
||||||
}
|
}
|
||||||
ContentBoxesQuery(node) => {
|
ContentBoxesQuery(node, reply_chan) => {
|
||||||
// FIXME: Isolate this transmutation into a single "bridge" module.
|
// FIXME: Isolate this transmutation into a single "bridge" module.
|
||||||
let node: AbstractNode<LayoutView> = unsafe {
|
let node: AbstractNode<LayoutView> = unsafe {
|
||||||
transmute(node)
|
transmute(node)
|
||||||
|
@ -322,7 +322,7 @@ impl Layout {
|
||||||
|
|
||||||
reply_chan.send(response)
|
reply_chan.send(response)
|
||||||
}
|
}
|
||||||
HitTestQuery(node, point) => {
|
HitTestQuery(node, point, reply_chan) => {
|
||||||
// FIXME: Isolate this transmutation into a single "bridge" module.
|
// FIXME: Isolate this transmutation into a single "bridge" module.
|
||||||
let node: AbstractNode<LayoutView> = unsafe {
|
let node: AbstractNode<LayoutView> = unsafe {
|
||||||
transmute(node)
|
transmute(node)
|
||||||
|
|
|
@ -234,7 +234,7 @@ impl TextRunScanner {
|
||||||
for clump.eachi |i| {
|
for clump.eachi |i| {
|
||||||
let range = new_ranges[i - self.clump.begin()];
|
let range = new_ranges[i - self.clump.begin()];
|
||||||
if range.length() == 0 {
|
if range.length() == 0 {
|
||||||
error!("Elided an `UnscannedTextbox` because it was zero-length after \
|
debug!("Elided an `UnscannedTextbox` because it was zero-length after \
|
||||||
compression; %s",
|
compression; %s",
|
||||||
in_boxes[i].debug_str());
|
in_boxes[i].debug_str());
|
||||||
loop
|
loop
|
||||||
|
|
|
@ -1,71 +1,12 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#[macro_escape];
|
||||||
{
|
macro_rules! special_stream(
|
||||||
macro_rules! move_ref(
|
($Chan:ident) => (
|
||||||
{ $x:expr } => { unsafe { let y <- *ptr::to_unsafe_ptr(*$x); y } }
|
|
||||||
)
|
|
||||||
|
|
||||||
macro_rules! move_val(
|
|
||||||
{ $x:expr } => { unsafe { let y <- *ptr::to_unsafe_ptr(*$x); y } }
|
|
||||||
)
|
|
||||||
|
|
||||||
// select!
|
|
||||||
macro_rules! select_if(
|
|
||||||
|
|
||||||
{
|
{
|
||||||
$index:expr,
|
let (port, chan) = comm::stream::();
|
||||||
$count:expr
|
(port, $Chan::new(chan))
|
||||||
} => {
|
|
||||||
fail
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
|
||||||
$index:expr,
|
|
||||||
$count:expr,
|
|
||||||
$port:path => [
|
|
||||||
$(type_this $message:path$(($(x $x: ident),+))dont_type_this*
|
|
||||||
-> $next:ident => { $e:expr }),+
|
|
||||||
]
|
|
||||||
$(, $ports:path => [
|
|
||||||
$(type_this $messages:path$(($(x $xs: ident),+))dont_type_this*
|
|
||||||
-> $nexts:ident => { $es:expr }),+
|
|
||||||
] )*
|
|
||||||
} => {
|
|
||||||
if $index == $count {
|
|
||||||
match pipes::try_recv($port) {
|
|
||||||
$(Some($message($($(ref $x,)+)* ref next)) => {
|
|
||||||
// FIXME (#2329) we really want move out of enum here.
|
|
||||||
let $next = move_ref!(next);
|
|
||||||
$e
|
|
||||||
})+
|
|
||||||
_ => fail
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
select_if!(
|
|
||||||
$index,
|
|
||||||
$count + 1
|
|
||||||
$(, $ports => [
|
|
||||||
$(type_this $messages$(($(x $xs),+))dont_type_this*
|
|
||||||
-> $nexts => { $es }),+
|
|
||||||
])*
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
)
|
|
||||||
|
|
||||||
macro_rules! select(
|
|
||||||
{
|
|
||||||
$( $port:path => {
|
|
||||||
$($message:path$(($($x: ident),+))dont_type_this*
|
|
||||||
-> $next:ident $e:expr),+
|
|
||||||
} )+
|
|
||||||
} => {
|
|
||||||
let index = pipes::selecti([$(($port).header()),+]/_);
|
|
||||||
select_if!(index, 0 $(, $port => [
|
|
||||||
$(type_this $message$(($(x $x),+))dont_type_this* -> $next => { $e }),+
|
|
||||||
])+)
|
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
}
|
)
|
||||||
|
|
110
src/components/main/pipeline.rs
Normal file
110
src/components/main/pipeline.rs
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use extra::net::url::Url;
|
||||||
|
use compositing::CompositorChan;
|
||||||
|
use gfx::render_task::{RenderChan, RenderTask};
|
||||||
|
use gfx::render_task;
|
||||||
|
use gfx::opts::Opts;
|
||||||
|
use layout::layout_task::LayoutTask;
|
||||||
|
use script::layout_interface::LayoutChan;
|
||||||
|
use script::script_task::LoadMsg;
|
||||||
|
use servo_msg::constellation_msg::{ConstellationChan, NavigationType};
|
||||||
|
use script::script_task::{ScriptTask, ScriptChan};
|
||||||
|
use script::script_task;
|
||||||
|
use servo_net::image_cache_task::ImageCacheTask;
|
||||||
|
use servo_net::resource_task::ResourceTask;
|
||||||
|
use servo_util::time::ProfilerChan;
|
||||||
|
use std::comm;
|
||||||
|
|
||||||
|
/// A uniquely-identifiable pipeline of stript task, layout task, and render task.
|
||||||
|
pub struct Pipeline {
|
||||||
|
id: uint,
|
||||||
|
script_chan: ScriptChan,
|
||||||
|
layout_chan: LayoutChan,
|
||||||
|
render_chan: RenderChan,
|
||||||
|
/// The most recently loaded url
|
||||||
|
url: Option<Url>,
|
||||||
|
navigation_type: Option<NavigationType>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pipeline {
|
||||||
|
/// Starts a render task, layout task, and script task. Returns the channels wrapped in a struct.
|
||||||
|
pub fn create(id: uint,
|
||||||
|
constellation_chan: ConstellationChan,
|
||||||
|
compositor_chan: CompositorChan,
|
||||||
|
image_cache_task: ImageCacheTask,
|
||||||
|
resource_task: ResourceTask,
|
||||||
|
profiler_chan: ProfilerChan,
|
||||||
|
opts: Opts) -> Pipeline {
|
||||||
|
|
||||||
|
let (script_port, script_chan) = special_stream!(ScriptChan);
|
||||||
|
let (layout_port, layout_chan) = special_stream!(LayoutChan);
|
||||||
|
let (render_port, render_chan) = special_stream!(RenderChan);
|
||||||
|
|
||||||
|
RenderTask::create(id,
|
||||||
|
render_port,
|
||||||
|
compositor_chan.clone(),
|
||||||
|
copy opts,
|
||||||
|
constellation_chan.clone(),
|
||||||
|
profiler_chan.clone());
|
||||||
|
|
||||||
|
LayoutTask::create(layout_port,
|
||||||
|
script_chan.clone(),
|
||||||
|
render_chan.clone(),
|
||||||
|
image_cache_task.clone(),
|
||||||
|
copy opts,
|
||||||
|
profiler_chan);
|
||||||
|
|
||||||
|
ScriptTask::create(id,
|
||||||
|
compositor_chan,
|
||||||
|
layout_chan.clone(),
|
||||||
|
script_port,
|
||||||
|
script_chan.clone(),
|
||||||
|
constellation_chan,
|
||||||
|
resource_task,
|
||||||
|
image_cache_task);
|
||||||
|
|
||||||
|
Pipeline::new(id,
|
||||||
|
script_chan,
|
||||||
|
layout_chan,
|
||||||
|
render_chan)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(id: uint,
|
||||||
|
script_chan: ScriptChan,
|
||||||
|
layout_chan: LayoutChan,
|
||||||
|
render_chan: RenderChan)
|
||||||
|
-> Pipeline {
|
||||||
|
Pipeline {
|
||||||
|
id: id,
|
||||||
|
script_chan: script_chan,
|
||||||
|
layout_chan: layout_chan,
|
||||||
|
render_chan: render_chan,
|
||||||
|
url: None,
|
||||||
|
navigation_type: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load(&mut self, url: Url) {
|
||||||
|
self.url = Some(url.clone());
|
||||||
|
self.script_chan.send(LoadMsg(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reload(&self) {
|
||||||
|
for self.url.iter().advance |&url| {
|
||||||
|
self.script_chan.send(LoadMsg(url));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exit(&self) {
|
||||||
|
// Script task handles shutting down layout, as well
|
||||||
|
self.script_chan.send(script_task::ExitMsg);
|
||||||
|
|
||||||
|
let (response_port, response_chan) = comm::stream();
|
||||||
|
self.render_chan.send(render_task::ExitMsg(response_chan));
|
||||||
|
response_port.recv();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,15 +9,16 @@
|
||||||
|
|
||||||
use windowing::{ApplicationMethods, CompositeCallback, LoadUrlCallback, MouseCallback};
|
use windowing::{ApplicationMethods, CompositeCallback, LoadUrlCallback, MouseCallback};
|
||||||
use windowing::{ResizeCallback, ScrollCallback, WindowMethods, WindowMouseEvent, WindowClickEvent};
|
use windowing::{ResizeCallback, ScrollCallback, WindowMethods, WindowMouseEvent, WindowClickEvent};
|
||||||
use windowing::{WindowMouseDownEvent, WindowMouseUpEvent, ZoomCallback};
|
use windowing::{WindowMouseDownEvent, WindowMouseUpEvent, ZoomCallback, Forward, Back, NavigationCallback};
|
||||||
|
|
||||||
use alert::{Alert, AlertMethods};
|
use alert::{Alert, AlertMethods};
|
||||||
use std::libc::c_int;
|
use std::libc::c_int;
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
use geom::size::Size2D;
|
use geom::size::Size2D;
|
||||||
use servo_msg::compositor::{IdleRenderState, RenderState, RenderingRenderState};
|
use servo_msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState};
|
||||||
use servo_msg::compositor::{FinishedLoading, Loading, PerformingLayout, ReadyState};
|
use servo_msg::compositor_msg::{FinishedLoading, Loading, PerformingLayout, ReadyState};
|
||||||
use glut::glut::{ACTIVE_CTRL, DOUBLE, HAVE_PRECISE_MOUSE_WHEEL, WindowHeight, WindowWidth};
|
use glut::glut::{ACTIVE_CTRL, ACTIVE_SHIFT, DOUBLE, HAVE_PRECISE_MOUSE_WHEEL, WindowHeight};
|
||||||
|
use glut::glut::WindowWidth;
|
||||||
use glut::glut;
|
use glut::glut;
|
||||||
use glut::machack;
|
use glut::machack;
|
||||||
|
|
||||||
|
@ -44,6 +45,7 @@ pub struct Window {
|
||||||
mouse_callback: Option<MouseCallback>,
|
mouse_callback: Option<MouseCallback>,
|
||||||
scroll_callback: Option<ScrollCallback>,
|
scroll_callback: Option<ScrollCallback>,
|
||||||
zoom_callback: Option<ZoomCallback>,
|
zoom_callback: Option<ZoomCallback>,
|
||||||
|
navigation_callback: Option<NavigationCallback>,
|
||||||
|
|
||||||
drag_origin: Point2D<c_int>,
|
drag_origin: Point2D<c_int>,
|
||||||
|
|
||||||
|
@ -72,6 +74,7 @@ impl WindowMethods<Application> for Window {
|
||||||
mouse_callback: None,
|
mouse_callback: None,
|
||||||
scroll_callback: None,
|
scroll_callback: None,
|
||||||
zoom_callback: None,
|
zoom_callback: None,
|
||||||
|
navigation_callback: None,
|
||||||
|
|
||||||
drag_origin: Point2D(0 as c_int, 0),
|
drag_origin: Point2D(0 as c_int, 0),
|
||||||
|
|
||||||
|
@ -177,6 +180,11 @@ impl WindowMethods<Application> for Window {
|
||||||
self.zoom_callback = Some(new_zoom_callback)
|
self.zoom_callback = Some(new_zoom_callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Registers a callback to be run when backspace or shift-backspace is pressed.
|
||||||
|
pub fn set_navigation_callback(&mut self, new_navigation_callback: NavigationCallback) {
|
||||||
|
self.navigation_callback = Some(new_navigation_callback)
|
||||||
|
}
|
||||||
|
|
||||||
/// Spins the event loop.
|
/// Spins the event loop.
|
||||||
pub fn check_loop(@mut self) {
|
pub fn check_loop(@mut self) {
|
||||||
glut::check_loop()
|
glut::check_loop()
|
||||||
|
@ -226,20 +234,33 @@ impl Window {
|
||||||
|
|
||||||
/// Helper function to handle keyboard events.
|
/// Helper function to handle keyboard events.
|
||||||
fn handle_key(&self, key: u8) {
|
fn handle_key(&self, key: u8) {
|
||||||
debug!("got key: %d", key as int);
|
debug!("got key: %?", key);
|
||||||
|
let modifiers = glut::get_modifiers();
|
||||||
match key {
|
match key {
|
||||||
12 => self.load_url(), // Ctrl+L
|
12 => self.load_url(), // Ctrl+L
|
||||||
k if k == ('=' as u8) && (glut::get_modifiers() & ACTIVE_CTRL) != 0 => { // Ctrl++
|
31 if (modifiers & ACTIVE_CTRL) != 0 => { // Ctrl+-
|
||||||
for self.zoom_callback.iter().advance |&callback| {
|
|
||||||
callback(0.1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
k if k == 31 && (glut::get_modifiers() & ACTIVE_CTRL) != 0 => { // Ctrl+-
|
|
||||||
for self.zoom_callback.iter().advance |&callback| {
|
for self.zoom_callback.iter().advance |&callback| {
|
||||||
callback(-0.1);
|
callback(-0.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
127 => {
|
||||||
|
for self.navigation_callback.iter().advance |&callback| {
|
||||||
|
if (modifiers & ACTIVE_SHIFT) != 0 { // Shift+Backspace
|
||||||
|
callback(Forward);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
callback(Back);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c => match c as char {
|
||||||
|
'=' if (modifiers & ACTIVE_CTRL) != 0 => { // Ctrl++
|
||||||
|
for self.zoom_callback.iter().advance |&callback| {
|
||||||
|
callback(0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,8 @@ extern mod core_graphics;
|
||||||
extern mod core_text;
|
extern mod core_text;
|
||||||
|
|
||||||
use compositing::{CompositorChan, CompositorTask};
|
use compositing::{CompositorChan, CompositorTask};
|
||||||
use engine::Engine;
|
use constellation::Constellation;
|
||||||
use servo_msg::engine::{ExitMsg, LoadUrlMsg};
|
use servo_msg::constellation_msg::{ExitMsg, LoadUrlMsg};
|
||||||
|
|
||||||
use gfx::opts;
|
use gfx::opts;
|
||||||
use servo_net::image_cache_task::ImageCacheTask;
|
use servo_net::image_cache_task::ImageCacheTask;
|
||||||
|
@ -53,6 +53,8 @@ use std::os;
|
||||||
#[path="compositing/mod.rs"]
|
#[path="compositing/mod.rs"]
|
||||||
pub mod compositing;
|
pub mod compositing;
|
||||||
|
|
||||||
|
pub mod macros;
|
||||||
|
|
||||||
pub mod css {
|
pub mod css {
|
||||||
priv mod select_handler;
|
priv mod select_handler;
|
||||||
priv mod node_util;
|
priv mod node_util;
|
||||||
|
@ -62,7 +64,8 @@ pub mod css {
|
||||||
pub mod node_style;
|
pub mod node_style;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod engine;
|
pub mod constellation;
|
||||||
|
pub mod pipeline;
|
||||||
|
|
||||||
pub mod layout {
|
pub mod layout {
|
||||||
pub mod block;
|
pub mod block;
|
||||||
|
@ -121,24 +124,24 @@ fn run(opts: &Opts) {
|
||||||
|
|
||||||
let resource_task = ResourceTask();
|
let resource_task = ResourceTask();
|
||||||
let image_cache_task = ImageCacheTask(resource_task.clone());
|
let image_cache_task = ImageCacheTask(resource_task.clone());
|
||||||
let engine_chan = Engine::start(compositor_chan.clone(),
|
let constellation_chan = Constellation::start(compositor_chan.clone(),
|
||||||
opts,
|
opts,
|
||||||
resource_task,
|
resource_task,
|
||||||
image_cache_task,
|
image_cache_task,
|
||||||
profiler_chan.clone());
|
profiler_chan.clone());
|
||||||
|
|
||||||
// Send the URL command to the engine task.
|
// Send the URL command to the constellation.
|
||||||
for opts.urls.each |filename| {
|
for opts.urls.each |filename| {
|
||||||
engine_chan.send(LoadUrlMsg(make_url(copy *filename, None)))
|
constellation_chan.send(LoadUrlMsg(make_url(copy *filename, None)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for the compositor to shut down.
|
// Wait for the compositor to shut down.
|
||||||
shutdown_port.recv();
|
shutdown_port.recv();
|
||||||
|
|
||||||
// Shut the engine down.
|
// Shut the constellation down.
|
||||||
debug!("master: Shut down");
|
debug!("master: Shut down");
|
||||||
let (exit_response_from_engine, exit_chan) = comm::stream();
|
let (exit_response_from_constellation, exit_chan) = comm::stream();
|
||||||
engine_chan.send(ExitMsg(exit_chan));
|
constellation_chan.send(ExitMsg(exit_chan));
|
||||||
exit_response_from_engine.recv();
|
exit_response_from_constellation.recv();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
use geom::size::Size2D;
|
use geom::size::Size2D;
|
||||||
use servo_msg::compositor::{ReadyState, RenderState};
|
use servo_msg::compositor_msg::{ReadyState, RenderState};
|
||||||
|
|
||||||
pub enum WindowMouseEvent {
|
pub enum WindowMouseEvent {
|
||||||
WindowClickEvent(uint, Point2D<f32>),
|
WindowClickEvent(uint, Point2D<f32>),
|
||||||
|
@ -14,6 +14,11 @@ pub enum WindowMouseEvent {
|
||||||
WindowMouseUpEvent(uint, Point2D<f32>),
|
WindowMouseUpEvent(uint, Point2D<f32>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum WindowNavigateMsg {
|
||||||
|
Forward,
|
||||||
|
Back,
|
||||||
|
}
|
||||||
|
|
||||||
/// Type of the function that is called when the screen is to be redisplayed.
|
/// Type of the function that is called when the screen is to be redisplayed.
|
||||||
pub type CompositeCallback = @fn();
|
pub type CompositeCallback = @fn();
|
||||||
|
|
||||||
|
@ -29,9 +34,12 @@ pub type MouseCallback = @fn(WindowMouseEvent);
|
||||||
/// Type of the function that is called when the user scrolls.
|
/// Type of the function that is called when the user scrolls.
|
||||||
pub type ScrollCallback = @fn(Point2D<f32>);
|
pub type ScrollCallback = @fn(Point2D<f32>);
|
||||||
|
|
||||||
///Type of the function that is called when the user zooms.
|
/// Type of the function that is called when the user zooms.
|
||||||
pub type ZoomCallback = @fn(f32);
|
pub type ZoomCallback = @fn(f32);
|
||||||
|
|
||||||
|
/// Type of the function that is called when the user clicks backspace or shift-backspace
|
||||||
|
pub type NavigationCallback = @fn(WindowNavigateMsg);
|
||||||
|
|
||||||
/// Methods for an abstract Application.
|
/// Methods for an abstract Application.
|
||||||
pub trait ApplicationMethods {
|
pub trait ApplicationMethods {
|
||||||
fn new() -> Self;
|
fn new() -> Self;
|
||||||
|
@ -57,6 +65,8 @@ pub trait WindowMethods<A> {
|
||||||
pub fn set_scroll_callback(&mut self, new_scroll_callback: ScrollCallback);
|
pub fn set_scroll_callback(&mut self, new_scroll_callback: ScrollCallback);
|
||||||
/// Registers a callback to run when the user zooms.
|
/// Registers a callback to run when the user zooms.
|
||||||
pub fn set_zoom_callback(&mut self, new_zoom_callback: ZoomCallback);
|
pub fn set_zoom_callback(&mut self, new_zoom_callback: ZoomCallback);
|
||||||
|
/// Registers a callback to run when the user presses backspace or shift-backspace.
|
||||||
|
pub fn set_navigation_callback(&mut self, new_navigation_callback: NavigationCallback);
|
||||||
|
|
||||||
/// Spins the event loop.
|
/// Spins the event loop.
|
||||||
pub fn check_loop(@mut self);
|
pub fn check_loop(@mut self);
|
||||||
|
|
|
@ -6,7 +6,9 @@ use azure::azure_hl::DrawTarget;
|
||||||
use azure::azure::AzGLContext;
|
use azure::azure::AzGLContext;
|
||||||
use geom::rect::Rect;
|
use geom::rect::Rect;
|
||||||
use geom::size::Size2D;
|
use geom::size::Size2D;
|
||||||
|
use std::util::NonCopyable;
|
||||||
|
|
||||||
|
#[deriving(Clone)]
|
||||||
pub struct LayerBuffer {
|
pub struct LayerBuffer {
|
||||||
draw_target: DrawTarget,
|
draw_target: DrawTarget,
|
||||||
|
|
||||||
|
@ -22,6 +24,7 @@ pub struct LayerBuffer {
|
||||||
|
|
||||||
/// A set of layer buffers. This is an atomic unit used to switch between the front and back
|
/// A set of layer buffers. This is an atomic unit used to switch between the front and back
|
||||||
/// buffers.
|
/// buffers.
|
||||||
|
#[deriving(Clone)]
|
||||||
pub struct LayerBufferSet {
|
pub struct LayerBufferSet {
|
||||||
buffers: ~[LayerBuffer]
|
buffers: ~[LayerBuffer]
|
||||||
}
|
}
|
||||||
|
@ -33,14 +36,6 @@ pub enum RenderState {
|
||||||
RenderingRenderState,
|
RenderingRenderState,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The interface used by the renderer to acquire draw targets for each rendered frame and
|
|
||||||
/// submit them to be drawn to the display.
|
|
||||||
pub trait RenderListener {
|
|
||||||
fn get_gl_context(&self) -> AzGLContext;
|
|
||||||
fn paint(&self, layer_buffer_set: LayerBufferSet, new_size: Size2D<uint>);
|
|
||||||
fn set_render_state(&self, render_state: RenderState);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ReadyState {
|
pub enum ReadyState {
|
||||||
/// Informs the compositor that a page is loading. Used for setting status
|
/// Informs the compositor that a page is loading. Used for setting status
|
||||||
Loading,
|
Loading,
|
||||||
|
@ -50,8 +45,33 @@ pub enum ReadyState {
|
||||||
FinishedLoading,
|
FinishedLoading,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The interface used by the renderer to acquire draw targets for each render frame and
|
||||||
|
/// submit them to be drawn to the display.
|
||||||
|
pub trait RenderListener {
|
||||||
|
fn get_gl_context(&self) -> AzGLContext;
|
||||||
|
fn paint(&self, id: uint, layer_buffer_set: LayerBufferSet, new_size: Size2D<uint>);
|
||||||
|
fn set_render_state(&self, render_state: RenderState);
|
||||||
|
}
|
||||||
|
|
||||||
/// The interface used by the script task to tell the compositor to update its ready state,
|
/// 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.
|
/// which is used in displaying the appropriate message in the window's title.
|
||||||
pub trait ScriptListener : Clone {
|
pub trait ScriptListener : Clone {
|
||||||
fn set_ready_state(&self, ReadyState);
|
fn set_ready_state(&self, ReadyState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Signifies to the renderer likely control of the compositor. Controlling the compositor token
|
||||||
|
/// is necessary but not sufficient for the renderer to successfully send paint messages to the
|
||||||
|
/// compositor. Only the render tasks controlling compositor tokens may send messages, and the
|
||||||
|
/// compositor is guaranteed to only accept messages from one of those tasks at a time.
|
||||||
|
pub struct CompositorToken {
|
||||||
|
construction_restrictor: NonCopyable,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompositorToken {
|
||||||
|
pub fn new() -> CompositorToken {
|
||||||
|
CompositorToken {
|
||||||
|
// Of course, this doesn't guarantee that renderers will invalidate their tokens
|
||||||
|
construction_restrictor: NonCopyable::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
44
src/components/msg/constellation_msg.rs
Normal file
44
src/components/msg/constellation_msg.rs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
//! The high-level interface from script to constellation. Using this abstract interface helps reduce
|
||||||
|
/// coupling between these two components
|
||||||
|
|
||||||
|
use std::comm::{Chan, SharedChan};
|
||||||
|
use extra::net::url::Url;
|
||||||
|
|
||||||
|
#[deriving(Clone)]
|
||||||
|
pub struct ConstellationChan {
|
||||||
|
chan: SharedChan<Msg>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConstellationChan {
|
||||||
|
pub fn new(chan: Chan<Msg>) -> ConstellationChan {
|
||||||
|
ConstellationChan {
|
||||||
|
chan: SharedChan::new(chan),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn send(&self, msg: Msg) {
|
||||||
|
self.chan.send(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Msg {
|
||||||
|
LoadUrlMsg(Url),
|
||||||
|
NavigateMsg(NavigationDirection),
|
||||||
|
ExitMsg(Chan<()>),
|
||||||
|
RendererReadyMsg(uint),
|
||||||
|
CompositorAck(uint),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents the two different ways to which a page can be navigated
|
||||||
|
enum NavigationType {
|
||||||
|
Load, // entered or clicked on a url
|
||||||
|
Navigate, // browser forward/back buttons
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum NavigationDirection {
|
||||||
|
Forward,
|
||||||
|
Back,
|
||||||
|
}
|
|
@ -1,31 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
//! The high-level interface from script to engine. Using this abstract interface helps reduce
|
|
||||||
/// coupling between these two components
|
|
||||||
|
|
||||||
use std::comm::{Chan, SharedChan};
|
|
||||||
use extra::net::url::Url;
|
|
||||||
|
|
||||||
#[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),
|
|
||||||
ExitMsg(Chan<()>),
|
|
||||||
}
|
|
||||||
|
|
|
@ -14,5 +14,5 @@ extern mod std;
|
||||||
extern mod geom;
|
extern mod geom;
|
||||||
extern mod extra;
|
extern mod extra;
|
||||||
|
|
||||||
pub mod compositor;
|
pub mod compositor_msg;
|
||||||
pub mod engine;
|
pub mod constellation_msg;
|
||||||
|
|
|
@ -16,6 +16,7 @@ use std::cast;
|
||||||
use std::i32;
|
use std::i32;
|
||||||
use std::libc;
|
use std::libc;
|
||||||
use std::libc::c_uint;
|
use std::libc::c_uint;
|
||||||
|
use std::comm;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::ptr::null;
|
use std::ptr::null;
|
||||||
use std::result;
|
use std::result;
|
||||||
|
@ -229,13 +230,9 @@ extern fn HTMLImageElement_getWidth(cx: *JSContext, _argc: c_uint, vp: *mut JSVa
|
||||||
let width = match node.type_id() {
|
let width = match node.type_id() {
|
||||||
ElementNodeTypeId(HTMLImageElementTypeId) => {
|
ElementNodeTypeId(HTMLImageElementTypeId) => {
|
||||||
let script_context = task_from_context(cx);
|
let script_context = task_from_context(cx);
|
||||||
match (*script_context).query_layout(ContentBoxQuery(node)) {
|
let (port, chan) = comm::stream();
|
||||||
Ok(rect) => {
|
match (*script_context).query_layout(ContentBoxQuery(node, chan), port) {
|
||||||
match rect {
|
Ok(ContentBoxResponse(rect)) => rect.size.width.to_px(),
|
||||||
ContentBoxResponse(rect) => rect.size.width.to_px(),
|
|
||||||
_ => fail!(~"unexpected layout reply")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(()) => 0
|
Err(()) => 0
|
||||||
}
|
}
|
||||||
// TODO: if nothing is being rendered(?), return zero dimensions
|
// TODO: if nothing is being rendered(?), return zero dimensions
|
||||||
|
|
|
@ -71,7 +71,7 @@ pub fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString {
|
||||||
return ptr::null();
|
return ptr::null();
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = ~"[object " + name + ~"]";
|
let result = ~"[object " + name + "]";
|
||||||
for result.iter().enumerate().advance |(i, c)| {
|
for result.iter().enumerate().advance |(i, c)| {
|
||||||
*chars.offset(i) = c as jschar;
|
*chars.offset(i) = c as jschar;
|
||||||
}
|
}
|
||||||
|
@ -86,4 +86,4 @@ pub fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString {
|
||||||
|
|
||||||
pub fn GetExpandoObject(_proxy: *JSObject) -> *JSObject {
|
pub fn GetExpandoObject(_proxy: *JSObject) -> *JSObject {
|
||||||
ptr::null()
|
ptr::null()
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,12 +21,12 @@ use js::glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB, ENUMERATE_STUB, CONVERT_STUB
|
||||||
use js::jsapi::{JS_AlreadyHasOwnProperty, JS_NewObject, JS_NewFunction};
|
use js::jsapi::{JS_AlreadyHasOwnProperty, JS_NewObject, JS_NewFunction};
|
||||||
use js::jsapi::{JS_DefineProperties, JS_WrapValue, JS_ForwardGetPropertyTo};
|
use js::jsapi::{JS_DefineProperties, JS_WrapValue, JS_ForwardGetPropertyTo};
|
||||||
use js::jsapi::{JS_EncodeString, JS_free, JS_GetStringCharsAndLength};
|
use js::jsapi::{JS_EncodeString, JS_free, JS_GetStringCharsAndLength};
|
||||||
use js::jsapi::{JS_GetClass, JS_GetPrototype, JS_LinkConstructorAndPrototype};
|
use js::jsapi::{JS_GetClass, JS_LinkConstructorAndPrototype};
|
||||||
use js::jsapi::{JS_GetFunctionPrototype, JS_InternString, JS_GetFunctionObject};
|
use js::jsapi::{JS_GetFunctionPrototype, JS_InternString, JS_GetFunctionObject};
|
||||||
use js::jsapi::{JS_HasPropertyById, JS_GetPrototype, JS_GetGlobalForObject};
|
use js::jsapi::{JS_HasPropertyById, JS_GetPrototype, JS_GetGlobalForObject};
|
||||||
use js::jsapi::{JS_NewStringCopyN, JS_DefineFunctions, JS_DefineProperty};
|
use js::jsapi::{JS_NewStringCopyN, JS_DefineFunctions, JS_DefineProperty};
|
||||||
use js::jsapi::{JS_ValueToString, JS_GetReservedSlot, JS_SetReservedSlot};
|
use js::jsapi::{JS_ValueToString, JS_GetReservedSlot, JS_SetReservedSlot};
|
||||||
use js::jsapi::{JSContext, JSVal, JSObject, JSBool, jsid, JSClass, JSNative};
|
use js::jsapi::{JSContext, JSObject, JSBool, jsid, JSClass, JSNative};
|
||||||
use js::jsapi::{JSFunctionSpec, JSPropertySpec, JSVal, JSPropertyDescriptor};
|
use js::jsapi::{JSFunctionSpec, JSPropertySpec, JSVal, JSPropertyDescriptor};
|
||||||
use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType;
|
use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType;
|
||||||
use js::rust::Compartment;
|
use js::rust::Compartment;
|
||||||
|
@ -83,7 +83,7 @@ extern fn InterfaceObjectToString(cx: *JSContext, _argc: uint, vp: *mut JSVal) -
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = jsval_to_str(cx, *v).get();
|
let name = jsval_to_str(cx, *v).get();
|
||||||
let retval = str(~"function " + name + ~"() {\n [native code]\n}");
|
let retval = str(~"function " + name + "() {\n [native code]\n}");
|
||||||
*vp = domstring_to_jsval(cx, &retval);
|
*vp = domstring_to_jsval(cx, &retval);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
use dom::bindings::utils::{DOMString, null_string, str};
|
use dom::bindings::utils::{DOMString, null_string, str};
|
||||||
use dom::node::{Node, NodeTypeId, ScriptView};
|
use dom::node::{Node, NodeTypeId, ScriptView};
|
||||||
|
|
||||||
use std::str;
|
|
||||||
|
|
||||||
pub struct CharacterData {
|
pub struct CharacterData {
|
||||||
parent: Node<ScriptView>,
|
parent: Node<ScriptView>,
|
||||||
data: DOMString
|
data: DOMString
|
||||||
|
|
|
@ -12,6 +12,7 @@ use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
|
||||||
use layout_interface::{ContentBoxesResponse};
|
use layout_interface::{ContentBoxesResponse};
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
use std::comm;
|
||||||
use std::uint;
|
use std::uint;
|
||||||
use std::str::eq_slice;
|
use std::str::eq_slice;
|
||||||
use extra::net::url::Url;
|
use extra::net::url::Url;
|
||||||
|
@ -165,20 +166,19 @@ impl<'self> Element {
|
||||||
Some(win) => {
|
Some(win) => {
|
||||||
let node = self.parent.abstract.get();
|
let node = self.parent.abstract.get();
|
||||||
assert!(node.is_element());
|
assert!(node.is_element());
|
||||||
let script_context = unsafe {
|
let script_task = unsafe {
|
||||||
&mut *win.script_context
|
&mut *win.script_task
|
||||||
};
|
};
|
||||||
match script_context.query_layout(ContentBoxesQuery(node)) {
|
let (port, chan) = comm::stream();
|
||||||
Ok(rects) => match rects {
|
match script_task.query_layout(ContentBoxesQuery(node, chan), port) {
|
||||||
ContentBoxesResponse(rects) =>
|
Ok(ContentBoxesResponse(rects)) => {
|
||||||
do rects.map |r| {
|
do rects.map |r| {
|
||||||
ClientRect::new(
|
ClientRect::new(
|
||||||
r.origin.y.to_f32(),
|
r.origin.y.to_f32(),
|
||||||
(r.origin.y + r.size.height).to_f32(),
|
(r.origin.y + r.size.height).to_f32(),
|
||||||
r.origin.x.to_f32(),
|
r.origin.x.to_f32(),
|
||||||
(r.origin.x + r.size.width).to_f32())
|
(r.origin.x + r.size.width).to_f32())
|
||||||
},
|
}
|
||||||
_ => fail!(~"unexpected layout reply")
|
|
||||||
},
|
},
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
debug!("layout query error");
|
debug!("layout query error");
|
||||||
|
@ -207,16 +207,15 @@ impl<'self> Element {
|
||||||
Some(win) => {
|
Some(win) => {
|
||||||
let node = self.parent.abstract.get();
|
let node = self.parent.abstract.get();
|
||||||
assert!(node.is_element());
|
assert!(node.is_element());
|
||||||
let script_context = unsafe { &mut *win.script_context };
|
let script_task = unsafe { &mut *win.script_task };
|
||||||
match script_context.query_layout(ContentBoxQuery(node)) {
|
let (port, chan) = comm::stream();
|
||||||
Ok(rect) => match rect {
|
match script_task.query_layout(ContentBoxQuery(node, chan), port) {
|
||||||
ContentBoxResponse(rect) =>
|
Ok(ContentBoxResponse(rect)) => {
|
||||||
Some(ClientRect::new(
|
Some(ClientRect::new(
|
||||||
rect.origin.y.to_f32(),
|
rect.origin.y.to_f32(),
|
||||||
(rect.origin.y + rect.size.height).to_f32(),
|
(rect.origin.y + rect.size.height).to_f32(),
|
||||||
rect.origin.x.to_f32(),
|
rect.origin.x.to_f32(),
|
||||||
(rect.origin.x + rect.size.width).to_f32())),
|
(rect.origin.x + rect.size.width).to_f32()))
|
||||||
_ => fail!(~"unexpected layout result")
|
|
||||||
},
|
},
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
debug!("error querying layout");
|
debug!("error querying layout");
|
||||||
|
|
|
@ -9,8 +9,6 @@ use dom::bindings::utils::{DOMString, ErrorResult, WrapperCache};
|
||||||
|
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
|
|
||||||
use std::comm;
|
|
||||||
|
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
ResizeEvent(uint, uint),
|
ResizeEvent(uint, uint),
|
||||||
ReflowEvent,
|
ReflowEvent,
|
||||||
|
|
|
@ -367,7 +367,7 @@ impl<View> AbstractNode<View> {
|
||||||
pub fn dump_indent(&self, indent: uint) {
|
pub fn dump_indent(&self, indent: uint) {
|
||||||
let mut s = ~"";
|
let mut s = ~"";
|
||||||
for uint::range(0u, indent) |_i| {
|
for uint::range(0u, indent) |_i| {
|
||||||
s += ~" ";
|
s += " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
s += self.debug_str();
|
s += self.debug_str();
|
||||||
|
|
|
@ -6,7 +6,7 @@ use dom::bindings::utils::WrapperCache;
|
||||||
use dom::bindings::window;
|
use dom::bindings::window;
|
||||||
|
|
||||||
use layout_interface::ReflowForScriptQuery;
|
use layout_interface::ReflowForScriptQuery;
|
||||||
use script_task::{ExitMsg, FireTimerMsg, ScriptChan, ScriptContext};
|
use script_task::{ExitMsg, FireTimerMsg, ScriptChan, ScriptTask};
|
||||||
|
|
||||||
use std::comm;
|
use std::comm;
|
||||||
use std::comm::Chan;
|
use std::comm::Chan;
|
||||||
|
@ -29,7 +29,7 @@ pub enum TimerControlMsg {
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
timer_chan: Chan<TimerControlMsg>,
|
timer_chan: Chan<TimerControlMsg>,
|
||||||
script_chan: ScriptChan,
|
script_chan: ScriptChan,
|
||||||
script_context: *mut ScriptContext,
|
script_task: *mut ScriptTask,
|
||||||
wrapper: WrapperCache
|
wrapper: WrapperCache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,11 +89,11 @@ impl Window {
|
||||||
|
|
||||||
pub fn content_changed(&self) {
|
pub fn content_changed(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
(*self.script_context).reflow_all(ReflowForScriptQuery)
|
(*self.script_task).reflow_all(ReflowForScriptQuery)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(script_chan: ScriptChan, script_context: *mut ScriptContext)
|
pub fn new(script_chan: ScriptChan, script_task: *mut ScriptTask)
|
||||||
-> @mut Window {
|
-> @mut Window {
|
||||||
let script_chan_clone = script_chan.clone();
|
let script_chan_clone = script_chan.clone();
|
||||||
let win = @mut Window {
|
let win = @mut Window {
|
||||||
|
@ -112,11 +112,11 @@ impl Window {
|
||||||
}
|
}
|
||||||
timer_chan
|
timer_chan
|
||||||
},
|
},
|
||||||
script_context: script_context,
|
script_task: script_task,
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let compartment = (*script_context).js_compartment;
|
let compartment = (*script_task).js_compartment;
|
||||||
window::create(compartment, win);
|
window::create(compartment, win);
|
||||||
}
|
}
|
||||||
win
|
win
|
||||||
|
|
|
@ -8,7 +8,6 @@ use std::cell::Cell;
|
||||||
use std::comm;
|
use std::comm;
|
||||||
use std::comm::Port;
|
use std::comm::Port;
|
||||||
use std::task;
|
use std::task;
|
||||||
use std::str;
|
|
||||||
use newcss::stylesheet::Stylesheet;
|
use newcss::stylesheet::Stylesheet;
|
||||||
use newcss::util::DataStream;
|
use newcss::util::DataStream;
|
||||||
use servo_net::resource_task::{ResourceTask, ProgressMsg, Load, Payload, Done};
|
use servo_net::resource_task::{ResourceTask, ProgressMsg, Load, Payload, Done};
|
||||||
|
|
|
@ -303,9 +303,9 @@ pub fn parse_html(url: Url,
|
||||||
// Handle CSS style sheets from <link> elements
|
// Handle CSS style sheets from <link> elements
|
||||||
ElementNodeTypeId(HTMLLinkElementTypeId) => {
|
ElementNodeTypeId(HTMLLinkElementTypeId) => {
|
||||||
do node.with_imm_element |element| {
|
do node.with_imm_element |element| {
|
||||||
match (element.get_attr(~"rel"), element.get_attr(~"href")) {
|
match (element.get_attr("rel"), element.get_attr("href")) {
|
||||||
(Some(rel), Some(href)) => {
|
(Some(rel), Some(href)) => {
|
||||||
if rel == ~"stylesheet" {
|
if rel == "stylesheet" {
|
||||||
debug!("found CSS stylesheet: %s", href);
|
debug!("found CSS stylesheet: %s", href);
|
||||||
let url = make_url(href.to_str(), Some(url2.clone()));
|
let url = make_url(href.to_str(), Some(url2.clone()));
|
||||||
css_chan2.send(CSSTaskNewFile(UrlProvenance(url)));
|
css_chan2.send(CSSTaskNewFile(UrlProvenance(url)));
|
||||||
|
@ -317,7 +317,7 @@ pub fn parse_html(url: Url,
|
||||||
},
|
},
|
||||||
ElementNodeTypeId(HTMLImageElementTypeId) => {
|
ElementNodeTypeId(HTMLImageElementTypeId) => {
|
||||||
do node.with_mut_image_element |image_element| {
|
do node.with_mut_image_element |image_element| {
|
||||||
let src_opt = image_element.parent.get_attr(~"src").map(|x| x.to_str());
|
let src_opt = image_element.parent.get_attr("src").map(|x| x.to_str());
|
||||||
match src_opt {
|
match src_opt {
|
||||||
None => {}
|
None => {}
|
||||||
Some(src) => {
|
Some(src) => {
|
||||||
|
@ -401,7 +401,7 @@ pub fn parse_html(url: Url,
|
||||||
unsafe {
|
unsafe {
|
||||||
let script: AbstractNode<ScriptView> = NodeWrapping::from_hubbub_node(script);
|
let script: AbstractNode<ScriptView> = NodeWrapping::from_hubbub_node(script);
|
||||||
do script.with_imm_element |script| {
|
do script.with_imm_element |script| {
|
||||||
match script.get_attr(~"src") {
|
match script.get_attr("src") {
|
||||||
Some(src) => {
|
Some(src) => {
|
||||||
debug!("found script: %s", src);
|
debug!("found script: %s", src);
|
||||||
let new_url = make_url(src.to_str(), Some(url.clone()));
|
let new_url = make_url(src.to_str(), Some(url.clone()));
|
||||||
|
|
|
@ -30,7 +30,7 @@ pub enum Msg {
|
||||||
/// Performs a synchronous layout request.
|
/// Performs a synchronous layout request.
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): As noted below, this isn't very type safe.
|
/// FIXME(pcwalton): As noted below, this isn't very type safe.
|
||||||
QueryMsg(LayoutQuery, Chan<Result<LayoutResponse,()>>),
|
QueryMsg(LayoutQuery),
|
||||||
|
|
||||||
/// Routes a message (usually from the compositor) to the appropriate script task
|
/// Routes a message (usually from the compositor) to the appropriate script task
|
||||||
RouteScriptMsg(ScriptMsg),
|
RouteScriptMsg(ScriptMsg),
|
||||||
|
@ -42,25 +42,16 @@ pub enum Msg {
|
||||||
/// Synchronous messages that script can send to layout.
|
/// Synchronous messages that script can send to layout.
|
||||||
pub enum LayoutQuery {
|
pub enum LayoutQuery {
|
||||||
/// Requests the dimensions of the content box, as in the `getBoundingClientRect()` call.
|
/// Requests the dimensions of the content box, as in the `getBoundingClientRect()` call.
|
||||||
ContentBoxQuery(AbstractNode<ScriptView>),
|
ContentBoxQuery(AbstractNode<ScriptView>, Chan<Result<ContentBoxResponse, ()>>),
|
||||||
/// Requests the dimensions of all the content boxes, as in the `getClientRects()` call.
|
/// Requests the dimensions of all the content boxes, as in the `getClientRects()` call.
|
||||||
ContentBoxesQuery(AbstractNode<ScriptView>),
|
ContentBoxesQuery(AbstractNode<ScriptView>, Chan<Result<ContentBoxesResponse, ()>>),
|
||||||
/// Requests the node containing the point of interest
|
/// Requests the node containing the point of interest
|
||||||
HitTestQuery(AbstractNode<ScriptView>, Point2D<f32>),
|
HitTestQuery(AbstractNode<ScriptView>, Point2D<f32>, Chan<Result<HitTestResponse, ()>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The reply of a synchronous message from script to layout.
|
pub struct ContentBoxResponse(Rect<Au>);
|
||||||
///
|
pub struct ContentBoxesResponse(~[Rect<Au>]);
|
||||||
/// FIXME(pcwalton): This isn't very type safe. Maybe `LayoutQuery` objects should include
|
pub struct HitTestResponse(AbstractNode<LayoutView>);
|
||||||
/// response channels?
|
|
||||||
pub enum LayoutResponse {
|
|
||||||
/// A response to the `ContentBoxQuery` message.
|
|
||||||
ContentBoxResponse(Rect<Au>),
|
|
||||||
/// A response to the `ContentBoxesQuery` message.
|
|
||||||
ContentBoxesResponse(~[Rect<Au>]),
|
|
||||||
/// A response to the `HitTestQuery` message.
|
|
||||||
HitTestResponse(AbstractNode<LayoutView>),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Determines which part of the
|
/// Determines which part of the
|
||||||
pub enum DocumentDamageLevel {
|
pub enum DocumentDamageLevel {
|
||||||
|
|
|
@ -5,19 +5,23 @@
|
||||||
/// The script task is the task that owns the DOM in memory, runs JavaScript, and spawns parsing
|
/// The script task is the task that owns the DOM in memory, runs JavaScript, and spawns parsing
|
||||||
/// and layout tasks.
|
/// and layout tasks.
|
||||||
|
|
||||||
use servo_msg::compositor::{ReadyState, Loading, PerformingLayout, FinishedLoading};
|
use servo_msg::compositor_msg::{ScriptListener, Loading, PerformingLayout};
|
||||||
|
use servo_msg::compositor_msg::FinishedLoading;
|
||||||
use dom::bindings::utils::GlobalStaticData;
|
use dom::bindings::utils::GlobalStaticData;
|
||||||
use dom::document::Document;
|
use dom::document::Document;
|
||||||
use dom::element::Element;
|
use dom::element::Element;
|
||||||
use dom::event::{Event, ResizeEvent, ReflowEvent, ClickEvent, MouseDownEvent, MouseUpEvent};
|
use dom::event::{Event, ResizeEvent, ReflowEvent, ClickEvent, MouseDownEvent, MouseUpEvent};
|
||||||
use dom::node::{AbstractNode, ScriptView, define_bindings};
|
use dom::node::{AbstractNode, ScriptView, define_bindings};
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use layout_interface::{AddStylesheetMsg, DocumentDamage, DocumentDamageLevel, HitTestQuery};
|
use layout_interface::{AddStylesheetMsg, DocumentDamage};
|
||||||
use layout_interface::{HitTestResponse, LayoutQuery, LayoutResponse, LayoutChan};
|
use layout_interface::{DocumentDamageLevel, HitTestQuery, HitTestResponse, LayoutQuery};
|
||||||
use layout_interface::{MatchSelectorsDocumentDamage, QueryMsg, Reflow, ReflowDocumentDamage};
|
use layout_interface::{LayoutChan, MatchSelectorsDocumentDamage, QueryMsg, Reflow};
|
||||||
use layout_interface::{ReflowForDisplay, ReflowForScriptQuery, ReflowGoal, ReflowMsg};
|
use layout_interface::{ReflowDocumentDamage, ReflowForDisplay, ReflowForScriptQuery, ReflowGoal};
|
||||||
|
use layout_interface::ReflowMsg;
|
||||||
use layout_interface;
|
use layout_interface;
|
||||||
use servo_msg::engine::{EngineChan, LoadUrlMsg};
|
use servo_msg::constellation_msg::{ConstellationChan, LoadUrlMsg, NavigationDirection};
|
||||||
|
use servo_msg::constellation_msg::RendererReadyMsg;
|
||||||
|
use servo_msg::constellation_msg;
|
||||||
|
|
||||||
use std::cast::transmute;
|
use std::cast::transmute;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
@ -51,13 +55,15 @@ pub enum ScriptMsg {
|
||||||
LoadMsg(Url),
|
LoadMsg(Url),
|
||||||
/// Executes a standalone script.
|
/// Executes a standalone script.
|
||||||
ExecuteMsg(Url),
|
ExecuteMsg(Url),
|
||||||
|
/// Instructs the script task to send a navigate message to the constellation.
|
||||||
|
NavigateMsg(NavigationDirection),
|
||||||
/// Sends a DOM event.
|
/// Sends a DOM event.
|
||||||
SendEventMsg(Event),
|
SendEventMsg(Event),
|
||||||
/// Fires a JavaScript timeout.
|
/// Fires a JavaScript timeout.
|
||||||
FireTimerMsg(~TimerData),
|
FireTimerMsg(~TimerData),
|
||||||
/// Notifies script that reflow is finished.
|
/// Notifies script that reflow is finished.
|
||||||
ReflowCompleteMsg,
|
ReflowCompleteMsg,
|
||||||
/// Exits the engine.
|
/// Exits the constellation.
|
||||||
ExitMsg,
|
ExitMsg,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +97,9 @@ pub struct Frame {
|
||||||
/// frames.
|
/// frames.
|
||||||
///
|
///
|
||||||
/// FIXME: Rename to `Page`, following WebKit?
|
/// FIXME: Rename to `Page`, following WebKit?
|
||||||
pub struct ScriptContext {
|
pub struct ScriptTask {
|
||||||
|
/// A unique identifier to the script's pipeline
|
||||||
|
id: uint,
|
||||||
/// A handle to the layout task.
|
/// A handle to the layout task.
|
||||||
layout_chan: LayoutChan,
|
layout_chan: LayoutChan,
|
||||||
/// A handle to the image cache task.
|
/// A handle to the image cache task.
|
||||||
|
@ -108,10 +116,10 @@ pub struct ScriptContext {
|
||||||
/// messages.
|
/// messages.
|
||||||
script_chan: ScriptChan,
|
script_chan: ScriptChan,
|
||||||
|
|
||||||
/// For communicating load url messages to the engine
|
/// For communicating load url messages to the constellation
|
||||||
engine_chan: EngineChan,
|
constellation_chan: ConstellationChan,
|
||||||
/// For communicating loading messages to the compositor
|
/// For permission to communicate ready state messages to the compositor
|
||||||
compositor_task: ~fn(ReadyState),
|
compositor: @ScriptListener,
|
||||||
|
|
||||||
/// The JavaScript runtime.
|
/// The JavaScript runtime.
|
||||||
js_runtime: js::rust::rt,
|
js_runtime: js::rust::rt,
|
||||||
|
@ -132,28 +140,33 @@ pub struct ScriptContext {
|
||||||
window_size: Size2D<uint>,
|
window_size: Size2D<uint>,
|
||||||
/// What parts of the document are dirty, if any.
|
/// What parts of the document are dirty, if any.
|
||||||
damage: Option<DocumentDamage>,
|
damage: Option<DocumentDamage>,
|
||||||
|
|
||||||
|
/// Cached copy of the most recent url loaded by the script
|
||||||
|
/// TODO(tkuehn): this currently does not follow any particular caching policy
|
||||||
|
/// and simply caches pages forever (!).
|
||||||
|
last_loaded_url: Option<Url>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn global_script_context_key(_: @ScriptContext) {}
|
fn global_script_context_key(_: @ScriptTask) {}
|
||||||
|
|
||||||
/// Returns this task's script context singleton.
|
/// Returns this task's script context singleton.
|
||||||
pub fn global_script_context() -> @ScriptContext {
|
pub fn global_script_context() -> @ScriptTask {
|
||||||
unsafe {
|
unsafe {
|
||||||
local_data::local_data_get(global_script_context_key).get()
|
local_data::local_data_get(global_script_context_key).get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the script context from the JS Context.
|
/// Returns the script task from the JS Context.
|
||||||
///
|
///
|
||||||
/// FIXME: Rename to `script_context_from_js_context`.
|
/// FIXME: Rename to `script_context_from_js_context`.
|
||||||
pub fn task_from_context(js_context: *JSContext) -> *mut ScriptContext {
|
pub fn task_from_context(js_context: *JSContext) -> *mut ScriptTask {
|
||||||
unsafe {
|
unsafe {
|
||||||
JS_GetContextPrivate(js_context) as *mut ScriptContext
|
JS_GetContextPrivate(js_context) as *mut ScriptTask
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unsafe_destructor]
|
#[unsafe_destructor]
|
||||||
impl Drop for ScriptContext {
|
impl Drop for ScriptTask {
|
||||||
fn finalize(&self) {
|
fn finalize(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let _ = local_data::local_data_pop(global_script_context_key);
|
let _ = local_data::local_data_pop(global_script_context_key);
|
||||||
|
@ -161,16 +174,17 @@ impl Drop for ScriptContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScriptContext {
|
impl ScriptTask {
|
||||||
/// Creates a new script context.
|
/// Creates a new script task.
|
||||||
pub fn new(layout_chan: LayoutChan,
|
pub fn new(id: uint,
|
||||||
|
compositor: @ScriptListener,
|
||||||
|
layout_chan: LayoutChan,
|
||||||
script_port: Port<ScriptMsg>,
|
script_port: Port<ScriptMsg>,
|
||||||
script_chan: ScriptChan,
|
script_chan: ScriptChan,
|
||||||
engine_chan: EngineChan,
|
constellation_chan: ConstellationChan,
|
||||||
compositor_task: ~fn(ReadyState),
|
|
||||||
resource_task: ResourceTask,
|
resource_task: ResourceTask,
|
||||||
img_cache_task: ImageCacheTask)
|
img_cache_task: ImageCacheTask)
|
||||||
-> @mut ScriptContext {
|
-> @mut ScriptTask {
|
||||||
let js_runtime = js::rust::rt();
|
let js_runtime = js::rust::rt();
|
||||||
let js_context = js_runtime.cx();
|
let js_context = js_runtime.cx();
|
||||||
|
|
||||||
|
@ -182,7 +196,10 @@ impl ScriptContext {
|
||||||
Err(()) => fail!("Failed to create a compartment"),
|
Err(()) => fail!("Failed to create a compartment"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let script_context = @mut ScriptContext {
|
let script_task = @mut ScriptTask {
|
||||||
|
id: id,
|
||||||
|
compositor: compositor,
|
||||||
|
|
||||||
layout_chan: layout_chan,
|
layout_chan: layout_chan,
|
||||||
image_cache_task: img_cache_task,
|
image_cache_task: img_cache_task,
|
||||||
resource_task: resource_task,
|
resource_task: resource_task,
|
||||||
|
@ -191,8 +208,7 @@ impl ScriptContext {
|
||||||
script_port: script_port,
|
script_port: script_port,
|
||||||
script_chan: script_chan,
|
script_chan: script_chan,
|
||||||
|
|
||||||
engine_chan: engine_chan,
|
constellation_chan: constellation_chan,
|
||||||
compositor_task: compositor_task,
|
|
||||||
|
|
||||||
js_runtime: js_runtime,
|
js_runtime: js_runtime,
|
||||||
js_context: js_context,
|
js_context: js_context,
|
||||||
|
@ -205,19 +221,21 @@ impl ScriptContext {
|
||||||
|
|
||||||
window_size: Size2D(800u, 600),
|
window_size: Size2D(800u, 600),
|
||||||
damage: None,
|
damage: None,
|
||||||
|
|
||||||
|
last_loaded_url: None,
|
||||||
};
|
};
|
||||||
// Indirection for Rust Issue #6248, dynamic freeze scope artifically extended
|
// Indirection for Rust Issue #6248, dynamic freeze scope artifically extended
|
||||||
let script_context_ptr = {
|
let script_task_ptr = {
|
||||||
let borrowed_ctx= &mut *script_context;
|
let borrowed_ctx= &mut *script_task;
|
||||||
borrowed_ctx as *mut ScriptContext
|
borrowed_ctx as *mut ScriptTask
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
js_context.set_cx_private(script_context_ptr as *());
|
js_context.set_cx_private(script_task_ptr as *());
|
||||||
local_data::local_data_set(global_script_context_key, transmute(script_context))
|
local_data::local_data_set(global_script_context_key, transmute(script_task))
|
||||||
}
|
}
|
||||||
|
|
||||||
script_context
|
script_task
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Starts the script task. After calling this method, the script task will loop receiving
|
/// Starts the script task. After calling this method, the script task will loop receiving
|
||||||
|
@ -228,58 +246,47 @@ impl ScriptContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_script_context(layout_chan: LayoutChan,
|
pub fn create<C: ScriptListener + Owned>(id: uint,
|
||||||
script_port: Port<ScriptMsg>,
|
compositor: C,
|
||||||
script_chan: ScriptChan,
|
layout_chan: LayoutChan,
|
||||||
engine_chan: EngineChan,
|
script_port: Port<ScriptMsg>,
|
||||||
compositor_task: ~fn(ReadyState),
|
script_chan: ScriptChan,
|
||||||
resource_task: ResourceTask,
|
constellation_chan: ConstellationChan,
|
||||||
image_cache_task: ImageCacheTask) {
|
resource_task: ResourceTask,
|
||||||
|
image_cache_task: ImageCacheTask) {
|
||||||
|
let compositor = Cell::new(compositor);
|
||||||
let script_port = Cell::new(script_port);
|
let script_port = Cell::new(script_port);
|
||||||
let compositor_task = Cell::new(compositor_task);
|
|
||||||
// FIXME: rust#6399
|
// FIXME: rust#6399
|
||||||
let mut the_task = task();
|
let mut the_task = task();
|
||||||
the_task.sched_mode(SingleThreaded);
|
the_task.sched_mode(SingleThreaded);
|
||||||
do the_task.spawn {
|
do spawn {
|
||||||
let script_context = ScriptContext::new(layout_chan.clone(),
|
let script_task = ScriptTask::new(id,
|
||||||
script_port.take(),
|
@compositor.take() as @ScriptListener,
|
||||||
script_chan.clone(),
|
layout_chan.clone(),
|
||||||
engine_chan.clone(),
|
script_port.take(),
|
||||||
compositor_task.take(),
|
script_chan.clone(),
|
||||||
resource_task.clone(),
|
constellation_chan.clone(),
|
||||||
image_cache_task.clone());
|
resource_task.clone(),
|
||||||
script_context.start();
|
image_cache_task.clone());
|
||||||
|
script_task.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles an incoming control message.
|
/// Handles an incoming control message.
|
||||||
fn handle_msg(&mut self) -> bool {
|
fn handle_msg(&mut self) -> bool {
|
||||||
match self.script_port.recv() {
|
match self.script_port.recv() {
|
||||||
LoadMsg(url) => {
|
LoadMsg(url) => self.load(url),
|
||||||
self.load(url);
|
ExecuteMsg(url) => self.handle_execute_msg(url),
|
||||||
true
|
SendEventMsg(event) => self.handle_event(event),
|
||||||
}
|
FireTimerMsg(timer_data) => self.handle_fire_timer_msg(timer_data),
|
||||||
ExecuteMsg(url) => {
|
NavigateMsg(direction) => self.handle_navigate_msg(direction),
|
||||||
self.handle_execute_msg(url);
|
ReflowCompleteMsg => self.handle_reflow_complete_msg(),
|
||||||
true
|
|
||||||
}
|
|
||||||
SendEventMsg(event) => {
|
|
||||||
self.handle_event(event);
|
|
||||||
true
|
|
||||||
}
|
|
||||||
FireTimerMsg(timer_data) => {
|
|
||||||
self.handle_fire_timer_msg(timer_data);
|
|
||||||
true
|
|
||||||
}
|
|
||||||
ReflowCompleteMsg => {
|
|
||||||
self.handle_reflow_complete_msg();
|
|
||||||
true
|
|
||||||
}
|
|
||||||
ExitMsg => {
|
ExitMsg => {
|
||||||
self.handle_exit_msg();
|
self.handle_exit_msg();
|
||||||
false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles a request to execute a script.
|
/// Handles a request to execute a script.
|
||||||
|
@ -324,7 +331,13 @@ impl ScriptContext {
|
||||||
/// Handles a notification that reflow completed.
|
/// Handles a notification that reflow completed.
|
||||||
fn handle_reflow_complete_msg(&mut self) {
|
fn handle_reflow_complete_msg(&mut self) {
|
||||||
self.layout_join_port = None;
|
self.layout_join_port = None;
|
||||||
self.set_ready_state(FinishedLoading)
|
self.constellation_chan.send(RendererReadyMsg(self.id));
|
||||||
|
self.compositor.set_ready_state(FinishedLoading);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handles a navigate forward or backward message.
|
||||||
|
fn handle_navigate_msg(&self, direction: NavigationDirection) {
|
||||||
|
self.constellation_chan.send(constellation_msg::NavigateMsg(direction));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles a request to exit the script task and shut down layout.
|
/// Handles a request to exit the script task and shut down layout.
|
||||||
|
@ -337,15 +350,12 @@ impl ScriptContext {
|
||||||
self.layout_chan.send(layout_interface::ExitMsg)
|
self.layout_chan.send(layout_interface::ExitMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// tells the compositor when loading starts and finishes
|
|
||||||
// FIXME ~compositor_interface doesn't work right now, which is why this is necessary
|
|
||||||
fn set_ready_state(&self, msg: ReadyState) {
|
|
||||||
(self.compositor_task)(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The entry point to document loading. Defines bindings, sets up the window and document
|
/// The entry point to document loading. Defines bindings, sets up the window and document
|
||||||
/// objects, parses HTML and CSS, and kicks off initial layout.
|
/// objects, parses HTML and CSS, and kicks off initial layout.
|
||||||
fn load(&mut self, url: Url) {
|
fn load(&mut self, url: Url) {
|
||||||
|
for self.last_loaded_url.iter().advance |&last_loaded_url| {
|
||||||
|
if url == last_loaded_url { return; }
|
||||||
|
}
|
||||||
// Define the script DOM bindings.
|
// Define the script DOM bindings.
|
||||||
//
|
//
|
||||||
// FIXME: Can this be done earlier, to save the flag?
|
// FIXME: Can this be done earlier, to save the flag?
|
||||||
|
@ -354,11 +364,11 @@ impl ScriptContext {
|
||||||
self.bindings_initialized = true
|
self.bindings_initialized = true
|
||||||
}
|
}
|
||||||
|
|
||||||
self.set_ready_state(Loading);
|
self.compositor.set_ready_state(Loading);
|
||||||
// Parse HTML.
|
// Parse HTML.
|
||||||
//
|
//
|
||||||
// Note: We can parse the next document in parallel with any previous documents.
|
// Note: We can parse the next document in parallel with any previous documents.
|
||||||
let html_parsing_result = hubbub_html_parser::parse_html(copy url,
|
let html_parsing_result = hubbub_html_parser::parse_html(url.clone(),
|
||||||
self.resource_task.clone(),
|
self.resource_task.clone(),
|
||||||
self.image_cache_task.clone());
|
self.image_cache_task.clone());
|
||||||
|
|
||||||
|
@ -392,7 +402,7 @@ impl ScriptContext {
|
||||||
self.root_frame = Some(Frame {
|
self.root_frame = Some(Frame {
|
||||||
document: document,
|
document: document,
|
||||||
window: window,
|
window: window,
|
||||||
url: url
|
url: url.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Perform the initial reflow.
|
// Perform the initial reflow.
|
||||||
|
@ -412,6 +422,7 @@ impl ScriptContext {
|
||||||
~"???",
|
~"???",
|
||||||
1);
|
1);
|
||||||
}
|
}
|
||||||
|
self.last_loaded_url = Some(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends a ping to layout and waits for the response. The response will arrive when the
|
/// Sends a ping to layout and waits for the response. The response will arrive when the
|
||||||
|
@ -446,7 +457,7 @@ impl ScriptContext {
|
||||||
self.join_layout();
|
self.join_layout();
|
||||||
|
|
||||||
// Tell the user that we're performing layout.
|
// Tell the user that we're performing layout.
|
||||||
self.set_ready_state(PerformingLayout);
|
self.compositor.set_ready_state(PerformingLayout);
|
||||||
|
|
||||||
// Layout will let us know when it's done.
|
// Layout will let us know when it's done.
|
||||||
let (join_port, join_chan) = comm::stream();
|
let (join_port, join_chan) = comm::stream();
|
||||||
|
@ -478,7 +489,7 @@ impl ScriptContext {
|
||||||
/// FIXME: This should basically never be used.
|
/// FIXME: This should basically never be used.
|
||||||
pub fn reflow_all(&mut self, goal: ReflowGoal) {
|
pub fn reflow_all(&mut self, goal: ReflowGoal) {
|
||||||
for self.root_frame.iter().advance |root_frame| {
|
for self.root_frame.iter().advance |root_frame| {
|
||||||
ScriptContext::damage(&mut self.damage,
|
ScriptTask::damage(&mut self.damage,
|
||||||
root_frame.document.root,
|
root_frame.document.root,
|
||||||
MatchSelectorsDocumentDamage)
|
MatchSelectorsDocumentDamage)
|
||||||
}
|
}
|
||||||
|
@ -487,12 +498,10 @@ impl ScriptContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends the given query to layout.
|
/// Sends the given query to layout.
|
||||||
pub fn query_layout(&mut self, query: LayoutQuery) -> Result<LayoutResponse,()> {
|
pub fn query_layout<T: Owned>(&mut self, query: LayoutQuery, response_port: Port<Result<T, ()>>) -> Result<T,()> {
|
||||||
self.join_layout();
|
self.join_layout();
|
||||||
|
self.layout_chan.send(QueryMsg(query));
|
||||||
let (response_port, response_chan) = comm::stream();
|
response_port.recv()
|
||||||
self.layout_chan.send(QueryMsg(query, response_chan));
|
|
||||||
response_port.recv()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds the given damage.
|
/// Adds the given damage.
|
||||||
|
@ -526,7 +535,7 @@ impl ScriptContext {
|
||||||
self.window_size = Size2D(new_width, new_height);
|
self.window_size = Size2D(new_width, new_height);
|
||||||
|
|
||||||
for self.root_frame.iter().advance |root_frame| {
|
for self.root_frame.iter().advance |root_frame| {
|
||||||
ScriptContext::damage(&mut self.damage,
|
ScriptTask::damage(&mut self.damage,
|
||||||
root_frame.document.root,
|
root_frame.document.root,
|
||||||
ReflowDocumentDamage);
|
ReflowDocumentDamage);
|
||||||
}
|
}
|
||||||
|
@ -541,7 +550,7 @@ impl ScriptContext {
|
||||||
debug!("script got reflow event");
|
debug!("script got reflow event");
|
||||||
|
|
||||||
for self.root_frame.iter().advance |root_frame| {
|
for self.root_frame.iter().advance |root_frame| {
|
||||||
ScriptContext::damage(&mut self.damage,
|
ScriptTask::damage(&mut self.damage,
|
||||||
root_frame.document.root,
|
root_frame.document.root,
|
||||||
MatchSelectorsDocumentDamage);
|
MatchSelectorsDocumentDamage);
|
||||||
}
|
}
|
||||||
|
@ -557,7 +566,8 @@ impl ScriptContext {
|
||||||
Some(ref frame) => frame.document.root,
|
Some(ref frame) => frame.document.root,
|
||||||
None => fail!("root frame is None")
|
None => fail!("root frame is None")
|
||||||
};
|
};
|
||||||
match self.query_layout(HitTestQuery(root, point)) {
|
let (port, chan) = comm::stream();
|
||||||
|
match self.query_layout(HitTestQuery(root, point, chan), port) {
|
||||||
Ok(node) => match node {
|
Ok(node) => match node {
|
||||||
HitTestResponse(node) => {
|
HitTestResponse(node) => {
|
||||||
debug!("clicked on %?", node.debug_str());
|
debug!("clicked on %?", node.debug_str());
|
||||||
|
@ -580,12 +590,11 @@ impl ScriptContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => fail!(~"unexpected layout reply")
|
|
||||||
},
|
},
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
debug!(fmt!("layout query error"));
|
debug!(fmt!("layout query error"));
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
MouseDownEvent(*) => {}
|
MouseDownEvent(*) => {}
|
||||||
MouseUpEvent(*) => {}
|
MouseUpEvent(*) => {}
|
||||||
|
@ -594,7 +603,7 @@ impl ScriptContext {
|
||||||
|
|
||||||
priv fn load_url_from_element(&self, element: &Element) {
|
priv fn load_url_from_element(&self, element: &Element) {
|
||||||
// if the node's element is "a," load url from href attr
|
// if the node's element is "a," load url from href attr
|
||||||
for element.attrs.each |attr| {
|
for element.attrs.iter().advance |attr| {
|
||||||
if attr.name == ~"href" {
|
if attr.name == ~"href" {
|
||||||
debug!("clicked on link to %?", attr.value);
|
debug!("clicked on link to %?", attr.value);
|
||||||
let current_url = match self.root_frame {
|
let current_url = match self.root_frame {
|
||||||
|
@ -602,7 +611,7 @@ impl ScriptContext {
|
||||||
None => None
|
None => None
|
||||||
};
|
};
|
||||||
let url = make_url(attr.value.clone(), current_url);
|
let url = make_url(attr.value.clone(), current_url);
|
||||||
self.engine_chan.send(LoadUrlMsg(url));
|
self.constellation_chan.send(LoadUrlMsg(url));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,7 +152,7 @@ impl Profiler {
|
||||||
|
|
||||||
priv fn print_buckets(&mut self) {
|
priv fn print_buckets(&mut self) {
|
||||||
println(fmt!("%31s %15s %15s %15s %15s %15s",
|
println(fmt!("%31s %15s %15s %15s %15s %15s",
|
||||||
"_category (ms)_", "_mean (ms)_", "_median (ms)_",
|
"_category_", "_mean (ms)_", "_median (ms)_",
|
||||||
"_min (ms)_", "_max (ms)_", "_bucket size_"));
|
"_min (ms)_", "_max (ms)_", "_bucket size_"));
|
||||||
for self.buckets.mut_iter().advance |bucket| {
|
for self.buckets.mut_iter().advance |bucket| {
|
||||||
match *bucket {
|
match *bucket {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue