diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/components/compositing/compositing.rs | 2 | ||||
-rw-r--r-- | src/components/compositing/constellation.rs | 52 | ||||
-rw-r--r-- | src/components/compositing/events.rs | 8 | ||||
-rw-r--r-- | src/components/compositing/pipeline.rs | 64 | ||||
-rw-r--r-- | src/components/layout/layout.rs | 1 | ||||
-rw-r--r-- | src/components/layout/layout_task.rs | 79 | ||||
-rw-r--r-- | src/components/layout_traits/layout_traits.rs | 21 | ||||
-rw-r--r-- | src/components/main/servo.rs | 3 | ||||
-rw-r--r-- | src/components/script/dom/event.rs | 12 | ||||
-rw-r--r-- | src/components/script/dom/window.rs | 6 | ||||
-rw-r--r-- | src/components/script/layout_interface.rs | 31 | ||||
-rw-r--r-- | src/components/script/page.rs | 4 | ||||
-rw-r--r-- | src/components/script/script.rs | 1 | ||||
-rw-r--r-- | src/components/script/script_task.rs | 203 | ||||
-rw-r--r-- | src/components/script_traits/script_traits.rs | 98 |
15 files changed, 396 insertions, 189 deletions
diff --git a/src/components/compositing/compositing.rs b/src/components/compositing/compositing.rs index c03cc7ca3e0..ef3875fc58d 100644 --- a/src/components/compositing/compositing.rs +++ b/src/components/compositing/compositing.rs @@ -27,7 +27,7 @@ extern crate layers; extern crate layout_traits; extern crate opengles; extern crate png; -extern crate script; +extern crate script_traits; extern crate servo_msg = "msg"; extern crate servo_net = "net"; #[phase(plugin, link)] diff --git a/src/components/compositing/constellation.rs b/src/components/compositing/constellation.rs index 31030f8a0c2..179327d9962 100644 --- a/src/components/compositing/constellation.rs +++ b/src/components/compositing/constellation.rs @@ -10,11 +10,9 @@ use geom::size::TypedSize2D; use gfx::render_task; use libc; use pipeline::{Pipeline, CompositionPipeline}; -use layout_traits::LayoutTaskFactory; -use script::script_task::{ResizeMsg, ResizeInactiveMsg, ExitPipelineMsg}; -use script::layout_interface; -use script::layout_interface::LayoutChan; -use script::script_task::ScriptChan; +use layout_traits::{LayoutControlChan, LayoutTaskFactory, ExitNowMsg}; +use script_traits::{ResizeMsg, ResizeInactiveMsg, ExitPipelineMsg}; +use script_traits::{ScriptControlChan, ScriptTaskFactory}; use servo_msg::compositor_msg::LayerId; use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, FailureMsg, Failure, FrameRectMsg}; use servo_msg::constellation_msg::{IFrameSandboxState, IFrameUnsandboxed, InitLoadUrlMsg}; @@ -37,7 +35,7 @@ use std::rc::Rc; use url::Url; /// Maintains the pipelines and navigation context and grants permission to composite -pub struct Constellation<LTF> { +pub struct Constellation<LTF, STF> { pub chan: ConstellationChan, pub request_port: Receiver<Msg>, pub compositor_chan: CompositorChan, @@ -240,7 +238,7 @@ impl NavigationContext { } } -impl<LTF: LayoutTaskFactory> Constellation<LTF> { +impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { pub fn start(compositor_chan: CompositorChan, opts: &Opts, resource_task: ResourceTask, @@ -252,7 +250,7 @@ impl<LTF: LayoutTaskFactory> Constellation<LTF> { let constellation_chan_clone = constellation_chan.clone(); let opts_clone = opts.clone(); spawn_named("Constellation", proc() { - let mut constellation : Constellation<LTF> = Constellation { + let mut constellation : Constellation<LTF, STF> = Constellation { chan: constellation_chan_clone, request_port: constellation_port, compositor_chan: compositor_chan, @@ -293,18 +291,18 @@ impl<LTF: LayoutTaskFactory> Constellation<LTF> { script_pipeline: Option<Rc<Pipeline>>, url: Url) -> Rc<Pipeline> { - let pipe = Pipeline::create::<LTF>(id, - subpage_id, - self.chan.clone(), - self.compositor_chan.clone(), - self.image_cache_task.clone(), - self.font_cache_task.clone(), - self.resource_task.clone(), - self.time_profiler_chan.clone(), - self.window_size, - self.opts.clone(), - script_pipeline, - url); + let pipe = Pipeline::create::<LTF, STF>(id, + subpage_id, + self.chan.clone(), + self.compositor_chan.clone(), + self.image_cache_task.clone(), + self.font_cache_task.clone(), + self.resource_task.clone(), + self.time_profiler_chan.clone(), + self.window_size, + self.opts.clone(), + script_pipeline, + url); pipe.load(); Rc::new(pipe) } @@ -421,11 +419,11 @@ impl<LTF: LayoutTaskFactory> Constellation<LTF> { }; fn force_pipeline_exit(old_pipeline: &Rc<Pipeline>) { - let ScriptChan(ref old_script) = old_pipeline.script_chan; + let ScriptControlChan(ref old_script) = old_pipeline.script_chan; let _ = old_script.send_opt(ExitPipelineMsg(old_pipeline.id)); let _ = old_pipeline.render_chan.send_opt(render_task::ExitMsg(None)); - let LayoutChan(ref old_layout) = old_pipeline.layout_chan; - let _ = old_layout.send_opt(layout_interface::ExitNowMsg); + let LayoutControlChan(ref old_layout) = old_pipeline.layout_chan; + let _ = old_layout.send_opt(ExitNowMsg); } force_pipeline_exit(&old_pipeline); self.pipelines.remove(&pipeline_id); @@ -503,7 +501,7 @@ impl<LTF: LayoutTaskFactory> Constellation<LTF> { let pipeline = &child_frame_tree.frame_tree.pipeline; if !already_sent.contains(&pipeline.id) { if is_active { - let ScriptChan(ref script_chan) = pipeline.script_chan; + let ScriptControlChan(ref script_chan) = pipeline.script_chan; script_chan.send(ResizeMsg(pipeline.id, WindowSizeData { visible_viewport: rect.size, initial_viewport: rect.size * ScaleFactor(1.0), @@ -783,7 +781,7 @@ impl<LTF: LayoutTaskFactory> Constellation<LTF> { for frame_tree in self.current_frame().iter() { debug!("constellation sending resize message to active frame"); let pipeline = &frame_tree.pipeline; - let ScriptChan(ref chan) = pipeline.script_chan; + let ScriptControlChan(ref chan) = pipeline.script_chan; let _ = chan.send_opt(ResizeMsg(pipeline.id, new_size)); already_seen.insert(pipeline.id); } @@ -792,7 +790,7 @@ impl<LTF: LayoutTaskFactory> Constellation<LTF> { let pipeline = &frame_tree.pipeline; if !already_seen.contains(&pipeline.id) { debug!("constellation sending resize message to inactive frame"); - let ScriptChan(ref chan) = pipeline.script_chan; + let ScriptControlChan(ref chan) = pipeline.script_chan; let _ = chan.send_opt(ResizeInactiveMsg(pipeline.id, new_size)); already_seen.insert(pipeline.id); } @@ -805,7 +803,7 @@ impl<LTF: LayoutTaskFactory> Constellation<LTF> { if frame_tree.parent.borrow().is_none() { debug!("constellation sending resize message to pending outer frame ({:?})", frame_tree.pipeline.id); - let ScriptChan(ref chan) = frame_tree.pipeline.script_chan; + let ScriptControlChan(ref chan) = frame_tree.pipeline.script_chan; let _ = chan.send_opt(ResizeMsg(frame_tree.pipeline.id, new_size)); } } diff --git a/src/components/compositing/events.rs b/src/components/compositing/events.rs index e4f57a3bb15..4699208eed2 100644 --- a/src/components/compositing/events.rs +++ b/src/components/compositing/events.rs @@ -11,8 +11,8 @@ use geom::rect::{Rect, TypedRect}; use geom::scale_factor::ScaleFactor; use geom::size::{Size2D, TypedSize2D}; use layers::layers::Layer; -use script::dom::event::{ClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent}; -use script::script_task::{ScriptChan, SendEventMsg}; +use script_traits::{ClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent, SendEventMsg}; +use script_traits::{ScriptControlChan}; use servo_msg::compositor_msg::{FixedPosition, LayerId}; use servo_msg::constellation_msg::PipelineId; use servo_util::geometry::{DevicePixel, PagePx}; @@ -139,14 +139,14 @@ pub fn send_mouse_event(layer: Rc<Layer<CompositorData>>, MouseWindowMouseDownEvent(button, _) => MouseDownEvent(button, cursor.to_untyped()), MouseWindowMouseUpEvent(button, _) => MouseUpEvent(button, cursor.to_untyped()), }; - let ScriptChan(ref chan) = layer.extra_data.borrow().pipeline.script_chan; + let ScriptControlChan(ref chan) = layer.extra_data.borrow().pipeline.script_chan; let _ = chan.send_opt(SendEventMsg(layer.extra_data.borrow().pipeline.id.clone(), message)); } pub fn send_mouse_move_event(layer: Rc<Layer<CompositorData>>, cursor: TypedPoint2D<PagePx, f32>) { let message = MouseMoveEvent(cursor.to_untyped()); - let ScriptChan(ref chan) = layer.extra_data.borrow().pipeline.script_chan; + let ScriptControlChan(ref chan) = layer.extra_data.borrow().pipeline.script_chan; let _ = chan.send_opt(SendEventMsg(layer.extra_data.borrow().pipeline.id.clone(), message)); } diff --git a/src/components/compositing/pipeline.rs b/src/components/compositing/pipeline.rs index 2c2a4e5e394..8ccc0fe48a5 100644 --- a/src/components/compositing/pipeline.rs +++ b/src/components/compositing/pipeline.rs @@ -3,14 +3,12 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use CompositorChan; -use layout_traits::LayoutTaskFactory; +use layout_traits::{LayoutTaskFactory, LayoutControlChan}; +use script_traits::{ScriptControlChan, ScriptTaskFactory}; +use script_traits::{AttachLayoutMsg, LoadMsg, NewLayoutInfo, ExitPipelineMsg}; use gfx::render_task::{PaintPermissionGranted, PaintPermissionRevoked}; use gfx::render_task::{RenderChan, RenderTask}; -use script::layout_interface::LayoutChan; -use script::script_task::LoadMsg; -use script::script_task::{AttachLayoutMsg, NewLayoutInfo, ScriptTask, ScriptChan}; -use script::script_task; use servo_msg::constellation_msg::{ConstellationChan, Failure, PipelineId, SubpageId}; use servo_msg::constellation_msg::WindowSizeData; use servo_net::image_cache_task::ImageCacheTask; @@ -25,8 +23,8 @@ use url::Url; pub struct Pipeline { pub id: PipelineId, pub subpage_id: Option<SubpageId>, - pub script_chan: ScriptChan, - pub layout_chan: LayoutChan, + pub script_chan: ScriptControlChan, + pub layout_chan: LayoutControlChan, pub render_chan: RenderChan, pub layout_shutdown_port: Receiver<()>, pub render_shutdown_port: Receiver<()>, @@ -38,7 +36,7 @@ pub struct Pipeline { #[deriving(Clone)] pub struct CompositionPipeline { pub id: PipelineId, - pub script_chan: ScriptChan, + pub script_chan: ScriptControlChan, pub render_chan: RenderChan, } @@ -46,7 +44,7 @@ impl Pipeline { /// Starts a render task, layout task, and possibly a script task. /// Returns the channels wrapped in a struct. /// If script_pipeline is not None, then subpage_id must also be not None. - pub fn create<LTF:LayoutTaskFactory>( + pub fn create<LTF:LayoutTaskFactory, STF:ScriptTaskFactory>( id: PipelineId, subpage_id: Option<SubpageId>, constellation_chan: ConstellationChan, @@ -60,10 +58,11 @@ impl Pipeline { script_pipeline: Option<Rc<Pipeline>>, url: Url) -> Pipeline { - let (layout_port, layout_chan) = LayoutChan::new(); + let layout_pair = ScriptTaskFactory::create_layout_channel(None::<&mut STF>); let (render_port, render_chan) = RenderChan::new(); let (render_shutdown_chan, render_shutdown_port) = channel(); let (layout_shutdown_chan, layout_shutdown_port) = channel(); + let (pipeline_chan, pipeline_port) = channel(); let failure = Failure { pipeline_id: id, @@ -72,28 +71,29 @@ impl Pipeline { let script_chan = match script_pipeline { None => { - let (script_port, script_chan) = ScriptChan::new(); - ScriptTask::create(id, - box compositor_chan.clone(), - layout_chan.clone(), - script_port, - script_chan.clone(), - constellation_chan.clone(), - failure.clone(), - resource_task, - image_cache_task.clone(), - window_size); - script_chan + let (script_chan, script_port) = channel(); + ScriptTaskFactory::create(None::<&mut STF>, + id, + box compositor_chan.clone(), + &layout_pair, + ScriptControlChan(script_chan.clone()), + script_port, + constellation_chan.clone(), + failure.clone(), + resource_task, + image_cache_task.clone(), + window_size); + ScriptControlChan(script_chan) } Some(spipe) => { let new_layout_info = NewLayoutInfo { old_pipeline_id: spipe.id.clone(), new_pipeline_id: id, subpage_id: subpage_id.expect("script_pipeline != None but subpage_id == None"), - layout_chan: layout_chan.clone(), + layout_chan: ScriptTaskFactory::clone_layout_channel(None::<&mut STF>, &layout_pair), }; - let ScriptChan(ref chan) = spipe.script_chan; + let ScriptControlChan(ref chan) = spipe.script_chan; chan.send(AttachLayoutMsg(new_layout_info)); spipe.script_chan.clone() } @@ -111,8 +111,8 @@ impl Pipeline { LayoutTaskFactory::create(None::<&mut LTF>, id, - layout_port, - layout_chan.clone(), + layout_pair, + pipeline_port, constellation_chan, failure, script_chan.clone(), @@ -126,7 +126,7 @@ impl Pipeline { Pipeline::new(id, subpage_id, script_chan, - layout_chan, + LayoutControlChan(pipeline_chan), render_chan, layout_shutdown_port, render_shutdown_port, @@ -135,8 +135,8 @@ impl Pipeline { pub fn new(id: PipelineId, subpage_id: Option<SubpageId>, - script_chan: ScriptChan, - layout_chan: LayoutChan, + script_chan: ScriptControlChan, + layout_chan: LayoutControlChan, render_chan: RenderChan, layout_shutdown_port: Receiver<()>, render_shutdown_port: Receiver<()>, @@ -155,7 +155,7 @@ impl Pipeline { } pub fn load(&self) { - let ScriptChan(ref chan) = self.script_chan; + let ScriptControlChan(ref chan) = self.script_chan; chan.send(LoadMsg(self.id, self.url.clone())); } @@ -173,8 +173,8 @@ impl Pipeline { // Script task handles shutting down layout, and layout handles shutting down the renderer. // For now, if the script task has failed, we give up on clean shutdown. - let ScriptChan(ref chan) = self.script_chan; - if chan.send_opt(script_task::ExitPipelineMsg(self.id)).is_ok() { + let ScriptControlChan(ref chan) = self.script_chan; + if chan.send_opt(ExitPipelineMsg(self.id)).is_ok() { // Wait until all slave tasks have terminated and run destructors // NOTE: We don't wait for script task as we don't always own it let _ = self.render_shutdown_port.recv_opt(); diff --git a/src/components/layout/layout.rs b/src/components/layout/layout.rs index 70fba05db5e..65acf09cc31 100644 --- a/src/components/layout/layout.rs +++ b/src/components/layout/layout.rs @@ -19,6 +19,7 @@ extern crate geom; extern crate gfx; extern crate layout_traits; extern crate script; +extern crate script_traits; extern crate style; #[phase(plugin)] extern crate servo_macros = "macros"; diff --git a/src/components/layout/layout_task.rs b/src/components/layout/layout_task.rs index 8c3fecd3368..e90545ed6d6 100644 --- a/src/components/layout/layout_task.rs +++ b/src/components/layout/layout_task.rs @@ -30,18 +30,18 @@ use gfx::display_list::{DisplayItemIterator, DisplayList, OpaqueNode}; use gfx::font_context::FontContext; use gfx::render_task::{RenderInitMsg, RenderChan, RenderLayer}; use gfx::{render_task, color}; -use layout_traits::LayoutTaskFactory; +use layout_traits; +use layout_traits::{LayoutControlMsg, LayoutTaskFactory}; use script::dom::bindings::js::JS; -use script::dom::event::ReflowEvent; use script::dom::node::{ElementNodeTypeId, LayoutDataRef, Node}; use script::dom::element::{HTMLBodyElementTypeId, HTMLHtmlElementTypeId}; -use script::layout_interface::{AddStylesheetMsg, ContentBoxQuery}; +use script::layout_interface::{AddStylesheetMsg, ContentBoxQuery, ScriptLayoutChan}; use script::layout_interface::{ContentBoxesQuery, ContentBoxesResponse, ExitNowMsg, LayoutQuery}; use script::layout_interface::{HitTestQuery, ContentBoxResponse, HitTestResponse, MouseOverQuery, MouseOverResponse}; use script::layout_interface::{ContentChangedDocumentDamage, LayoutChan, Msg, PrepareToExitMsg}; use script::layout_interface::{QueryMsg, ReapLayoutDataMsg, Reflow, UntrustedNodeAddress}; use script::layout_interface::{ReflowForDisplay, ReflowMsg}; -use script::script_task::{ReflowCompleteMsg, ScriptChan, SendEventMsg}; +use script_traits::{SendEventMsg, ReflowEvent, ReflowCompleteMsg, OpaqueScriptLayoutChannel, ScriptControlChan}; use servo_msg::compositor_msg::Scrollable; use servo_msg::constellation_msg::{ConstellationChan, PipelineId, Failure, FailureMsg}; use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg}; @@ -55,7 +55,7 @@ use servo_util::time::{TimeProfilerChan, profile}; use servo_util::time; use servo_util::task::spawn_named_with_send_on_failure; use servo_util::workqueue::WorkQueue; -use std::comm::{channel, Sender, Receiver}; +use std::comm::{channel, Sender, Receiver, Select}; use std::mem; use std::ptr; use style::{AuthorOrigin, Stylesheet, Stylist}; @@ -68,9 +68,12 @@ pub struct LayoutTask { /// The ID of the pipeline that we belong to. pub id: PipelineId, - /// The port on which we receive messages. + /// The port on which we receive messages from the script task. pub port: Receiver<Msg>, + /// The port on which we receive messages from the constellation + pub pipeline_port: Receiver<LayoutControlMsg>, + //// The channel to send messages to ourself. pub chan: LayoutChan, @@ -78,7 +81,7 @@ pub struct LayoutTask { pub constellation_chan: ConstellationChan, /// The channel on which messages can be sent to the script task. - pub script_chan: ScriptChan, + pub script_chan: ScriptControlChan, /// The channel on which messages can be sent to the painting task. pub render_chan: RenderChan, @@ -258,7 +261,7 @@ impl<'a> BuildDisplayListTraversal<'a> { struct LayoutImageResponder { id: PipelineId, - script_chan: ScriptChan, + script_chan: ScriptControlChan, } impl ImageResponder for LayoutImageResponder { @@ -266,7 +269,7 @@ impl ImageResponder for LayoutImageResponder { let id = self.id.clone(); let script_chan = self.script_chan.clone(); let f: proc(ImageResponseMsg):Send = proc(_) { - let ScriptChan(chan) = script_chan; + let ScriptControlChan(chan) = script_chan; drop(chan.send_opt(SendEventMsg(id.clone(), ReflowEvent))) }; f @@ -277,11 +280,11 @@ impl LayoutTaskFactory for LayoutTask { /// Spawns a new layout task. fn create(_phantom: Option<&mut LayoutTask>, id: PipelineId, - port: Receiver<Msg>, - chan: LayoutChan, + chan: OpaqueScriptLayoutChannel, + pipeline_port: Receiver<LayoutControlMsg>, constellation_chan: ConstellationChan, failure_msg: Failure, - script_chan: ScriptChan, + script_chan: ScriptControlChan, render_chan: RenderChan, img_cache_task: ImageCacheTask, font_cache_task: FontCacheTask, @@ -291,9 +294,11 @@ impl LayoutTaskFactory for LayoutTask { let ConstellationChan(con_chan) = constellation_chan.clone(); spawn_named_with_send_on_failure("LayoutTask", proc() { { // Ensures layout task is destroyed before we send shutdown message + let sender = chan.sender(); let mut layout = LayoutTask::new(id, - port, - chan, + chan.receiver(), + LayoutChan(sender), + pipeline_port, constellation_chan, script_chan, render_chan, @@ -313,8 +318,9 @@ impl LayoutTask { fn new(id: PipelineId, port: Receiver<Msg>, chan: LayoutChan, + pipeline_port: Receiver<LayoutControlMsg>, constellation_chan: ConstellationChan, - script_chan: ScriptChan, + script_chan: ScriptControlChan, render_chan: RenderChan, image_cache_task: ImageCacheTask, font_cache_task: FontCacheTask, @@ -332,6 +338,7 @@ impl LayoutTask { LayoutTask { id: id, port: port, + pipeline_port: pipeline_port, chan: chan, constellation_chan: constellation_chan, script_chan: script_chan, @@ -373,9 +380,45 @@ impl LayoutTask { } } - /// Receives and dispatches messages from the port. + /// Receives and dispatches messages from the script and constellation tasks fn handle_request(&mut self) -> bool { - match self.port.recv() { + enum PortToRead { + Pipeline, + Script, + } + + let port_to_read = { + let sel = Select::new(); + let mut port1 = sel.handle(&self.port); + let mut port2 = sel.handle(&self.pipeline_port); + unsafe { + port1.add(); + port2.add(); + } + let ret = sel.wait(); + if ret == port1.id() { + Script + } else if ret == port2.id() { + Pipeline + } else { + fail!("invalid select result"); + } + }; + + match port_to_read { + Pipeline => match self.pipeline_port.recv() { + layout_traits::ExitNowMsg => self.handle_script_request(ExitNowMsg), + }, + Script => { + let msg = self.port.recv(); + self.handle_script_request(msg) + } + } + } + + /// Receives and dispatches messages from the script task. + fn handle_script_request(&mut self, request: Msg) -> bool { + match request { AddStylesheetMsg(sheet) => self.handle_add_stylesheet(sheet), ReflowMsg(data) => { profile(time::LayoutPerformCategory, self.time_profiler_chan.clone(), || { @@ -764,7 +807,7 @@ impl LayoutTask { // FIXME(pcwalton): This should probably be *one* channel, but we can't fix this without // either select or a filtered recv() that only looks for messages of a given type. data.script_join_chan.send(()); - let ScriptChan(ref chan) = data.script_chan; + let ScriptControlChan(ref chan) = data.script_chan; chan.send(ReflowCompleteMsg(self.id, data.id)); } diff --git a/src/components/layout_traits/layout_traits.rs b/src/components/layout_traits/layout_traits.rs index 31d0c91683b..572721dee24 100644 --- a/src/components/layout_traits/layout_traits.rs +++ b/src/components/layout_traits/layout_traits.rs @@ -9,7 +9,7 @@ #![license = "MPL"] extern crate gfx; -extern crate script; +extern crate script_traits; extern crate servo_msg = "msg"; extern crate servo_net = "net"; extern crate servo_util = "util"; @@ -26,9 +26,16 @@ use servo_msg::constellation_msg::Failure; use servo_net::image_cache_task::ImageCacheTask; use servo_util::opts::Opts; use servo_util::time::TimeProfilerChan; -use script::layout_interface::{LayoutChan, Msg}; -use script::script_task::ScriptChan; -use std::comm::{Sender, Receiver}; +use script_traits::{ScriptControlChan, OpaqueScriptLayoutChannel}; +use std::comm::Sender; + +/// Messages sent to the layout task from the constellation +pub enum LayoutControlMsg { + ExitNowMsg, +} + +/// A channel wrapper for constellation messages +pub struct LayoutControlChan(pub Sender<LayoutControlMsg>); // A static method creating a layout task // Here to remove the compositor -> layout dependency @@ -36,11 +43,11 @@ pub trait LayoutTaskFactory { // FIXME: use a proper static method fn create(_phantom: Option<&mut Self>, id: PipelineId, - port: Receiver<Msg>, - chan: LayoutChan, + chan: OpaqueScriptLayoutChannel, + pipeline_port: Receiver<LayoutControlMsg>, constellation_chan: ConstellationChan, failure_msg: Failure, - script_chan: ScriptChan, + script_chan: ScriptControlChan, render_chan: RenderChan, img_cache_task: ImageCacheTask, font_cache_task: FontCacheTask, diff --git a/src/components/main/servo.rs b/src/components/main/servo.rs index 09225b9ae96..c4ee380fbdc 100644 --- a/src/components/main/servo.rs +++ b/src/components/main/servo.rs @@ -126,7 +126,8 @@ pub fn run(opts: opts::Opts) { ImageCacheTask::new(resource_task.clone()) }; let font_cache_task = FontCacheTask::new(resource_task.clone()); - let constellation_chan = Constellation::<layout::layout_task::LayoutTask>::start( + let constellation_chan = Constellation::<layout::layout_task::LayoutTask, + script::script_task::ScriptTask>::start( compositor_chan, opts, resource_task, diff --git a/src/components/script/dom/event.rs b/src/components/script/dom/event.rs index 115f9a4024b..15709ad5bc1 100644 --- a/src/components/script/dom/event.rs +++ b/src/components/script/dom/event.rs @@ -10,23 +10,11 @@ use dom::bindings::js::{JS, JSRef, Temporary}; use dom::bindings::trace::Traceable; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; use dom::eventtarget::EventTarget; -use servo_msg::constellation_msg::WindowSizeData; use servo_util::str::DOMString; use std::cell::{Cell, RefCell}; -use geom::point::Point2D; - use time; -pub enum Event_ { - ResizeEvent(WindowSizeData), - ReflowEvent, - ClickEvent(uint, Point2D<f32>), - MouseDownEvent(uint, Point2D<f32>), - MouseUpEvent(uint, Point2D<f32>), - MouseMoveEvent(Point2D<f32>) -} - #[deriving(Encodable)] pub enum EventPhase { PhaseNone = EventConstants::NONE as int, diff --git a/src/components/script/dom/window.rs b/src/components/script/dom/window.rs index 070c2373792..b73b37c4c66 100644 --- a/src/components/script/dom/window.rs +++ b/src/components/script/dom/window.rs @@ -21,6 +21,7 @@ use dom::screen::Screen; use layout_interface::{ReflowForDisplay, DocumentDamageLevel}; use page::Page; use script_task::{ExitWindowMsg, FireTimerMsg, ScriptChan, TriggerLoadMsg, TriggerFragmentMsg}; +use script_traits::ScriptControlChan; use servo_msg::compositor_msg::ScriptListener; use servo_net::image_cache_task::ImageCacheTask; @@ -73,6 +74,7 @@ impl TimerHandle { pub struct Window { eventtarget: EventTarget, pub script_chan: ScriptChan, + control_chan: ScriptControlChan, console: Cell<Option<JS<Console>>>, location: Cell<Option<JS<Location>>>, navigator: Cell<Option<JS<Navigator>>>, @@ -287,7 +289,7 @@ impl<'a> WindowHelpers for JSRef<'a, Window> { // currently rely on the display list, which means we can't destroy it by // doing a query reflow. self.page().damage(damage); - self.page().reflow(ReflowForDisplay, self.script_chan.clone(), *self.compositor); + self.page().reflow(ReflowForDisplay, self.control_chan.clone(), *self.compositor); } fn wait_until_safe_to_modify_dom(&self) { @@ -402,12 +404,14 @@ impl Window { pub fn new(cx: *mut JSContext, page: Rc<Page>, script_chan: ScriptChan, + control_chan: ScriptControlChan, compositor: Box<ScriptListener>, image_cache_task: ImageCacheTask) -> Temporary<Window> { let win = box Window { eventtarget: EventTarget::new_inherited(WindowTypeId), script_chan: script_chan, + control_chan: control_chan, console: Cell::new(None), compositor: Untraceable::new(compositor), page: page, diff --git a/src/components/script/layout_interface.rs b/src/components/script/layout_interface.rs index 0e84554c8a7..892c64414c3 100644 --- a/src/components/script/layout_interface.rs +++ b/src/components/script/layout_interface.rs @@ -12,11 +12,13 @@ use dom::node::{Node, LayoutDataRef}; use geom::point::Point2D; use geom::rect::Rect; use libc::c_void; -use script_task::{ScriptChan}; +use script_traits::{ScriptControlChan, OpaqueScriptLayoutChannel}; use servo_msg::constellation_msg::WindowSizeData; use servo_util::geometry::Au; +use std::any::{Any, AnyRefExt}; use std::cmp; use std::comm::{channel, Receiver, Sender}; +use std::owned::BoxAny; use style::Stylesheet; use url::Url; @@ -135,7 +137,7 @@ pub struct Reflow { /// The URL of the page. pub url: Url, /// The channel through which messages can be sent back to the script task. - pub script_chan: ScriptChan, + pub script_chan: ScriptControlChan, /// The current window size. pub window_size: WindowSizeData, /// The channel that we send a notification to. @@ -155,6 +157,31 @@ impl LayoutChan { } } +/// A trait to manage opaque references to script<->layout channels without needing +/// to expose the message type to crates that don't need to know about them. +pub trait ScriptLayoutChan { + fn new(sender: Sender<Msg>, receiver: Receiver<Msg>) -> Self; + fn sender(&self) -> Sender<Msg>; + fn receiver(self) -> Receiver<Msg>; +} + +impl ScriptLayoutChan for OpaqueScriptLayoutChannel { + fn new(sender: Sender<Msg>, receiver: Receiver<Msg>) -> OpaqueScriptLayoutChannel { + let inner = (box sender as Box<Any+Send>, box receiver as Box<Any+Send>); + OpaqueScriptLayoutChannel(inner) + } + + fn sender(&self) -> Sender<Msg> { + let &OpaqueScriptLayoutChannel((ref sender, _)) = self; + (*sender.as_ref::<Sender<Msg>>().unwrap()).clone() + } + + fn receiver(self) -> Receiver<Msg> { + let OpaqueScriptLayoutChannel((_, receiver)) = self; + *receiver.downcast::<Receiver<Msg>>().unwrap() + } +} + #[test] fn test_add_damage() { fn assert_add(mut a: DocumentDamageLevel, b: DocumentDamageLevel, diff --git a/src/components/script/page.rs b/src/components/script/page.rs index 8543c887da7..227a6e66e3c 100644 --- a/src/components/script/page.rs +++ b/src/components/script/page.rs @@ -17,7 +17,7 @@ use layout_interface::{DocumentDamageLevel, HitTestQuery, HitTestResponse, Layou use layout_interface::{LayoutChan, QueryMsg}; use layout_interface::{Reflow, ReflowGoal, ReflowMsg}; use layout_interface::UntrustedNodeAddress; -use script_task::ScriptChan; +use script_traits::ScriptControlChan; use geom::point::Point2D; use js::rust::Cx; @@ -301,7 +301,7 @@ impl Page { /// This function fails if there is no root frame. pub fn reflow(&self, goal: ReflowGoal, - script_chan: ScriptChan, + script_chan: ScriptControlChan, compositor: &ScriptListener) { let root = match *self.frame() { diff --git a/src/components/script/script.rs b/src/components/script/script.rs index 134d032f635..51a7caf8527 100644 --- a/src/components/script/script.rs +++ b/src/components/script/script.rs @@ -33,6 +33,7 @@ extern crate net; extern crate rustrt; extern crate serialize; extern crate time; +extern crate script_traits; #[phase(plugin)] extern crate servo_macros = "macros"; extern crate servo_net = "net"; diff --git a/src/components/script/script_task.rs b/src/components/script/script_task.rs index 8a9e022312e..d431bc368bf 100644 --- a/src/components/script/script_task.rs +++ b/src/components/script/script_task.rs @@ -14,7 +14,6 @@ use dom::bindings::utils::{wrap_for_same_compartment, pre_wrap}; use dom::document::{Document, HTMLDocument, DocumentHelpers}; use dom::element::{Element, HTMLButtonElementTypeId, HTMLInputElementTypeId}; use dom::element::{HTMLSelectElementTypeId, HTMLTextAreaElementTypeId, HTMLOptionElementTypeId}; -use dom::event::{Event_, ResizeEvent, ReflowEvent, ClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent}; use dom::event::Event; use dom::uievent::UIEvent; use dom::eventtarget::{EventTarget, EventTargetHelpers}; @@ -26,7 +25,7 @@ use html::hubbub_html_parser::HtmlParserResult; use html::hubbub_html_parser::{HtmlDiscoveredStyle, HtmlDiscoveredScript}; use html::hubbub_html_parser; use layout_interface::AddStylesheetMsg; -use layout_interface::{LayoutChan, MatchSelectorsDocumentDamage}; +use layout_interface::{ScriptLayoutChan, LayoutChan, MatchSelectorsDocumentDamage}; use layout_interface::{ReflowDocumentDamage, ReflowForDisplay}; use layout_interface::ContentChangedDocumentDamage; use layout_interface; @@ -38,17 +37,23 @@ use js::jsapi::{JSContext, JSRuntime}; use js::rust::{Cx, RtUtils}; use js::rust::with_compartment; use js; +use script_traits::{CompositorEvent, ResizeEvent, ReflowEvent, ClickEvent, MouseDownEvent}; +use script_traits::{MouseMoveEvent, MouseUpEvent, ConstellationControlMsg, ScriptTaskFactory}; +use script_traits::{ResizeMsg, AttachLayoutMsg, LoadMsg, SendEventMsg, ResizeInactiveMsg}; +use script_traits::{ExitPipelineMsg, NewLayoutInfo, OpaqueScriptLayoutChannel, ScriptControlChan}; +use script_traits::ReflowCompleteMsg; use servo_msg::compositor_msg::{FinishedLoading, LayerId, Loading}; use servo_msg::compositor_msg::{ScriptListener}; use servo_msg::constellation_msg::{ConstellationChan, LoadCompleteMsg, LoadUrlMsg, NavigationDirection}; -use servo_msg::constellation_msg::{PipelineId, SubpageId, Failure, FailureMsg, WindowSizeData}; +use servo_msg::constellation_msg::{PipelineId, Failure, FailureMsg, WindowSizeData}; use servo_msg::constellation_msg; use servo_net::image_cache_task::ImageCacheTask; use servo_net::resource_task::ResourceTask; use servo_util::geometry::to_frac_px; use servo_util::task::spawn_named_with_send_on_failure; +use std::any::{Any, AnyRefExt}; use std::cell::RefCell; -use std::comm::{channel, Sender, Receiver}; +use std::comm::{channel, Sender, Receiver, Select}; use std::mem::replace; use std::rc::Rc; use url::Url; @@ -59,42 +64,21 @@ local_data_key!(pub StackRoots: *const RootCollection) /// Messages used to control the script task. pub enum ScriptMsg { - /// Loads a new URL on the specified pipeline. - LoadMsg(PipelineId, Url), /// Acts on a fragment URL load on the specified pipeline. TriggerFragmentMsg(PipelineId, Url), /// Begins a content-initiated load on the specified pipeline. TriggerLoadMsg(PipelineId, Url), - /// Gives a channel and ID to a layout task, as well as the ID of that layout's parent - AttachLayoutMsg(NewLayoutInfo), /// Instructs the script task to send a navigate message to the constellation. NavigateMsg(NavigationDirection), - /// Sends a DOM event. - SendEventMsg(PipelineId, Event_), - /// Window resized. Sends a DOM event eventually, but first we combine events. - ResizeMsg(PipelineId, WindowSizeData), /// Fires a JavaScript timeout. FireTimerMsg(PipelineId, TimerId), - /// Notifies script that reflow is finished. - ReflowCompleteMsg(PipelineId, uint), - /// Notifies script that window has been resized but to not take immediate action. - ResizeInactiveMsg(PipelineId, WindowSizeData), - /// Notifies the script that a pipeline should be closed. - ExitPipelineMsg(PipelineId), /// Notifies the script that a window associated with a particular pipeline should be closed. ExitWindowMsg(PipelineId), /// Notifies the script of progress on a fetch XHRProgressMsg(TrustedXHRAddress, XHRProgress) } -pub struct NewLayoutInfo { - pub old_pipeline_id: PipelineId, - pub new_pipeline_id: PipelineId, - pub subpage_id: SubpageId, - pub layout_chan: LayoutChan, -} - -/// Encapsulates external communication with the script task. +/// Encapsulates internal communication within the script task. #[deriving(Clone)] pub struct ScriptChan(pub Sender<ScriptMsg>); @@ -141,10 +125,17 @@ pub struct ScriptTask { /// The port on which the script task receives messages (load URL, exit, etc.) port: Receiver<ScriptMsg>, - /// A channel to hand out when some other task needs to be able to respond to a message from - /// the script task. + /// A channel to hand out to script task-based entities that need to be able to enqueue + /// events in the event queue. chan: ScriptChan, + /// A channel to hand out to tasks that need to respond to a message from the script task. + control_chan: ScriptControlChan, + + /// The port on which the constellation and layout tasks can communicate with the + /// script task. + control_port: Receiver<ConstellationControlMsg>, + /// For communicating load url messages to the constellation constellation_chan: ConstellationChan, /// A handle to the compositor for communicating ready state messages. @@ -212,6 +203,52 @@ impl<'a> PrivateScriptTaskHelpers for JSRef<'a, Node> { } } +impl ScriptTaskFactory for ScriptTask { + fn create_layout_channel(_phantom: Option<&mut ScriptTask>) -> OpaqueScriptLayoutChannel { + let (chan, port) = channel(); + ScriptLayoutChan::new(chan, port) + } + + fn clone_layout_channel(_phantom: Option<&mut ScriptTask>, pair: &OpaqueScriptLayoutChannel) -> Box<Any+Send> { + box pair.sender() as Box<Any+Send> + } + + fn create<C:ScriptListener + Send>( + _phantom: Option<&mut ScriptTask>, + id: PipelineId, + compositor: Box<C>, + layout_chan: &OpaqueScriptLayoutChannel, + control_chan: ScriptControlChan, + control_port: Receiver<ConstellationControlMsg>, + constellation_chan: ConstellationChan, + failure_msg: Failure, + resource_task: ResourceTask, + image_cache_task: ImageCacheTask, + window_size: WindowSizeData) { + let ConstellationChan(const_chan) = constellation_chan.clone(); + let (script_chan, script_port) = channel(); + let layout_chan = LayoutChan(layout_chan.sender()); + spawn_named_with_send_on_failure("ScriptTask", proc() { + let script_task = ScriptTask::new(id, + compositor as Box<ScriptListener>, + layout_chan, + script_port, + ScriptChan(script_chan), + control_chan, + control_port, + constellation_chan, + resource_task, + image_cache_task, + window_size); + let mut failsafe = ScriptMemoryFailsafe::new(&*script_task); + script_task.start(); + + // This must always be the very last operation performed before the task completes + failsafe.neuter(); + }, FailureMsg(failure_msg), const_chan, false); + } +} + impl ScriptTask { /// Creates a new script task. pub fn new(id: PipelineId, @@ -219,6 +256,8 @@ impl ScriptTask { layout_chan: LayoutChan, port: Receiver<ScriptMsg>, chan: ScriptChan, + control_chan: ScriptControlChan, + control_port: Receiver<ConstellationControlMsg>, constellation_chan: ConstellationChan, resource_task: ResourceTask, img_cache_task: ImageCacheTask, @@ -252,6 +291,8 @@ impl ScriptTask { port: port, chan: chan, + control_chan: control_chan, + control_port: control_port, constellation_chan: constellation_chan, compositor: compositor, @@ -294,36 +335,6 @@ impl ScriptTask { } } - pub fn create<C:ScriptListener + Send>( - id: PipelineId, - compositor: Box<C>, - layout_chan: LayoutChan, - port: Receiver<ScriptMsg>, - chan: ScriptChan, - constellation_chan: ConstellationChan, - failure_msg: Failure, - resource_task: ResourceTask, - image_cache_task: ImageCacheTask, - window_size: WindowSizeData) { - let ConstellationChan(const_chan) = constellation_chan.clone(); - spawn_named_with_send_on_failure("ScriptTask", proc() { - let script_task = ScriptTask::new(id, - compositor as Box<ScriptListener>, - layout_chan, - port, - chan, - constellation_chan, - resource_task, - image_cache_task, - window_size); - let mut failsafe = ScriptMemoryFailsafe::new(&*script_task); - script_task.start(); - - // This must always be the very last operation performed before the task completes - failsafe.neuter(); - }, FailureMsg(failure_msg), const_chan, false); - } - /// Handle incoming control messages. fn handle_msgs(&self) -> bool { let roots = RootCollection::new(); @@ -353,15 +364,36 @@ impl ScriptTask { self.handle_event(id, ResizeEvent(size)); } + enum MixedMessage { + FromConstellation(ConstellationControlMsg), + FromScript(ScriptMsg), + } + // Store new resizes, and gather all other events. let mut sequential = vec!(); // Receive at least one message so we don't spinloop. - let mut event = self.port.recv(); + let mut event = { + let sel = Select::new(); + let mut port1 = sel.handle(&self.port); + let mut port2 = sel.handle(&self.control_port); + unsafe { + port1.add(); + port2.add(); + } + let ret = sel.wait(); + if ret == port1.id() { + FromScript(self.port.recv()) + } else if ret == port2.id() { + FromConstellation(self.control_port.recv()) + } else { + fail!("unexpected select result") + } + }; loop { match event { - ResizeMsg(id, size) => { + FromConstellation(ResizeMsg(id, size)) => { let mut page = self.page.borrow_mut(); let page = page.find(id).expect("resize sent to nonexistent pipeline"); page.resize_event.deref().set(Some(size)); @@ -371,9 +403,12 @@ impl ScriptTask { } } - match self.port.try_recv() { - Err(_) => break, - Ok(ev) => event = ev, + match self.control_port.try_recv() { + Err(_) => match self.port.try_recv() { + Err(_) => break, + Ok(ev) => event = FromScript(ev), + }, + Ok(ev) => event = FromConstellation(ev), } } @@ -381,19 +416,20 @@ impl ScriptTask { for msg in sequential.move_iter() { match msg { // TODO(tkuehn) need to handle auxiliary layouts for iframes - AttachLayoutMsg(new_layout_info) => self.handle_new_layout(new_layout_info), - LoadMsg(id, url) => self.load(id, url), - TriggerLoadMsg(id, url) => self.trigger_load(id, url), - TriggerFragmentMsg(id, url) => self.trigger_fragment(id, url), - SendEventMsg(id, event) => self.handle_event(id, event), - FireTimerMsg(id, timer_id) => self.handle_fire_timer_msg(id, timer_id), - NavigateMsg(direction) => self.handle_navigate_msg(direction), - ReflowCompleteMsg(id, reflow_id) => self.handle_reflow_complete_msg(id, reflow_id), - ResizeInactiveMsg(id, new_size) => self.handle_resize_inactive_msg(id, new_size), - ExitPipelineMsg(id) => if self.handle_exit_pipeline_msg(id) { return false }, - ExitWindowMsg(id) => self.handle_exit_window_msg(id), - ResizeMsg(..) => fail!("should have handled ResizeMsg already"), - XHRProgressMsg(addr, progress) => XMLHttpRequest::handle_xhr_progress(addr, progress), + FromConstellation(AttachLayoutMsg(new_layout_info)) => + self.handle_new_layout(new_layout_info), + FromConstellation(LoadMsg(id, url)) => self.load(id, url), + FromScript(TriggerLoadMsg(id, url)) => self.trigger_load(id, url), + FromScript(TriggerFragmentMsg(id, url)) => self.trigger_fragment(id, url), + FromConstellation(SendEventMsg(id, event)) => self.handle_event(id, event), + FromScript(FireTimerMsg(id, timer_id)) => self.handle_fire_timer_msg(id, timer_id), + FromScript(NavigateMsg(direction)) => self.handle_navigate_msg(direction), + FromConstellation(ReflowCompleteMsg(id, reflow_id)) => self.handle_reflow_complete_msg(id, reflow_id), + FromConstellation(ResizeInactiveMsg(id, new_size)) => self.handle_resize_inactive_msg(id, new_size), + FromConstellation(ExitPipelineMsg(id)) => if self.handle_exit_pipeline_msg(id) { return false }, + FromScript(ExitWindowMsg(id)) => self.handle_exit_window_msg(id), + FromConstellation(ResizeMsg(..)) => fail!("should have handled ResizeMsg already"), + FromScript(XHRProgressMsg(addr, progress)) => XMLHttpRequest::handle_xhr_progress(addr, progress), } } @@ -415,7 +451,9 @@ impl ScriptTask { task's page tree. This is a bug."); let new_page = { let window_size = parent_page.window_size.deref().get(); - Page::new(new_pipeline_id, Some(subpage_id), layout_chan, window_size, + Page::new(new_pipeline_id, Some(subpage_id), + LayoutChan(layout_chan.as_ref::<Sender<layout_interface::Msg>>().unwrap().clone()), + window_size, parent_page.resource_task.deref().clone(), self.constellation_chan.clone(), self.js_context.borrow().get_ref().clone()) @@ -524,7 +562,7 @@ impl ScriptTask { *page.mut_url() = Some((loaded.clone(), false)); if needs_reflow { page.damage(ContentChangedDocumentDamage); - page.reflow(ReflowForDisplay, self.chan.clone(), self.compositor); + page.reflow(ReflowForDisplay, self.control_chan.clone(), self.compositor); } return; }, @@ -537,6 +575,7 @@ impl ScriptTask { let window = Window::new(cx.deref().ptr, page.clone(), self.chan.clone(), + self.control_chan.clone(), self.compositor.dup(), self.image_cache_task.clone()).root(); let document = Document::new(&*window, Some(url.clone()), HTMLDocument, None).root(); @@ -643,7 +682,7 @@ impl ScriptTask { /// This is the main entry point for receiving and dispatching DOM events. /// /// TODO: Actually perform DOM event dispatch. - fn handle_event(&self, pipeline_id: PipelineId, event: Event_) { + fn handle_event(&self, pipeline_id: PipelineId, event: CompositorEvent) { match event { ResizeEvent(new_size) => { debug!("script got resize event: {:?}", new_size); @@ -655,7 +694,7 @@ impl ScriptTask { let frame = page.frame(); if frame.is_some() { page.damage(ReflowDocumentDamage); - page.reflow(ReflowForDisplay, self.chan.clone(), self.compositor) + page.reflow(ReflowForDisplay, self.control_chan.clone(), self.compositor) } let mut fragment_node = page.fragment_node.get(); @@ -691,7 +730,7 @@ impl ScriptTask { let frame = page.frame(); if frame.is_some() { page.damage(MatchSelectorsDocumentDamage); - page.reflow(ReflowForDisplay, self.chan.clone(), self.compositor) + page.reflow(ReflowForDisplay, self.control_chan.clone(), self.compositor) } } @@ -789,7 +828,7 @@ impl ScriptTask { if target_compare { if mouse_over_targets.is_some() { page.damage(MatchSelectorsDocumentDamage); - page.reflow(ReflowForDisplay, self.chan.clone(), self.compositor); + page.reflow(ReflowForDisplay, self.control_chan.clone(), self.compositor); } *mouse_over_targets = Some(target_list); } diff --git a/src/components/script_traits/script_traits.rs b/src/components/script_traits/script_traits.rs new file mode 100644 index 00000000000..26837b91612 --- /dev/null +++ b/src/components/script_traits/script_traits.rs @@ -0,0 +1,98 @@ +/* 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/. */ + +#![crate_name = "script_traits"] +#![crate_type = "rlib"] + +#![comment = "The Servo Parallel Browser Project"] +#![license = "MPL"] + +extern crate geom; +extern crate servo_msg = "msg"; +extern crate servo_net = "net"; +extern crate url = "url_"; +extern crate std; +extern crate serialize; + +// This module contains traits in script used generically +// in the rest of Servo. +// The traits are here instead of in layout so +// that these modules won't have to depend on script. + +use servo_msg::constellation_msg::{ConstellationChan, PipelineId, Failure, WindowSizeData}; +use servo_msg::constellation_msg::SubpageId; +use servo_msg::compositor_msg::ScriptListener; +use servo_net::image_cache_task::ImageCacheTask; +use servo_net::resource_task::ResourceTask; +use std::any::Any; +use url::Url; + +use geom::point::Point2D; + +use serialize::{Encodable, Encoder}; + +pub struct NewLayoutInfo { + pub old_pipeline_id: PipelineId, + pub new_pipeline_id: PipelineId, + pub subpage_id: SubpageId, + pub layout_chan: Box<Any+Send>, // opaque reference to a LayoutChannel +} + +/// Messages sent from the constellation to the script task +pub enum ConstellationControlMsg { + /// Loads a new URL on the specified pipeline. + LoadMsg(PipelineId, Url), + /// Gives a channel and ID to a layout task, as well as the ID of that layout's parent + AttachLayoutMsg(NewLayoutInfo), + /// Window resized. Sends a DOM event eventually, but first we combine events. + ResizeMsg(PipelineId, WindowSizeData), + /// Notifies script that window has been resized but to not take immediate action. + ResizeInactiveMsg(PipelineId, WindowSizeData), + /// Notifies the script that a pipeline should be closed. + ExitPipelineMsg(PipelineId), + /// Sends a DOM event. + SendEventMsg(PipelineId, CompositorEvent), + /// Notifies script that reflow is finished. + ReflowCompleteMsg(PipelineId, uint), +} + +/// Events from the compositor that the script task needs to know about +pub enum CompositorEvent { + ResizeEvent(WindowSizeData), + ReflowEvent, + ClickEvent(uint, Point2D<f32>), + MouseDownEvent(uint, Point2D<f32>), + MouseUpEvent(uint, Point2D<f32>), + MouseMoveEvent(Point2D<f32>) +} + +/// An opaque wrapper around script<->layout channels to avoid leaking message types into +/// crates that don't need to know about them. +pub struct OpaqueScriptLayoutChannel(pub (Box<Any+Send>, Box<Any+Send>)); + +/// Encapsulates external communication with the script task. +#[deriving(Clone)] +pub struct ScriptControlChan(pub Sender<ConstellationControlMsg>); + +impl<S: Encoder<E>, E> Encodable<S, E> for ScriptControlChan { + fn encode(&self, _s: &mut S) -> Result<(), E> { + Ok(()) + } +} + +pub trait ScriptTaskFactory { + fn create<C: ScriptListener + Send>(_phantom: Option<&mut Self>, + id: PipelineId, + compositor: Box<C>, + layout_chan: &OpaqueScriptLayoutChannel, + control_chan: ScriptControlChan, + control_port: Receiver<ConstellationControlMsg>, + constellation_msg: ConstellationChan, + failure_msg: Failure, + resource_task: ResourceTask, + image_cache_task: ImageCacheTask, + window_size: WindowSizeData); + fn create_layout_channel(_phantom: Option<&mut Self>) -> OpaqueScriptLayoutChannel; + fn clone_layout_channel(_phantom: Option<&mut Self>, pair: &OpaqueScriptLayoutChannel) -> Box<Any+Send>; +} |