mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
add pipeline.rs, modularized pipelines communicating with constellation
This commit is contained in:
parent
fdb0d820a4
commit
fba7ec423c
19 changed files with 528 additions and 317 deletions
|
@ -8,7 +8,8 @@ use azure::{AzFloat, AzGLContext};
|
|||
use azure::azure_hl::{B8G8R8A8, DrawTarget};
|
||||
use display_list::DisplayList;
|
||||
use servo_msg::compositor::{RenderListener, IdleRenderState, RenderingRenderState, LayerBuffer};
|
||||
use servo_msg::compositor::LayerBufferSet;
|
||||
use servo_msg::compositor::{CompositorToken, LayerBufferSet};
|
||||
use servo_msg::engine::{EngineChan, TokenSurrenderMsg};
|
||||
use font_context::FontContext;
|
||||
use geom::matrix2d::Matrix2D;
|
||||
use geom::point::Point2D;
|
||||
|
@ -20,6 +21,7 @@ use render_context::RenderContext;
|
|||
use std::cell::Cell;
|
||||
use std::comm::{Chan, Port, SharedChan};
|
||||
use std::uint;
|
||||
use std::util::replace;
|
||||
|
||||
use servo_util::time::{ProfilerChan, profile};
|
||||
use servo_util::time;
|
||||
|
@ -29,70 +31,32 @@ pub struct RenderLayer {
|
|||
size: Size2D<uint>
|
||||
}
|
||||
|
||||
pub enum Msg<C> {
|
||||
AttachCompositorMsg(C),
|
||||
pub enum Msg {
|
||||
RenderMsg(RenderLayer),
|
||||
ReRenderMsg(f32),
|
||||
TokenBestowMsg(~CompositorToken),
|
||||
TokenProcureMsg,
|
||||
ExitMsg(Chan<()>),
|
||||
}
|
||||
|
||||
pub struct RenderChan<C> {
|
||||
chan: SharedChan<Msg<C>>,
|
||||
#[deriving(Clone)]
|
||||
pub struct RenderChan {
|
||||
chan: SharedChan<Msg>,
|
||||
}
|
||||
|
||||
impl<C: RenderListener + Owned> Clone for RenderChan<C> {
|
||||
pub fn clone(&self) -> RenderChan<C> {
|
||||
RenderChan {
|
||||
chan: self.chan.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: RenderListener + Owned> RenderChan<C> {
|
||||
pub fn new(chan: Chan<Msg<C>>) -> RenderChan<C> {
|
||||
impl RenderChan {
|
||||
pub fn new(chan: Chan<Msg>) -> RenderChan {
|
||||
RenderChan {
|
||||
chan: SharedChan::new(chan),
|
||||
}
|
||||
}
|
||||
pub fn send(&self, msg: Msg<C>) {
|
||||
pub fn send(&self, msg: Msg) {
|
||||
self.chan.send(msg);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_render_task<C: RenderListener + Owned>(port: Port<Msg<C>>,
|
||||
compositor: C,
|
||||
opts: Opts,
|
||||
profiler_chan: ProfilerChan) {
|
||||
let compositor_cell = Cell::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>>,
|
||||
priv struct RenderTask<C> {
|
||||
port: Port<Msg>,
|
||||
compositor: C,
|
||||
font_ctx: @mut FontContext,
|
||||
opts: Opts,
|
||||
|
@ -104,15 +68,58 @@ priv struct Renderer<C> {
|
|||
|
||||
/// The layer to be rendered
|
||||
render_layer: Option<RenderLayer>,
|
||||
/// A channel to the engine task for surrendering token
|
||||
engine_chan: EngineChan,
|
||||
/// A token that grants permission to send paint messages to compositor
|
||||
compositor_token: Option<~CompositorToken>,
|
||||
/// Cached copy of last layers rendered
|
||||
next_paint_msg: Option<(LayerBufferSet, Size2D<uint>)>,
|
||||
}
|
||||
|
||||
impl<C: RenderListener + Owned> RenderTask<C> {
|
||||
pub fn create(port: Port<Msg>,
|
||||
compositor: C,
|
||||
opts: Opts,
|
||||
engine_chan: EngineChan,
|
||||
profiler_chan: ProfilerChan) {
|
||||
let compositor_cell = Cell::new(compositor);
|
||||
let opts_cell = Cell::new(opts);
|
||||
let port = Cell::new(port);
|
||||
let engine_chan = Cell::new(engine_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 {
|
||||
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,
|
||||
|
||||
engine_chan: engine_chan.take(),
|
||||
compositor_token: None,
|
||||
next_paint_msg: None,
|
||||
};
|
||||
|
||||
render_task.start();
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: RenderListener + Owned> Renderer<C> {
|
||||
fn start(&mut self) {
|
||||
debug!("renderer: beginning rendering loop");
|
||||
debug!("render_task: beginning rendering loop");
|
||||
|
||||
loop {
|
||||
match self.port.recv() {
|
||||
AttachCompositorMsg(compositor) => self.compositor = compositor,
|
||||
RenderMsg(render_layer) => {
|
||||
self.render_layer = Some(render_layer);
|
||||
self.render(1.0);
|
||||
|
@ -120,6 +127,21 @@ impl<C: RenderListener + Owned> Renderer<C> {
|
|||
ReRenderMsg(scale) => {
|
||||
self.render(scale);
|
||||
}
|
||||
TokenBestowMsg(token) => {
|
||||
self.compositor_token = Some(token);
|
||||
let next_paint_msg = replace(&mut self.next_paint_msg, None);
|
||||
match next_paint_msg {
|
||||
Some((layer_buffer_set, layer_size)) => {
|
||||
println("retrieving cached paint msg");
|
||||
self.compositor.paint(layer_buffer_set, layer_size);
|
||||
self.compositor.set_render_state(IdleRenderState);
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
TokenProcureMsg => {
|
||||
self.engine_chan.send(TokenSurrenderMsg(self.compositor_token.swap_unwrap()));
|
||||
}
|
||||
ExitMsg(response_ch) => {
|
||||
response_ch.send(());
|
||||
break;
|
||||
|
@ -129,7 +151,7 @@ impl<C: RenderListener + Owned> Renderer<C> {
|
|||
}
|
||||
|
||||
fn render(&mut self, scale: f32) {
|
||||
debug!("renderer: rendering");
|
||||
debug!("render_task: rendering");
|
||||
|
||||
let render_layer;
|
||||
match (self.render_layer) {
|
||||
|
@ -164,7 +186,8 @@ impl<C: RenderListener + Owned> Renderer<C> {
|
|||
let buffer = LayerBuffer {
|
||||
draw_target: DrawTarget::new_with_fbo(self.opts.render_backend,
|
||||
self.share_gl_context,
|
||||
Size2D(width as i32, height as i32),
|
||||
Size2D(width as i32,
|
||||
height as i32),
|
||||
B8G8R8A8),
|
||||
rect: tile_rect,
|
||||
screen_pos: screen_rect,
|
||||
|
@ -210,8 +233,14 @@ impl<C: RenderListener + Owned> Renderer<C> {
|
|||
buffers: new_buffers,
|
||||
};
|
||||
|
||||
debug!("renderer: returning surface");
|
||||
debug!("render_task: returning surface");
|
||||
if self.compositor_token.is_some() {
|
||||
self.compositor.paint(layer_buffer_set, render_layer.size);
|
||||
}
|
||||
else {
|
||||
println("caching paint msg");
|
||||
self.next_paint_msg = Some((layer_buffer_set, render_layer.size));
|
||||
}
|
||||
self.compositor.set_render_state(IdleRenderState);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ pub enum Msg {
|
|||
/// Sets the channel to the current layout task
|
||||
SetLayoutChan(LayoutChan),
|
||||
/// Sets the channel to the current renderer
|
||||
SetRenderChan(RenderChan<CompositorChan>),
|
||||
SetRenderChan(RenderChan),
|
||||
}
|
||||
|
||||
/// Azure surface wrapping to work with the layers infrastructure.
|
||||
|
@ -176,7 +176,7 @@ impl CompositorTask {
|
|||
let local_zoom = @mut 1f32;
|
||||
// Channel to the current renderer.
|
||||
// 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 update_layout_callbacks: @fn(LayoutChan) = |layout_chan: LayoutChan| {
|
||||
let layout_chan_clone = layout_chan.clone();
|
||||
|
@ -432,3 +432,4 @@ fn on_osmain(f: ~fn()) {
|
|||
f();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,28 +10,69 @@ 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 gfx::render_task::{TokenBestowMsg, TokenProcureMsg};
|
||||
use pipeline::Pipeline;
|
||||
use servo_msg::compositor::{CompositorToken};
|
||||
use servo_msg::engine::{EngineChan, ExitMsg, LoadUrlMsg, Msg, RendererReadyMsg, TokenSurrenderMsg};
|
||||
use script::script_task::{ExecuteMsg, LoadMsg};
|
||||
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 servo_util::time::ProfilerChan;
|
||||
use std::hashmap::HashMap;
|
||||
|
||||
pub struct Engine {
|
||||
chan: EngineChan,
|
||||
request_port: Port<Msg>,
|
||||
compositor_chan: CompositorChan,
|
||||
render_chan: RenderChan<CompositorChan>,
|
||||
resource_task: ResourceTask,
|
||||
image_cache_task: ImageCacheTask,
|
||||
layout_chan: LayoutChan,
|
||||
script_chan: ScriptChan,
|
||||
pipelines: HashMap<uint, Pipeline>,
|
||||
navigation_context: NavigationContext,
|
||||
next_id: uint,
|
||||
current_token_holder: Option<uint>,
|
||||
loading: Option<uint>,
|
||||
profiler_chan: ProfilerChan,
|
||||
opts: Opts,
|
||||
}
|
||||
|
||||
pub struct NavigationContext {
|
||||
previous: ~[uint],
|
||||
next: ~[uint],
|
||||
current: Option<uint>,
|
||||
}
|
||||
|
||||
impl NavigationContext {
|
||||
pub fn new() -> NavigationContext {
|
||||
NavigationContext {
|
||||
previous: ~[],
|
||||
next: ~[],
|
||||
current: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn back(&mut self) -> uint {
|
||||
do self.current.mutate |id| {
|
||||
self.next.push(id);
|
||||
self.previous.pop()
|
||||
}
|
||||
self.current.get()
|
||||
}
|
||||
|
||||
pub fn forward(&mut self) -> uint {
|
||||
do self.current.mutate |id| {
|
||||
self.previous.push(id);
|
||||
self.next.pop()
|
||||
}
|
||||
self.current.get()
|
||||
}
|
||||
|
||||
pub fn navigate(&mut self, id: uint) {
|
||||
do self.current.mutate_default(id) |cur_id| {
|
||||
self.previous.push(cur_id);
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Engine {
|
||||
|
@ -41,105 +82,99 @@ impl Engine {
|
|||
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_port, engine_chan) = comm::stream();
|
||||
let (engine_port, engine_chan) = (Cell::new(engine_port), EngineChan::new(engine_chan));
|
||||
|
||||
let compositor_chan = Cell::new(compositor_chan);
|
||||
let engine_chan_clone = Cell::new(engine_chan.clone());
|
||||
{
|
||||
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 {
|
||||
let mut engine = Engine {
|
||||
chan: engine_chan_clone.take(),
|
||||
request_port: engine_port.take(),
|
||||
compositor_chan: compositor_chan.clone(),
|
||||
render_chan: render_chan.clone(),
|
||||
compositor_chan: compositor_chan.take(),
|
||||
resource_task: resource_task.clone(),
|
||||
image_cache_task: image_cache_task.clone(),
|
||||
layout_chan: layout_chan.clone(),
|
||||
script_chan: script_chan.clone(),
|
||||
pipelines: HashMap::new(),
|
||||
navigation_context: NavigationContext::new(),
|
||||
next_id: 0,
|
||||
current_token_holder: None,
|
||||
loading: None,
|
||||
profiler_chan: profiler_chan.clone(),
|
||||
}.run();
|
||||
opts: opts.take(),
|
||||
};
|
||||
engine.run();
|
||||
}
|
||||
}
|
||||
engine_chan
|
||||
}
|
||||
|
||||
fn run(&self) {
|
||||
while self.handle_request(self.request_port.recv()) {
|
||||
// Go on...
|
||||
fn run(&mut self) {
|
||||
loop {
|
||||
let request = self.request_port.recv();
|
||||
if !self.handle_request(request) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_request(&self, request: Msg) -> bool {
|
||||
fn get_next_id(&mut self) -> uint {
|
||||
let id = self.next_id;
|
||||
self.next_id = id + 1;
|
||||
id
|
||||
}
|
||||
|
||||
fn handle_request(&mut self, request: Msg) -> bool {
|
||||
match request {
|
||||
LoadUrlMsg(url) => {
|
||||
let pipeline_id = self.get_next_id();
|
||||
let 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") {
|
||||
self.script_chan.send(ExecuteMsg(url))
|
||||
pipeline.script_chan.send(ExecuteMsg(url));
|
||||
} else {
|
||||
self.script_chan.send(LoadMsg(url))
|
||||
pipeline.script_chan.send(LoadMsg(url));
|
||||
self.loading = Some(pipeline_id);
|
||||
}
|
||||
return true
|
||||
self.pipelines.insert(pipeline_id, pipeline);
|
||||
}
|
||||
|
||||
RendererReadyMsg(pipeline_id) => {
|
||||
let loading = self.loading.clone();
|
||||
do loading.map() |&id| {
|
||||
if pipeline_id == id {
|
||||
match self.current_token_holder {
|
||||
Some(ref id) => {
|
||||
let current_holder = self.pipelines.find(id).get();
|
||||
current_holder.render_chan.send(TokenProcureMsg);
|
||||
}
|
||||
None => self.bestow_compositor_token(id, ~CompositorToken::new())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TokenSurrenderMsg(token) => {
|
||||
self.remove_active_pipeline();
|
||||
let loading = self.loading.clone();
|
||||
let token = Cell::new(token);
|
||||
do loading.map |&id| {
|
||||
self.bestow_compositor_token(id, token.take());
|
||||
};
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
for self.pipelines.each |_, pipeline| {
|
||||
pipeline.exit();
|
||||
}
|
||||
self.image_cache_task.exit();
|
||||
self.resource_task.send(resource_task::Exit);
|
||||
|
||||
|
@ -147,6 +182,31 @@ impl Engine {
|
|||
return false
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn remove_active_pipeline(&mut self) {
|
||||
// FIXME(tkuehn): currently, pipelines are not removed at all
|
||||
// do self.current_token_holder.map |id| {
|
||||
// self.pipelines.pop(id).unwrap().exit();
|
||||
// };
|
||||
|
||||
self.current_token_holder = None;
|
||||
}
|
||||
|
||||
fn bestow_compositor_token(&mut self, id: uint, compositor_token: ~CompositorToken) {
|
||||
let pipeline = self.pipelines.find(&id);
|
||||
match pipeline {
|
||||
None => fail!("Id of pipeline that made token request does not have a \
|
||||
corresponding struct in Engine's pipelines. This is a bug. :-("),
|
||||
Some(pipeline) => {
|
||||
pipeline.render_chan.send(TokenBestowMsg(compositor_token));
|
||||
self.compositor_chan.send(SetLayoutChan(pipeline.layout_chan.clone()));
|
||||
self.current_token_holder = Some(id);
|
||||
self.loading = None;
|
||||
self.navigation_context.navigate(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
//! The layout task. Performs layout on the DOM, builds display lists and sends them to be
|
||||
/// rendered.
|
||||
|
||||
use compositing::CompositorChan;
|
||||
use css::matching::MatchMethods;
|
||||
use css::select::new_css_select_ctx;
|
||||
use layout::aux::{LayoutData, LayoutAuxMethods};
|
||||
|
@ -34,7 +33,7 @@ use script::dom::node::{AbstractNode, LayoutView};
|
|||
use script::layout_interface::{AddStylesheetMsg, ContentBoxQuery};
|
||||
use script::layout_interface::{HitTestQuery, ContentBoxResponse, HitTestResponse};
|
||||
use script::layout_interface::{ContentBoxesQuery, ContentBoxesResponse, ExitMsg, LayoutQuery};
|
||||
use script::layout_interface::{LayoutResponse, MatchSelectorsDocumentDamage, Msg};
|
||||
use script::layout_interface::{MatchSelectorsDocumentDamage, Msg};
|
||||
use script::layout_interface::{QueryMsg, RouteScriptMsg, Reflow, ReflowDocumentDamage};
|
||||
use script::layout_interface::{ReflowForDisplay, ReflowMsg};
|
||||
use script::script_task::{ReflowCompleteMsg, ScriptChan, ScriptMsg, SendEventMsg};
|
||||
|
@ -45,28 +44,10 @@ use servo_util::time::{ProfilerChan, profile, time};
|
|||
use servo_util::time;
|
||||
use extra::net::url::Url;
|
||||
|
||||
pub fn create_layout_task(port: Port<Msg>,
|
||||
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 {
|
||||
struct LayoutTask {
|
||||
port: Port<Msg>,
|
||||
script_chan: ScriptChan,
|
||||
render_chan: RenderChan<CompositorChan>,
|
||||
render_chan: RenderChan,
|
||||
image_cache_task: ImageCacheTask,
|
||||
local_image_cache: @mut LocalImageCache,
|
||||
font_ctx: @mut FontContext,
|
||||
|
@ -80,17 +61,35 @@ struct Layout {
|
|||
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>,
|
||||
script_chan: ScriptChan,
|
||||
render_chan: RenderChan<CompositorChan>,
|
||||
render_chan: RenderChan,
|
||||
image_cache_task: ImageCacheTask,
|
||||
opts: &Opts,
|
||||
profiler_chan: ProfilerChan)
|
||||
-> Layout {
|
||||
-> LayoutTask {
|
||||
let fctx = @mut FontContext::new(opts.render_backend, true, profiler_chan.clone());
|
||||
|
||||
Layout {
|
||||
LayoutTask {
|
||||
port: port,
|
||||
script_chan: script_chan,
|
||||
render_chan: render_chan,
|
||||
|
@ -135,10 +134,10 @@ impl Layout {
|
|||
self.handle_reflow(data.take());
|
||||
}
|
||||
}
|
||||
QueryMsg(query, chan) => {
|
||||
let chan = Cell::new(chan);
|
||||
QueryMsg(query) => {
|
||||
let query = Cell::new(query);
|
||||
do profile(time::LayoutQueryCategory, self.profiler_chan.clone()) {
|
||||
self.handle_query(query, chan.take());
|
||||
self.handle_query(query.take());
|
||||
}
|
||||
}
|
||||
RouteScriptMsg(script_msg) => {
|
||||
|
@ -268,9 +267,9 @@ impl Layout {
|
|||
|
||||
/// Handles a query from the script task. This is the main routine that DOM functions like
|
||||
/// `getClientRects()` or `getBoundingClientRect()` ultimately invoke.
|
||||
fn handle_query(&self, query: LayoutQuery, reply_chan: Chan<Result<LayoutResponse,()>>) {
|
||||
fn handle_query(&self, query: LayoutQuery) {
|
||||
match query {
|
||||
ContentBoxQuery(node) => {
|
||||
ContentBoxQuery(node, reply_chan) => {
|
||||
// FIXME: Isolate this transmutation into a single "bridge" module.
|
||||
let node: AbstractNode<LayoutView> = unsafe {
|
||||
transmute(node)
|
||||
|
@ -302,7 +301,7 @@ impl Layout {
|
|||
|
||||
reply_chan.send(response)
|
||||
}
|
||||
ContentBoxesQuery(node) => {
|
||||
ContentBoxesQuery(node, reply_chan) => {
|
||||
// FIXME: Isolate this transmutation into a single "bridge" module.
|
||||
let node: AbstractNode<LayoutView> = unsafe {
|
||||
transmute(node)
|
||||
|
@ -322,7 +321,7 @@ impl Layout {
|
|||
|
||||
reply_chan.send(response)
|
||||
}
|
||||
HitTestQuery(node, point) => {
|
||||
HitTestQuery(node, point, reply_chan) => {
|
||||
// FIXME: Isolate this transmutation into a single "bridge" module.
|
||||
let node: AbstractNode<LayoutView> = unsafe {
|
||||
transmute(node)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* 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/. */
|
||||
|
||||
#[macro_escape];
|
||||
{
|
||||
macro_rules! move_ref(
|
||||
{ $x:expr } => { unsafe { let y <- *ptr::to_unsafe_ptr(*$x); y } }
|
||||
|
@ -68,4 +68,13 @@
|
|||
])+)
|
||||
}
|
||||
)
|
||||
|
||||
macro_rules! closure_stream(
|
||||
($Msg:ty, $Chan:ident) => (
|
||||
{
|
||||
let (port, chan) = comm::stream::<$Msg>();
|
||||
(Cell(port), $Chan::new(chan))
|
||||
}
|
||||
);
|
||||
)
|
||||
}
|
||||
|
|
105
src/components/main/pipeline.rs
Normal file
105
src/components/main/pipeline.rs
Normal file
|
@ -0,0 +1,105 @@
|
|||
/* 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;
|
||||
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::layout_interface;
|
||||
use servo_msg::engine::{EngineChan};
|
||||
use script::script_task::{ScriptTask, ScriptChan, ScriptMsg};
|
||||
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,
|
||||
}
|
||||
|
||||
impl Pipeline {
|
||||
/// Starts a render task, layout task, and script task. Returns the channels wrapped in a struct.
|
||||
pub fn create(id: uint,
|
||||
engine_chan: EngineChan,
|
||||
compositor_chan: CompositorChan,
|
||||
image_cache_task: ImageCacheTask,
|
||||
resource_task: ResourceTask,
|
||||
profiler_chan: ProfilerChan,
|
||||
opts: Opts) -> Pipeline {
|
||||
|
||||
macro_rules! closure_stream(
|
||||
($Msg:ty, $Chan:ident) => (
|
||||
{
|
||||
let (port, chan) = comm::stream::<$Msg>();
|
||||
(port, $Chan::new(chan))
|
||||
}
|
||||
);
|
||||
)
|
||||
// Create the script port and channel.
|
||||
let (script_port, script_chan) = closure_stream!(ScriptMsg, ScriptChan);
|
||||
|
||||
// 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>();
|
||||
let render_chan = RenderChan::new(render_chan);
|
||||
|
||||
RenderTask::create(render_port,
|
||||
compositor_chan.clone(),
|
||||
copy opts,
|
||||
engine_chan.clone(),
|
||||
profiler_chan.clone());
|
||||
|
||||
LayoutTask::create(layout_port,
|
||||
script_chan.clone(),
|
||||
render_chan.clone(),
|
||||
image_cache_task.clone(),
|
||||
copy opts,
|
||||
profiler_chan.clone());
|
||||
|
||||
ScriptTask::create(id,
|
||||
compositor_chan.clone(),
|
||||
layout_chan.clone(),
|
||||
script_port,
|
||||
script_chan.clone(),
|
||||
engine_chan,
|
||||
resource_task.clone(),
|
||||
image_cache_task.clone());
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exit(&self) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
@ -63,6 +63,7 @@ pub mod css {
|
|||
}
|
||||
|
||||
pub mod engine;
|
||||
pub mod pipeline;
|
||||
|
||||
pub mod layout {
|
||||
pub mod block;
|
||||
|
|
|
@ -6,6 +6,7 @@ use azure::azure_hl::DrawTarget;
|
|||
use azure::azure::AzGLContext;
|
||||
use geom::rect::Rect;
|
||||
use geom::size::Size2D;
|
||||
use std::util::NonCopyable;
|
||||
|
||||
pub struct LayerBuffer {
|
||||
draw_target: DrawTarget,
|
||||
|
@ -33,14 +34,6 @@ pub enum RenderState {
|
|||
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 {
|
||||
/// Informs the compositor that a page is loading. Used for setting status
|
||||
Loading,
|
||||
|
@ -50,8 +43,30 @@ pub enum ReadyState {
|
|||
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, 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,
|
||||
/// which is used in displaying the appropriate message in the window's title.
|
||||
pub trait ScriptListener : Clone {
|
||||
fn set_ready_state(&self, ReadyState);
|
||||
}
|
||||
|
||||
/// Signifies control of the compositor. Only the render task controlling
|
||||
/// the compositor token may send paint messages to the compositor
|
||||
pub struct CompositorToken {
|
||||
construction_restrictor: NonCopyable,
|
||||
}
|
||||
|
||||
impl CompositorToken {
|
||||
pub fn new() -> CompositorToken {
|
||||
CompositorToken {
|
||||
construction_restrictor: NonCopyable::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
|
||||
use std::comm::{Chan, SharedChan};
|
||||
use extra::net::url::Url;
|
||||
use compositor::CompositorToken;
|
||||
|
||||
pub use compositor;
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct EngineChan {
|
||||
|
@ -27,5 +30,7 @@ impl EngineChan {
|
|||
pub enum Msg {
|
||||
LoadUrlMsg(Url),
|
||||
ExitMsg(Chan<()>),
|
||||
RendererReadyMsg(uint),
|
||||
TokenSurrenderMsg(~CompositorToken),
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ use std::cast;
|
|||
use std::i32;
|
||||
use std::libc;
|
||||
use std::libc::c_uint;
|
||||
use std::comm;
|
||||
use std::ptr;
|
||||
use std::ptr::null;
|
||||
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() {
|
||||
ElementNodeTypeId(HTMLImageElementTypeId) => {
|
||||
let script_context = task_from_context(cx);
|
||||
match (*script_context).query_layout(ContentBoxQuery(node)) {
|
||||
Ok(rect) => {
|
||||
match rect {
|
||||
ContentBoxResponse(rect) => rect.size.width.to_px(),
|
||||
_ => fail!(~"unexpected layout reply")
|
||||
}
|
||||
}
|
||||
let (port, chan) = comm::stream();
|
||||
match (*script_context).query_layout(ContentBoxQuery(node, chan), port) {
|
||||
Ok(ContentBoxResponse(rect)) => rect.size.width.to_px(),
|
||||
Err(()) => 0
|
||||
}
|
||||
// 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();
|
||||
}
|
||||
|
||||
let result = ~"[object " + name + ~"]";
|
||||
let result = ~"[object " + name + "]";
|
||||
for result.iter().enumerate().advance |(i, c)| {
|
||||
*chars.offset(i) = c as jschar;
|
||||
}
|
||||
|
|
|
@ -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_DefineProperties, JS_WrapValue, JS_ForwardGetPropertyTo};
|
||||
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_HasPropertyById, JS_GetPrototype, JS_GetGlobalForObject};
|
||||
use js::jsapi::{JS_NewStringCopyN, JS_DefineFunctions, JS_DefineProperty};
|
||||
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::jsfriendapi::bindgen::JS_NewObjectWithUniqueType;
|
||||
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 retval = str(~"function " + name + ~"() {\n [native code]\n}");
|
||||
let retval = str(~"function " + name + "() {\n [native code]\n}");
|
||||
*vp = domstring_to_jsval(cx, &retval);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
|
|||
use layout_interface::{ContentBoxesResponse};
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::comm;
|
||||
use std::uint;
|
||||
use std::str::eq_slice;
|
||||
use extra::net::url::Url;
|
||||
|
@ -165,20 +166,19 @@ impl<'self> Element {
|
|||
Some(win) => {
|
||||
let node = self.parent.abstract.get();
|
||||
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(ContentBoxesQuery(node)) {
|
||||
Ok(rects) => match rects {
|
||||
ContentBoxesResponse(rects) =>
|
||||
let (port, chan) = comm::stream();
|
||||
match script_task.query_layout(ContentBoxesQuery(node, chan), port) {
|
||||
Ok(ContentBoxesResponse(rects)) => {
|
||||
do rects.map |r| {
|
||||
ClientRect::new(
|
||||
r.origin.y.to_f32(),
|
||||
(r.origin.y + r.size.height).to_f32(),
|
||||
r.origin.x.to_f32(),
|
||||
(r.origin.x + r.size.width).to_f32())
|
||||
},
|
||||
_ => fail!(~"unexpected layout reply")
|
||||
}
|
||||
},
|
||||
Err(()) => {
|
||||
debug!("layout query error");
|
||||
|
@ -207,16 +207,15 @@ impl<'self> Element {
|
|||
Some(win) => {
|
||||
let node = self.parent.abstract.get();
|
||||
assert!(node.is_element());
|
||||
let script_context = unsafe { &mut *win.script_context };
|
||||
match script_context.query_layout(ContentBoxQuery(node)) {
|
||||
Ok(rect) => match rect {
|
||||
ContentBoxResponse(rect) =>
|
||||
let script_task = unsafe { &mut *win.script_task };
|
||||
let (port, chan) = comm::stream();
|
||||
match script_task.query_layout(ContentBoxQuery(node, chan), port) {
|
||||
Ok(ContentBoxResponse(rect)) => {
|
||||
Some(ClientRect::new(
|
||||
rect.origin.y.to_f32(),
|
||||
(rect.origin.y + rect.size.height).to_f32(),
|
||||
rect.origin.x.to_f32(),
|
||||
(rect.origin.x + rect.size.width).to_f32())),
|
||||
_ => fail!(~"unexpected layout result")
|
||||
(rect.origin.x + rect.size.width).to_f32()))
|
||||
},
|
||||
Err(()) => {
|
||||
debug!("error querying layout");
|
||||
|
|
|
@ -9,8 +9,6 @@ use dom::bindings::utils::{DOMString, ErrorResult, WrapperCache};
|
|||
|
||||
use geom::point::Point2D;
|
||||
|
||||
use std::comm;
|
||||
|
||||
pub enum Event {
|
||||
ResizeEvent(uint, uint),
|
||||
ReflowEvent,
|
||||
|
|
|
@ -6,7 +6,7 @@ use dom::bindings::utils::WrapperCache;
|
|||
use dom::bindings::window;
|
||||
|
||||
use layout_interface::ReflowForScriptQuery;
|
||||
use script_task::{ExitMsg, FireTimerMsg, ScriptChan, ScriptContext};
|
||||
use script_task::{ExitMsg, FireTimerMsg, ScriptChan, ScriptTask};
|
||||
|
||||
use std::comm;
|
||||
use std::comm::Chan;
|
||||
|
@ -29,7 +29,7 @@ pub enum TimerControlMsg {
|
|||
pub struct Window {
|
||||
timer_chan: Chan<TimerControlMsg>,
|
||||
script_chan: ScriptChan,
|
||||
script_context: *mut ScriptContext,
|
||||
script_task: *mut ScriptTask,
|
||||
wrapper: WrapperCache
|
||||
}
|
||||
|
||||
|
@ -89,11 +89,11 @@ impl Window {
|
|||
|
||||
pub fn content_changed(&self) {
|
||||
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 {
|
||||
let script_chan_clone = script_chan.clone();
|
||||
let win = @mut Window {
|
||||
|
@ -112,11 +112,11 @@ impl Window {
|
|||
}
|
||||
timer_chan
|
||||
},
|
||||
script_context: script_context,
|
||||
script_task: script_task,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let compartment = (*script_context).js_compartment;
|
||||
let compartment = (*script_task).js_compartment;
|
||||
window::create(compartment, win);
|
||||
}
|
||||
win
|
||||
|
|
|
@ -303,9 +303,9 @@ pub fn parse_html(url: Url,
|
|||
// Handle CSS style sheets from <link> elements
|
||||
ElementNodeTypeId(HTMLLinkElementTypeId) => {
|
||||
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)) => {
|
||||
if rel == ~"stylesheet" {
|
||||
if rel == "stylesheet" {
|
||||
debug!("found CSS stylesheet: %s", href);
|
||||
let url = make_url(href.to_str(), Some(url2.clone()));
|
||||
css_chan2.send(CSSTaskNewFile(UrlProvenance(url)));
|
||||
|
@ -317,7 +317,7 @@ pub fn parse_html(url: Url,
|
|||
},
|
||||
ElementNodeTypeId(HTMLImageElementTypeId) => {
|
||||
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 {
|
||||
None => {}
|
||||
Some(src) => {
|
||||
|
@ -401,7 +401,7 @@ pub fn parse_html(url: Url,
|
|||
unsafe {
|
||||
let script: AbstractNode<ScriptView> = NodeWrapping::from_hubbub_node(script);
|
||||
do script.with_imm_element |script| {
|
||||
match script.get_attr(~"src") {
|
||||
match script.get_attr("src") {
|
||||
Some(src) => {
|
||||
debug!("found script: %s", src);
|
||||
let new_url = make_url(src.to_str(), Some(url.clone()));
|
||||
|
|
|
@ -30,7 +30,7 @@ pub enum Msg {
|
|||
/// Performs a synchronous layout request.
|
||||
///
|
||||
/// 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
|
||||
RouteScriptMsg(ScriptMsg),
|
||||
|
@ -42,25 +42,16 @@ pub enum Msg {
|
|||
/// Synchronous messages that script can send to layout.
|
||||
pub enum LayoutQuery {
|
||||
/// 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.
|
||||
ContentBoxesQuery(AbstractNode<ScriptView>),
|
||||
ContentBoxesQuery(AbstractNode<ScriptView>, Chan<Result<ContentBoxesResponse, ()>>),
|
||||
/// 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.
|
||||
///
|
||||
/// FIXME(pcwalton): This isn't very type safe. Maybe `LayoutQuery` objects should include
|
||||
/// 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>),
|
||||
}
|
||||
pub struct ContentBoxResponse(Rect<Au>);
|
||||
pub struct ContentBoxesResponse(~[Rect<Au>]);
|
||||
pub struct HitTestResponse(AbstractNode<LayoutView>);
|
||||
|
||||
/// Determines which part of the
|
||||
pub enum DocumentDamageLevel {
|
||||
|
|
|
@ -5,19 +5,21 @@
|
|||
/// The script task is the task that owns the DOM in memory, runs JavaScript, and spawns parsing
|
||||
/// and layout tasks.
|
||||
|
||||
use servo_msg::compositor::{ReadyState, Loading, PerformingLayout, FinishedLoading};
|
||||
use servo_msg::compositor::{ScriptListener, Loading, PerformingLayout};
|
||||
use servo_msg::compositor::FinishedLoading;
|
||||
use dom::bindings::utils::GlobalStaticData;
|
||||
use dom::document::Document;
|
||||
use dom::element::Element;
|
||||
use dom::event::{Event, ResizeEvent, ReflowEvent, ClickEvent, MouseDownEvent, MouseUpEvent};
|
||||
use dom::node::{AbstractNode, ScriptView, define_bindings};
|
||||
use dom::window::Window;
|
||||
use layout_interface::{AddStylesheetMsg, DocumentDamage, DocumentDamageLevel, HitTestQuery};
|
||||
use layout_interface::{HitTestResponse, LayoutQuery, LayoutResponse, LayoutChan};
|
||||
use layout_interface::{MatchSelectorsDocumentDamage, QueryMsg, Reflow, ReflowDocumentDamage};
|
||||
use layout_interface::{ReflowForDisplay, ReflowForScriptQuery, ReflowGoal, ReflowMsg};
|
||||
use layout_interface::{AddStylesheetMsg, DocumentDamage};
|
||||
use layout_interface::{DocumentDamageLevel, HitTestQuery, HitTestResponse, LayoutQuery};
|
||||
use layout_interface::{LayoutChan, MatchSelectorsDocumentDamage, QueryMsg, Reflow};
|
||||
use layout_interface::{ReflowDocumentDamage, ReflowForDisplay, ReflowForScriptQuery, ReflowGoal};
|
||||
use layout_interface::ReflowMsg;
|
||||
use layout_interface;
|
||||
use servo_msg::engine::{EngineChan, LoadUrlMsg};
|
||||
use servo_msg::engine::{EngineChan, LoadUrlMsg, RendererReadyMsg};
|
||||
|
||||
use std::cast::transmute;
|
||||
use std::cell::Cell;
|
||||
|
@ -91,7 +93,9 @@ pub struct Frame {
|
|||
/// frames.
|
||||
///
|
||||
/// 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.
|
||||
layout_chan: LayoutChan,
|
||||
/// A handle to the image cache task.
|
||||
|
@ -110,8 +114,8 @@ pub struct ScriptContext {
|
|||
|
||||
/// For communicating load url messages to the engine
|
||||
engine_chan: EngineChan,
|
||||
/// For communicating loading messages to the compositor
|
||||
compositor_task: ~fn(ReadyState),
|
||||
/// For permission to communicate ready state messages to the compositor
|
||||
compositor: @ScriptListener,
|
||||
|
||||
/// The JavaScript runtime.
|
||||
js_runtime: js::rust::rt,
|
||||
|
@ -134,26 +138,26 @@ pub struct ScriptContext {
|
|||
damage: Option<DocumentDamage>,
|
||||
}
|
||||
|
||||
fn global_script_context_key(_: @ScriptContext) {}
|
||||
fn global_script_context_key(_: @ScriptTask) {}
|
||||
|
||||
/// Returns this task's script context singleton.
|
||||
pub fn global_script_context() -> @ScriptContext {
|
||||
pub fn global_script_context() -> @ScriptTask {
|
||||
unsafe {
|
||||
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`.
|
||||
pub fn task_from_context(js_context: *JSContext) -> *mut ScriptContext {
|
||||
pub fn task_from_context(js_context: *JSContext) -> *mut ScriptTask {
|
||||
unsafe {
|
||||
JS_GetContextPrivate(js_context) as *mut ScriptContext
|
||||
JS_GetContextPrivate(js_context) as *mut ScriptTask
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
impl Drop for ScriptContext {
|
||||
impl Drop for ScriptTask {
|
||||
fn finalize(&self) {
|
||||
unsafe {
|
||||
let _ = local_data::local_data_pop(global_script_context_key);
|
||||
|
@ -161,16 +165,17 @@ impl Drop for ScriptContext {
|
|||
}
|
||||
}
|
||||
|
||||
impl ScriptContext {
|
||||
/// Creates a new script context.
|
||||
pub fn new(layout_chan: LayoutChan,
|
||||
impl ScriptTask {
|
||||
/// Creates a new script task.
|
||||
pub fn new(id: uint,
|
||||
compositor: @ScriptListener,
|
||||
layout_chan: LayoutChan,
|
||||
script_port: Port<ScriptMsg>,
|
||||
script_chan: ScriptChan,
|
||||
engine_chan: EngineChan,
|
||||
compositor_task: ~fn(ReadyState),
|
||||
resource_task: ResourceTask,
|
||||
img_cache_task: ImageCacheTask)
|
||||
-> @mut ScriptContext {
|
||||
-> @mut ScriptTask {
|
||||
let js_runtime = js::rust::rt();
|
||||
let js_context = js_runtime.cx();
|
||||
|
||||
|
@ -182,7 +187,10 @@ impl ScriptContext {
|
|||
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,
|
||||
image_cache_task: img_cache_task,
|
||||
resource_task: resource_task,
|
||||
|
@ -192,7 +200,6 @@ impl ScriptContext {
|
|||
script_chan: script_chan,
|
||||
|
||||
engine_chan: engine_chan,
|
||||
compositor_task: compositor_task,
|
||||
|
||||
js_runtime: js_runtime,
|
||||
js_context: js_context,
|
||||
|
@ -207,17 +214,17 @@ impl ScriptContext {
|
|||
damage: None,
|
||||
};
|
||||
// Indirection for Rust Issue #6248, dynamic freeze scope artifically extended
|
||||
let script_context_ptr = {
|
||||
let borrowed_ctx= &mut *script_context;
|
||||
borrowed_ctx as *mut ScriptContext
|
||||
let script_task_ptr = {
|
||||
let borrowed_ctx= &mut *script_task;
|
||||
borrowed_ctx as *mut ScriptTask
|
||||
};
|
||||
|
||||
unsafe {
|
||||
js_context.set_cx_private(script_context_ptr as *());
|
||||
local_data::local_data_set(global_script_context_key, transmute(script_context))
|
||||
js_context.set_cx_private(script_task_ptr as *());
|
||||
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
|
||||
|
@ -228,27 +235,29 @@ impl ScriptContext {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn create_script_context(layout_chan: LayoutChan,
|
||||
pub fn create<C: ScriptListener + Owned>(id: uint,
|
||||
compositor: C,
|
||||
layout_chan: LayoutChan,
|
||||
script_port: Port<ScriptMsg>,
|
||||
script_chan: ScriptChan,
|
||||
engine_chan: EngineChan,
|
||||
compositor_task: ~fn(ReadyState),
|
||||
resource_task: ResourceTask,
|
||||
image_cache_task: ImageCacheTask) {
|
||||
let compositor = Cell::new(compositor);
|
||||
let script_port = Cell::new(script_port);
|
||||
let compositor_task = Cell::new(compositor_task);
|
||||
// FIXME: rust#6399
|
||||
let mut the_task = task();
|
||||
the_task.sched_mode(SingleThreaded);
|
||||
do the_task.spawn {
|
||||
let script_context = ScriptContext::new(layout_chan.clone(),
|
||||
do spawn {
|
||||
let script_task = ScriptTask::new(id,
|
||||
@compositor.take() as @ScriptListener,
|
||||
layout_chan.clone(),
|
||||
script_port.take(),
|
||||
script_chan.clone(),
|
||||
engine_chan.clone(),
|
||||
compositor_task.take(),
|
||||
resource_task.clone(),
|
||||
image_cache_task.clone());
|
||||
script_context.start();
|
||||
script_task.start();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -324,7 +333,8 @@ impl ScriptContext {
|
|||
/// Handles a notification that reflow completed.
|
||||
fn handle_reflow_complete_msg(&mut self) {
|
||||
self.layout_join_port = None;
|
||||
self.set_ready_state(FinishedLoading)
|
||||
self.engine_chan.send(RendererReadyMsg(self.id));
|
||||
self.compositor.set_ready_state(FinishedLoading);
|
||||
}
|
||||
|
||||
/// Handles a request to exit the script task and shut down layout.
|
||||
|
@ -337,12 +347,6 @@ impl ScriptContext {
|
|||
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
|
||||
/// objects, parses HTML and CSS, and kicks off initial layout.
|
||||
fn load(&mut self, url: Url) {
|
||||
|
@ -354,7 +358,7 @@ impl ScriptContext {
|
|||
self.bindings_initialized = true
|
||||
}
|
||||
|
||||
self.set_ready_state(Loading);
|
||||
self.compositor.set_ready_state(Loading);
|
||||
// Parse HTML.
|
||||
//
|
||||
// Note: We can parse the next document in parallel with any previous documents.
|
||||
|
@ -446,7 +450,7 @@ impl ScriptContext {
|
|||
self.join_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.
|
||||
let (join_port, join_chan) = comm::stream();
|
||||
|
@ -478,7 +482,7 @@ impl ScriptContext {
|
|||
/// FIXME: This should basically never be used.
|
||||
pub fn reflow_all(&mut self, goal: ReflowGoal) {
|
||||
for self.root_frame.iter().advance |root_frame| {
|
||||
ScriptContext::damage(&mut self.damage,
|
||||
ScriptTask::damage(&mut self.damage,
|
||||
root_frame.document.root,
|
||||
MatchSelectorsDocumentDamage)
|
||||
}
|
||||
|
@ -487,11 +491,9 @@ impl ScriptContext {
|
|||
}
|
||||
|
||||
/// 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();
|
||||
|
||||
let (response_port, response_chan) = comm::stream();
|
||||
self.layout_chan.send(QueryMsg(query, response_chan));
|
||||
self.layout_chan.send(QueryMsg(query));
|
||||
response_port.recv()
|
||||
}
|
||||
|
||||
|
@ -526,7 +528,7 @@ impl ScriptContext {
|
|||
self.window_size = Size2D(new_width, new_height);
|
||||
|
||||
for self.root_frame.iter().advance |root_frame| {
|
||||
ScriptContext::damage(&mut self.damage,
|
||||
ScriptTask::damage(&mut self.damage,
|
||||
root_frame.document.root,
|
||||
ReflowDocumentDamage);
|
||||
}
|
||||
|
@ -541,7 +543,7 @@ impl ScriptContext {
|
|||
debug!("script got reflow event");
|
||||
|
||||
for self.root_frame.iter().advance |root_frame| {
|
||||
ScriptContext::damage(&mut self.damage,
|
||||
ScriptTask::damage(&mut self.damage,
|
||||
root_frame.document.root,
|
||||
MatchSelectorsDocumentDamage);
|
||||
}
|
||||
|
@ -557,7 +559,8 @@ impl ScriptContext {
|
|||
Some(ref frame) => frame.document.root,
|
||||
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 {
|
||||
HitTestResponse(node) => {
|
||||
debug!("clicked on %?", node.debug_str());
|
||||
|
@ -580,7 +583,6 @@ impl ScriptContext {
|
|||
}
|
||||
}
|
||||
}
|
||||
_ => fail!(~"unexpected layout reply")
|
||||
},
|
||||
Err(()) => {
|
||||
debug!(fmt!("layout query error"));
|
||||
|
@ -594,7 +596,7 @@ impl ScriptContext {
|
|||
|
||||
priv fn load_url_from_element(&self, element: &Element) {
|
||||
// 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" {
|
||||
debug!("clicked on link to %?", attr.value);
|
||||
let current_url = match self.root_frame {
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 68875af396cb583e670dd5caad99431dac62f8db
|
||||
Subproject commit 502ec156da38860a4dff911cf8f33f388a0a1883
|
Loading…
Add table
Add a link
Reference in a new issue