aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/script_task.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/script_task.rs')
-rw-r--r--components/script/script_task.rs243
1 files changed, 147 insertions, 96 deletions
diff --git a/components/script/script_task.rs b/components/script/script_task.rs
index b1f77f7a6f4..faf1f06d202 100644
--- a/components/script/script_task.rs
+++ b/components/script/script_task.rs
@@ -30,11 +30,10 @@ use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, RootCollection, trace_roots};
use dom::bindings::js::{RootCollectionPtr, Root, RootedReference};
use dom::bindings::refcounted::{LiveDOMReferences, Trusted, TrustedReference, trace_refcounted_objects};
-use dom::bindings::structuredclone::StructuredCloneData;
use dom::bindings::trace::{JSTraceable, trace_traceables, RootedVec};
use dom::bindings::utils::{WRAP_CALLBACKS, DOM_CALLBACKS};
-use dom::document::{Document, IsHTMLDocument, DocumentHelpers, DocumentProgressHandler,
- DocumentProgressTask, DocumentSource, MouseEventType};
+use dom::document::{Document, IsHTMLDocument, DocumentHelpers, DocumentProgressHandler};
+use dom::document::{DocumentProgressTask, DocumentSource, MouseEventType};
use dom::element::{Element, AttributeHandlers};
use dom::event::{EventHelpers, EventBubbles, EventCancelable};
use dom::htmliframeelement::HTMLIFrameElementHelpers;
@@ -63,7 +62,7 @@ use script_traits::{CompositorEvent, MouseButton};
use script_traits::ConstellationControlMsg;
use script_traits::{NewLayoutInfo, OpaqueScriptLayoutChannel};
use script_traits::{ScriptState, ScriptTaskFactory};
-use msg::compositor_msg::{LayerId, ScriptListener};
+use msg::compositor_msg::{LayerId, ScriptToCompositorMsg};
use msg::constellation_msg::{ConstellationChan, FocusType};
use msg::constellation_msg::{LoadData, PipelineId, SubpageId, MozBrowserEvent, WorkerId};
use msg::constellation_msg::{Failure, WindowSizeData, PipelineExitType};
@@ -179,45 +178,47 @@ pub trait MainThreadRunnable {
fn handler(self: Box<Self>, script_task: &ScriptTask);
}
-/// Messages used to control script event loops, such as ScriptTask and
-/// DedicatedWorkerGlobalScope.
-pub enum ScriptMsg {
- /// Begins a content-initiated load on the specified pipeline (only
- /// dispatched to ScriptTask).
- Navigate(PipelineId, LoadData),
+/// Common messages used to control the event loops in both the script and the worker
+pub enum CommonScriptMsg {
+ /// Requests that the script task measure its memory usage. The results are sent back via the
+ /// supplied channel.
+ CollectReports(ReportsChan),
/// Fires a JavaScript timeout
/// TimerSource must be FromWindow when dispatched to ScriptTask and
/// must be FromWorker when dispatched to a DedicatedGlobalWorkerScope
FireTimer(TimerSource, TimerId),
- /// Notifies the script that a window associated with a particular pipeline
- /// should be closed (only dispatched to ScriptTask).
- ExitWindow(PipelineId),
- /// Message sent through Worker.postMessage (only dispatched to
- /// DedicatedWorkerGlobalScope).
- DOMMessage(StructuredCloneData),
- /// Generic message that encapsulates event handling.
- RunnableMsg(Box<Runnable+Send>),
- /// Generic message for running tasks in the ScriptTask
- MainThreadRunnableMsg(Box<MainThreadRunnable+Send>),
/// A DOM object's last pinned reference was removed (dispatched to all tasks).
RefcountCleanup(TrustedReference),
+ /// Generic message that encapsulates event handling.
+ RunnableMsg(Box<Runnable + Send>),
+}
+
+/// Messages used to control the script event loop
+pub enum MainThreadScriptMsg {
+ /// Common variants associated with the script messages
+ Common(CommonScriptMsg),
/// Notify a document that all pending loads are complete.
DocumentLoadsComplete(PipelineId),
- /// Requests that the script task measure its memory usage. The results are sent back via the
- /// supplied channel.
- CollectReports(ReportsChan),
+ /// Notifies the script that a window associated with a particular pipeline
+ /// should be closed (only dispatched to ScriptTask).
+ ExitWindow(PipelineId),
+ /// Generic message for running tasks in the ScriptTask
+ MainThreadRunnableMsg(Box<MainThreadRunnable + Send>),
+ /// Begins a content-initiated load on the specified pipeline (only
+ /// dispatched to ScriptTask).
+ Navigate(PipelineId, LoadData),
}
/// A cloneable interface for communicating with an event loop.
pub trait ScriptChan {
/// Send a message to the associated event loop.
- fn send(&self, msg: ScriptMsg) -> Result<(), ()>;
+ fn send(&self, msg: CommonScriptMsg) -> Result<(), ()>;
/// Clone this handle.
- fn clone(&self) -> Box<ScriptChan+Send>;
+ fn clone(&self) -> Box<ScriptChan + Send>;
}
-impl OpaqueSender<ScriptMsg> for Box<ScriptChan+Send> {
- fn send(&self, msg: ScriptMsg) {
+impl OpaqueSender<CommonScriptMsg> for Box<ScriptChan + Send> {
+ fn send(&self, msg: CommonScriptMsg) {
ScriptChan::send(&**self, msg).unwrap();
}
}
@@ -226,42 +227,84 @@ impl OpaqueSender<ScriptMsg> for Box<ScriptChan+Send> {
/// APIs that need to abstract over multiple kinds of event loops (worker/main thread) with
/// different Receiver interfaces.
pub trait ScriptPort {
- fn recv(&self) -> ScriptMsg;
+ fn recv(&self) -> CommonScriptMsg;
}
-impl ScriptPort for Receiver<ScriptMsg> {
- fn recv(&self) -> ScriptMsg {
+impl ScriptPort for Receiver<CommonScriptMsg> {
+ fn recv(&self) -> CommonScriptMsg {
self.recv().unwrap()
}
}
-impl ScriptPort for Receiver<(TrustedWorkerAddress, ScriptMsg)> {
- fn recv(&self) -> ScriptMsg {
+impl ScriptPort for Receiver<MainThreadScriptMsg> {
+ fn recv(&self) -> CommonScriptMsg {
+ match self.recv().unwrap() {
+ MainThreadScriptMsg::Common(script_msg) => script_msg,
+ _ => panic!("unexpected main thread event message!")
+ }
+ }
+}
+
+impl ScriptPort for Receiver<(TrustedWorkerAddress, CommonScriptMsg)> {
+ fn recv(&self) -> CommonScriptMsg {
self.recv().unwrap().1
}
}
-/// Encapsulates internal communication within the script task.
+impl ScriptPort for Receiver<(TrustedWorkerAddress, MainThreadScriptMsg)> {
+ fn recv(&self) -> CommonScriptMsg {
+ match self.recv().unwrap().1 {
+ MainThreadScriptMsg::Common(script_msg) => script_msg,
+ _ => panic!("unexpected main thread event message!")
+ }
+ }
+}
+
+/// Encapsulates internal communication of shared messages within the script task.
#[derive(JSTraceable)]
-pub struct NonWorkerScriptChan(pub Sender<ScriptMsg>);
+pub struct SendableMainThreadScriptChan(pub Sender<CommonScriptMsg>);
-impl ScriptChan for NonWorkerScriptChan {
- fn send(&self, msg: ScriptMsg) -> Result<(), ()> {
- let NonWorkerScriptChan(ref chan) = *self;
+impl ScriptChan for SendableMainThreadScriptChan {
+ fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> {
+ let SendableMainThreadScriptChan(ref chan) = *self;
return chan.send(msg).map_err(|_| ());
}
- fn clone(&self) -> Box<ScriptChan+Send> {
- let NonWorkerScriptChan(ref chan) = *self;
- box NonWorkerScriptChan((*chan).clone())
+ fn clone(&self) -> Box<ScriptChan + Send> {
+ let SendableMainThreadScriptChan(ref chan) = *self;
+ box SendableMainThreadScriptChan((*chan).clone())
+ }
+}
+
+impl SendableMainThreadScriptChan {
+ /// Creates a new script chan.
+ pub fn new() -> (Receiver<CommonScriptMsg>, Box<SendableMainThreadScriptChan>) {
+ let (chan, port) = channel();
+ (port, box SendableMainThreadScriptChan(chan))
+ }
+}
+
+/// Encapsulates internal communication of main thread messages within the script task.
+#[derive(JSTraceable)]
+pub struct MainThreadScriptChan(pub Sender<MainThreadScriptMsg>);
+
+impl ScriptChan for MainThreadScriptChan {
+ fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> {
+ let MainThreadScriptChan(ref chan) = *self;
+ return chan.send(MainThreadScriptMsg::Common(msg)).map_err(|_| ());
+ }
+
+ fn clone(&self) -> Box<ScriptChan + Send> {
+ let MainThreadScriptChan(ref chan) = *self;
+ box MainThreadScriptChan((*chan).clone())
}
}
-impl NonWorkerScriptChan {
+impl MainThreadScriptChan {
/// Creates a new script chan.
- pub fn new() -> (Receiver<ScriptMsg>, Box<NonWorkerScriptChan>) {
+ pub fn new() -> (Receiver<MainThreadScriptMsg>, Box<MainThreadScriptChan>) {
let (chan, port) = channel();
- (port, box NonWorkerScriptChan(chan))
+ (port, box MainThreadScriptChan(chan))
}
}
@@ -302,10 +345,10 @@ pub struct ScriptTask {
storage_task: StorageTask,
/// The port on which the script task receives messages (load URL, exit, etc.)
- port: Receiver<ScriptMsg>,
+ port: Receiver<MainThreadScriptMsg>,
/// A channel to hand out to script task-based entities that need to be able to enqueue
/// events in the event queue.
- chan: NonWorkerScriptChan,
+ chan: MainThreadScriptChan,
/// A channel to hand out to tasks that need to respond to a message from the script task.
control_chan: Sender<ConstellationControlMsg>,
@@ -318,7 +361,7 @@ pub struct ScriptTask {
constellation_chan: ConstellationChan,
/// A handle to the compositor for communicating ready state messages.
- compositor: DOMRefCell<ScriptListener>,
+ compositor: DOMRefCell<IpcSender<ScriptToCompositorMsg>>,
/// The port on which we receive messages from the image cache
image_cache_port: Receiver<ImageCacheResult>,
@@ -393,14 +436,14 @@ impl ScriptTaskFactory for ScriptTask {
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 clone_layout_channel(_phantom: Option<&mut ScriptTask>, pair: &OpaqueScriptLayoutChannel) -> Box<Any + Send> {
+ box pair.sender() as Box<Any + Send>
}
fn create(_phantom: Option<&mut ScriptTask>,
id: PipelineId,
parent_info: Option<(PipelineId, SubpageId)>,
- compositor: ScriptListener,
+ compositor: IpcSender<ScriptToCompositorMsg>,
layout_chan: &OpaqueScriptLayoutChannel,
control_chan: Sender<ConstellationControlMsg>,
control_port: Receiver<ConstellationControlMsg>,
@@ -419,7 +462,7 @@ impl ScriptTaskFactory for ScriptTask {
spawn_named_with_send_on_failure(format!("ScriptTask {:?}", id), task_state::SCRIPT, move || {
let roots = RootCollection::new();
let _stack_roots_tls = StackRootTLS::new(&roots);
- let chan = NonWorkerScriptChan(script_chan);
+ let chan = MainThreadScriptChan(script_chan);
let channel_for_reporter = chan.clone();
let script_task = ScriptTask::new(compositor,
script_port,
@@ -446,7 +489,7 @@ impl ScriptTaskFactory for ScriptTask {
let reporter_name = format!("script-reporter-{}", id.0);
mem_profiler_chan.run_with_memory_reporting(|| {
script_task.start();
- }, reporter_name, channel_for_reporter, ScriptMsg::CollectReports);
+ }, reporter_name, channel_for_reporter, CommonScriptMsg::CollectReports);
// This must always be the very last operation performed before the task completes
failsafe.neuter();
@@ -526,19 +569,19 @@ impl ScriptTask {
});
}
- pub fn process_event(msg: ScriptMsg) {
+ pub fn process_event(msg: CommonScriptMsg) {
SCRIPT_TASK_ROOT.with(|root| {
if let Some(script_task) = *root.borrow() {
let script_task = unsafe { &*script_task };
- script_task.handle_msg_from_script(msg);
+ script_task.handle_msg_from_script(MainThreadScriptMsg::Common(msg));
}
});
}
/// Creates a new script task.
- pub fn new(compositor: ScriptListener,
- port: Receiver<ScriptMsg>,
- chan: NonWorkerScriptChan,
+ pub fn new(compositor: IpcSender<ScriptToCompositorMsg>,
+ port: Receiver<MainThreadScriptMsg>,
+ chan: MainThreadScriptChan,
control_chan: Sender<ConstellationControlMsg>,
control_port: Receiver<ConstellationControlMsg>,
constellation_chan: ConstellationChan,
@@ -672,7 +715,7 @@ impl ScriptTask {
enum MixedMessage {
FromConstellation(ConstellationControlMsg),
- FromScript(ScriptMsg),
+ FromScript(MainThreadScriptMsg),
FromDevtools(DevtoolScriptControlMsg),
FromImageCache(ImageCacheResult),
}
@@ -855,27 +898,27 @@ impl ScriptTask {
}
}
- fn handle_msg_from_script(&self, msg: ScriptMsg) {
+ fn handle_msg_from_script(&self, msg: MainThreadScriptMsg) {
match msg {
- ScriptMsg::Navigate(id, load_data) =>
+ MainThreadScriptMsg::Navigate(id, load_data) =>
self.handle_navigate(id, None, load_data),
- ScriptMsg::FireTimer(TimerSource::FromWindow(id), timer_id) =>
+ MainThreadScriptMsg::ExitWindow(id) =>
+ self.handle_exit_window_msg(id),
+ MainThreadScriptMsg::MainThreadRunnableMsg(runnable) =>
+ runnable.handler(self),
+ MainThreadScriptMsg::DocumentLoadsComplete(id) =>
+ self.handle_loads_complete(id),
+ MainThreadScriptMsg::Common(
+ CommonScriptMsg::FireTimer(TimerSource::FromWindow(id), timer_id)) =>
self.handle_fire_timer_msg(id, timer_id),
- ScriptMsg::FireTimer(TimerSource::FromWorker, _) =>
+ MainThreadScriptMsg::Common(
+ CommonScriptMsg::FireTimer(TimerSource::FromWorker, _)) =>
panic!("Worker timeouts must not be sent to script task"),
- ScriptMsg::ExitWindow(id) =>
- self.handle_exit_window_msg(id),
- ScriptMsg::DOMMessage(..) =>
- panic!("unexpected message"),
- ScriptMsg::RunnableMsg(runnable) =>
+ MainThreadScriptMsg::Common(CommonScriptMsg::RunnableMsg(runnable)) =>
runnable.handler(),
- ScriptMsg::MainThreadRunnableMsg(runnable) =>
- runnable.handler(self),
- ScriptMsg::RefcountCleanup(addr) =>
+ MainThreadScriptMsg::Common(CommonScriptMsg::RefcountCleanup(addr)) =>
LiveDOMReferences::cleanup(addr),
- ScriptMsg::DocumentLoadsComplete(id) =>
- self.handle_loads_complete(id),
- ScriptMsg::CollectReports(reports_chan) =>
+ MainThreadScriptMsg::Common(CommonScriptMsg::CollectReports(reports_chan)) =>
self.collect_reports(reports_chan),
}
}
@@ -1085,7 +1128,7 @@ impl ScriptTask {
// https://html.spec.whatwg.org/multipage/#the-end step 7
let addr: Trusted<Document> = Trusted::new(self.get_cx(), doc, self.chan.clone());
let handler = box DocumentProgressHandler::new(addr.clone(), DocumentProgressTask::Load);
- self.chan.send(ScriptMsg::RunnableMsg(handler)).unwrap();
+ self.chan.send(CommonScriptMsg::RunnableMsg(handler)).unwrap();
let ConstellationChan(ref chan) = self.constellation_chan;
chan.send(ConstellationMsg::LoadComplete(pipeline)).unwrap();
@@ -1145,23 +1188,26 @@ impl ScriptTask {
let mut urls = vec![];
let mut dom_tree_size = 0;
let mut reports = vec![];
- for it_page in self.root_page().iter() {
- let current_url = it_page.document().url().serialize();
- urls.push(current_url.clone());
- for child in NodeCast::from_ref(&*it_page.document()).traverse_preorder() {
- let target = EventTargetCast::from_ref(&*child);
+ if let Some(root_page) = self.page.borrow().as_ref() {
+ for it_page in root_page.iter() {
+ let current_url = it_page.document().url().serialize();
+ urls.push(current_url.clone());
+
+ for child in NodeCast::from_ref(&*it_page.document()).traverse_preorder() {
+ let target = EventTargetCast::from_ref(&*child);
+ dom_tree_size += heap_size_of_eventtarget(target);
+ }
+ let window = it_page.window();
+ let target = EventTargetCast::from_ref(&*window);
dom_tree_size += heap_size_of_eventtarget(target);
+
+ reports.push(Report {
+ path: path![format!("url({})", current_url), "dom-tree"],
+ kind: ReportKind::ExplicitJemallocHeapSize,
+ size: dom_tree_size,
+ })
}
- let window = it_page.window();
- let target = EventTargetCast::from_ref(&*window);
- dom_tree_size += heap_size_of_eventtarget(target);
-
- reports.push(Report {
- path: path![format!("url({})", current_url), "dom-tree"],
- kind: ReportKind::ExplicitJemallocHeapSize,
- size: dom_tree_size,
- })
}
let path_seg = format!("url({})", urls.join(", "));
reports.extend(ScriptTask::get_reports(self.get_cx(), path_seg));
@@ -1286,7 +1332,7 @@ impl ScriptTask {
// TODO(tkuehn): currently there is only one window,
// so this can afford to be naive and just shut down the
// compositor. In the future it'll need to be smarter.
- self.compositor.borrow_mut().close();
+ self.compositor.borrow_mut().send(ScriptToCompositorMsg::Exit).unwrap();
}
/// We have received notification that the response associated with a load has completed.
@@ -1455,14 +1501,15 @@ impl ScriptTask {
PageToRemove::Child(incomplete.pipeline_id)
};
let mut page_remover = AutoPageRemover::new(self, page_to_remove);
+ let MainThreadScriptChan(ref sender) = self.chan;
// Create the window and document objects.
let window = Window::new(self.js_runtime.clone(),
page.clone(),
- self.chan.clone(),
+ MainThreadScriptChan(sender.clone()),
self.image_cache_channel.clone(),
self.control_chan.clone(),
- self.compositor.borrow_mut().dup(),
+ self.compositor.borrow_mut().clone(),
self.image_cache_task.clone(),
self.resource_task.clone(),
self.storage_task.clone(),
@@ -1485,9 +1532,12 @@ impl ScriptTask {
_ => None
};
- let notifier_data = NotifierData {
- script_chan: self.chan.clone(),
- pipeline: page.pipeline(),
+ let notifier_data = {
+ let MainThreadScriptChan(ref sender) = self.chan;
+ NotifierData {
+ script_chan: sender.clone(),
+ pipeline: page.pipeline(),
+ }
};
let loader = DocumentLoader::new_with_task(self.resource_task.clone(),
Some(notifier_data),
@@ -1554,7 +1604,8 @@ impl ScriptTask {
// Really what needs to happen is that this needs to go through layout to ask which
// layer the element belongs to, and have it send the scroll message to the
// compositor.
- self.compositor.borrow_mut().scroll_fragment_point(pipeline_id, LayerId::null(), point);
+ self.compositor.borrow_mut().send(ScriptToCompositorMsg::ScrollFragmentPoint(
+ pipeline_id, LayerId::null(), point)).unwrap();
}
/// Reflows non-incrementally, rebuilding the entire layout tree in the process.
@@ -1652,7 +1703,7 @@ impl ScriptTask {
let page = get_page(&self.root_page(), pipeline_id);
let document = page.document();
document.r().dispatch_key_event(
- key, state, modifiers, &mut *self.compositor.borrow_mut());
+ key, state, modifiers, &mut self.compositor.borrow_mut());
}
}
}
@@ -1822,7 +1873,7 @@ impl ScriptTask {
// https://html.spec.whatwg.org/multipage/#the-end step 4
let addr: Trusted<Document> = Trusted::new(self.get_cx(), document.r(), self.chan.clone());
let handler = box DocumentProgressHandler::new(addr, DocumentProgressTask::DOMContentLoaded);
- self.chan.send(ScriptMsg::RunnableMsg(handler)).unwrap();
+ self.chan.send(CommonScriptMsg::RunnableMsg(handler)).unwrap();
window.r().set_fragment_name(final_url.fragment.clone());