diff options
author | Ravi Shankar <wafflespeanut@gmail.com> | 2015-08-01 21:25:49 +0530 |
---|---|---|
committer | Ravi Shankar <wafflespeanut@gmail.com> | 2015-08-01 21:25:49 +0530 |
commit | 79b65402d70e54af10e11bc859db50fb0d5744c5 (patch) | |
tree | 29bdcfc951341fd8820f2cf7555281518bbf0343 | |
parent | 4de6e699b2ee095177360ae1812d9f47829adcc3 (diff) | |
download | servo-79b65402d70e54af10e11bc859db50fb0d5744c5.tar.gz servo-79b65402d70e54af10e11bc859db50fb0d5744c5.zip |
Persuading devtools to communicate with the workers; r=jdm
-rw-r--r-- | components/script/devtools.rs | 24 | ||||
-rw-r--r-- | components/script/dom/bindings/global.rs | 22 | ||||
-rw-r--r-- | components/script/dom/dedicatedworkerglobalscope.rs | 84 | ||||
-rw-r--r-- | components/script/dom/worker.rs | 33 | ||||
-rw-r--r-- | components/script/dom/workerglobalscope.rs | 35 | ||||
-rw-r--r-- | components/script/lib.rs | 1 | ||||
-rw-r--r-- | components/script/script_task.rs | 18 |
7 files changed, 161 insertions, 56 deletions
diff --git a/components/script/devtools.rs b/components/script/devtools.rs index b7edc7616a3..8c40af12c73 100644 --- a/components/script/devtools.rs +++ b/components/script/devtools.rs @@ -12,6 +12,7 @@ use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast}; use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; use dom::bindings::codegen::Bindings::DOMRectBinding::{DOMRectMethods}; use dom::bindings::codegen::Bindings::ElementBinding::{ElementMethods}; +use dom::bindings::global::GlobalRef; use dom::node::{Node, NodeHelpers}; use dom::window::{WindowHelpers, ScriptHelpers}; use dom::document::DocumentHelpers; @@ -24,18 +25,10 @@ use js::jsval::UndefinedValue; use std::rc::Rc; - -pub fn handle_evaluate_js( - page: &Rc<Page>, - pipeline: PipelineId, - eval: String, - reply: IpcSender<EvaluateJSReply> - ) { - let page = get_page(&*page, pipeline); - let window = page.window(); - let cx = window.r().get_cx(); +pub fn handle_evaluate_js(global: &GlobalRef, eval: String, reply: IpcSender<EvaluateJSReply>) { + let cx = global.get_cx(); let mut rval = RootedValue::new(cx, UndefinedValue()); - window.r().evaluate_js_on_global_with_result(&eval, rval.handle_mut()); + global.evaluate_js_on_global_with_result(&eval, rval.handle_mut()); reply.send(if rval.ptr.is_undefined() { EvaluateJSReply::VoidValue @@ -43,8 +36,7 @@ pub fn handle_evaluate_js( EvaluateJSReply::BooleanValue(rval.ptr.to_boolean()) } else if rval.ptr.is_double() || rval.ptr.is_int32() { EvaluateJSReply::NumberValue( - FromJSValConvertible::from_jsval(cx, rval.handle(), ()).unwrap() - ) + FromJSValConvertible::from_jsval(cx, rval.handle(), ()).unwrap()) } else if rval.ptr.is_string() { //FIXME: use jsstring_to_str when jsval grows to_jsstring EvaluateJSReply::StringValue( @@ -165,10 +157,8 @@ pub fn handle_modify_attribute(page: &Rc<Page>, } } -pub fn handle_wants_live_notifications(page: &Rc<Page>, pipeline_id: PipelineId, send_notifications: bool) { - let page = get_page(&*page, pipeline_id); - let window = page.window(); - window.r().set_devtools_wants_updates(send_notifications); +pub fn handle_wants_live_notifications(global: &GlobalRef, send_notifications: bool) { + global.set_devtools_wants_updates(send_notifications); } pub fn handle_set_timeline_markers(page: &Rc<Page>, diff --git a/components/script/dom/bindings/global.rs b/components/script/dom/bindings/global.rs index cfdd3df4af5..91c4a86625b 100644 --- a/components/script/dom/bindings/global.rs +++ b/components/script/dom/bindings/global.rs @@ -13,7 +13,7 @@ use dom::bindings::js::{JS, Root}; use dom::bindings::utils::{Reflectable, Reflector}; use dom::document::DocumentHelpers; use dom::workerglobalscope::{WorkerGlobalScope, WorkerGlobalScopeHelpers}; -use dom::window::{self, WindowHelpers}; +use dom::window::{self, WindowHelpers, ScriptHelpers}; use devtools_traits::ScriptToDevtoolsControlMsg; use script_task::{ScriptChan, ScriptPort, ScriptMsg, ScriptTask}; @@ -24,8 +24,7 @@ use profile_traits::mem; use ipc_channel::ipc::IpcSender; use js::{JSCLASS_IS_GLOBAL, JSCLASS_IS_DOMJSCLASS}; use js::jsapi::{GetGlobalForObjectCrossCompartment}; -use js::jsapi::{JSContext, JSObject}; -use js::jsapi::{JS_GetClass}; +use js::jsapi::{JSContext, JSObject, JS_GetClass, MutableHandleValue}; use url::Url; /// A freely-copyable reference to a rooted global object. @@ -165,6 +164,23 @@ impl<'a> GlobalRef<'a> { GlobalRef::Worker(ref worker) => worker.process_event(msg), } } + + /// Evaluate the JS messages on the `RootedValue` of this global + pub fn evaluate_js_on_global_with_result(&self, code: &str, rval: MutableHandleValue) { + match *self { + GlobalRef::Window(window) => window.evaluate_js_on_global_with_result(code, rval), + GlobalRef::Worker(worker) => worker.evaluate_js_on_global_with_result(code, rval), + } + } + + /// Set the `bool` value to indicate whether developer tools has requested + /// updates from the global + pub fn set_devtools_wants_updates(&self, send_updates: bool) { + match *self { + GlobalRef::Window(window) => window.set_devtools_wants_updates(send_updates), + GlobalRef::Worker(worker) => worker.set_devtools_wants_updates(send_updates), + } + } } impl<'a> Reflectable for GlobalRef<'a> { diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs index 5c44f5aff6a..5fe286bc640 100644 --- a/components/script/dom/dedicatedworkerglobalscope.rs +++ b/components/script/dom/dedicatedworkerglobalscope.rs @@ -2,6 +2,7 @@ * 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 devtools; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding; use dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding::DedicatedWorkerGlobalScopeMethods; @@ -26,7 +27,7 @@ use script_task::StackRootTLS; use msg::constellation_msg::{ConstellationChan, PipelineId}; -use devtools_traits::ScriptToDevtoolsControlMsg; +use devtools_traits::{ScriptToDevtoolsControlMsg, DevtoolScriptControlMsg}; use net_traits::{load_whole_resource, ResourceTask}; use profile_traits::mem::{self, Reporter, ReporterRequest}; @@ -34,7 +35,7 @@ use util::task::spawn_named; use util::task_state; use util::task_state::{SCRIPT, IN_WORKER}; -use ipc_channel::ipc::{self, IpcSender}; +use ipc_channel::ipc::{self, IpcSender, IpcReceiver}; use ipc_channel::router::ROUTER; use js::jsapi::{JSContext, RootedValue, HandleValue}; use js::jsapi::{JSAutoRequest, JSAutoCompartment}; @@ -45,7 +46,7 @@ use url::Url; use rand::random; use std::mem::replace; use std::rc::Rc; -use std::sync::mpsc::{Sender, Receiver, channel}; +use std::sync::mpsc::{Sender, Receiver, channel, Select}; /// A ScriptChan that can be cloned freely and will silently send a TrustedWorkerAddress with /// every message. While this SendableWorkerScriptChan is alive, the associated Worker object @@ -110,6 +111,8 @@ impl DedicatedWorkerGlobalScope { id: PipelineId, mem_profiler_chan: mem::ProfilerChan, devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, + devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>, + devtools_port: Receiver<DevtoolScriptControlMsg>, runtime: Rc<Runtime>, resource_task: ResourceTask, constellation_chan: ConstellationChan, @@ -119,8 +122,8 @@ impl DedicatedWorkerGlobalScope { -> DedicatedWorkerGlobalScope { DedicatedWorkerGlobalScope { workerglobalscope: WorkerGlobalScope::new_inherited( - WorkerGlobalScopeTypeId::DedicatedGlobalScope, worker_url, - runtime, resource_task, mem_profiler_chan, devtools_chan, constellation_chan), + WorkerGlobalScopeTypeId::DedicatedGlobalScope, worker_url, runtime, resource_task, + mem_profiler_chan, devtools_chan, devtools_sender, devtools_port, constellation_chan), id: id, receiver: receiver, own_sender: own_sender, @@ -133,6 +136,8 @@ impl DedicatedWorkerGlobalScope { id: PipelineId, mem_profiler_chan: mem::ProfilerChan, devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, + devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>, + devtools_port: Receiver<DevtoolScriptControlMsg>, runtime: Rc<Runtime>, resource_task: ResourceTask, constellation_chan: ConstellationChan, @@ -141,17 +146,20 @@ impl DedicatedWorkerGlobalScope { receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>) -> Root<DedicatedWorkerGlobalScope> { let scope = box DedicatedWorkerGlobalScope::new_inherited( - worker_url, id, mem_profiler_chan, devtools_chan, runtime.clone(), resource_task, - constellation_chan, parent_sender, own_sender, receiver); + worker_url, id, mem_profiler_chan, devtools_chan, devtools_sender, devtools_port, + runtime.clone(), resource_task, constellation_chan, parent_sender, own_sender, receiver); DedicatedWorkerGlobalScopeBinding::Wrap(runtime.cx(), scope) } } impl DedicatedWorkerGlobalScope { + #[allow(unsafe_code)] pub fn run_worker_scope(worker_url: Url, id: PipelineId, mem_profiler_chan: mem::ProfilerChan, devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, + devtools_ipc_chan: Option<IpcSender<DevtoolScriptControlMsg>>, + devtools_ipc_port: IpcReceiver<DevtoolScriptControlMsg>, worker: TrustedWorkerAddress, resource_task: ResourceTask, constellation_chan: ConstellationChan, @@ -180,11 +188,16 @@ impl DedicatedWorkerGlobalScope { let runtime = Rc::new(ScriptTask::new_rt_and_cx()); let serialized_url = url.serialize(); let parent_sender_for_reporter = parent_sender.clone(); + + let (devtools_mpsc_chan, devtools_mpsc_port) = channel(); + ROUTER.route_ipc_receiver_to_mpsc_sender(devtools_ipc_port, devtools_mpsc_chan); + let global = DedicatedWorkerGlobalScope::new( - url, id, mem_profiler_chan.clone(), devtools_chan, runtime.clone(), - resource_task, constellation_chan, parent_sender, own_sender, receiver); + url, id, mem_profiler_chan.clone(), devtools_chan, devtools_ipc_chan, devtools_mpsc_port, + runtime.clone(), resource_task, constellation_chan, parent_sender, own_sender, receiver); // FIXME(njn): workers currently don't have a unique ID suitable for using in reporter // registration (#6631), so we instead use a random number and cross our fingers. + let scope = WorkerGlobalScopeCast::from_ref(global.r()); let reporter_name = format!("worker-reporter-{}", random::<u64>()); { @@ -216,13 +229,58 @@ impl DedicatedWorkerGlobalScope { Reporter(reporter_sender))); } + enum MixedMessage { + FromWorker((TrustedWorkerAddress, ScriptMsg)), + FromDevtools(DevtoolScriptControlMsg), + } + loop { - match global.r().receiver.recv() { - Ok((linked_worker, msg)) => { + let worker_port = &global.r().receiver; + let devtools_port = scope.devtools_port(); + + let event = { + let sel = Select::new(); + let mut worker_handle = sel.handle(worker_port); + let mut devtools_handle = sel.handle(devtools_port); + unsafe { + worker_handle.add(); + if scope.devtools_sender().is_some() { + devtools_handle.add(); + } + } + let ret = sel.wait(); + if ret == worker_handle.id() { + match worker_port.recv() { + Ok(stuff) => MixedMessage::FromWorker(stuff), + Err(_) => break, + } + } else if ret == devtools_handle.id() { + match devtools_port.recv() { + Ok(stuff) => MixedMessage::FromDevtools(stuff), + Err(_) => break, + } + } else { + panic!("unexpected select result!") + } + }; + + match event { + MixedMessage::FromDevtools(msg) => { + let global_ref = GlobalRef::Worker(scope); + match msg { + DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) => + devtools::handle_evaluate_js(&global_ref, string, sender), + DevtoolScriptControlMsg::GetCachedMessages(pipe_id, message_types, sender) => + devtools::handle_get_cached_messages(pipe_id, message_types, sender), + DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, bool_val) => + devtools::handle_wants_live_notifications(&global_ref, bool_val), + _ => debug!("got an unusable devtools control message inside the worker!"), + } + }, + MixedMessage::FromWorker((linked_worker, msg)) => { let _ar = AutoWorkerReset::new(global.r(), linked_worker); global.r().handle_event(msg); - } - Err(_) => break, + }, } } diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs index e536200fb43..2ef505308a3 100644 --- a/components/script/dom/worker.rs +++ b/components/script/dom/worker.rs @@ -77,23 +77,28 @@ impl Worker { let worker = Worker::new(global, sender.clone()); let worker_ref = Trusted::new(global.get_cx(), worker.r(), global.script_chan()); - if let Some(ref chan) = global.devtools_chan() { - let pipeline_id = global.pipeline(); - let (devtools_sender, _) = ipc::channel().unwrap(); - let title = format!("Worker for {}", worker_url); - let page_info = DevtoolsPageInfo { - title: title, - url: worker_url.clone(), - }; - let worker_id = global.get_next_worker_id(); - chan.send(ScriptToDevtoolsControlMsg::NewGlobal((pipeline_id, Some(worker_id)), - devtools_sender.clone(), - page_info)).unwrap(); - } + let (devtools_sender, devtools_receiver) = ipc::channel().unwrap(); + let optional_sender = match global.devtools_chan() { + Some(ref chan) => { + let pipeline_id = global.pipeline(); + let title = format!("Worker for {}", worker_url); + let page_info = DevtoolsPageInfo { + title: title, + url: worker_url.clone(), + }; + let worker_id = global.get_next_worker_id(); + chan.send(ScriptToDevtoolsControlMsg::NewGlobal((pipeline_id, Some(worker_id)), + devtools_sender.clone(), + page_info)).unwrap(); + Some(devtools_sender) + }, + None => None, + }; DedicatedWorkerGlobalScope::run_worker_scope( worker_url, global.pipeline(), global.mem_profiler_chan(), global.devtools_chan(), - worker_ref, resource_task, constellation_chan, global.script_chan(), sender, receiver); + optional_sender, devtools_receiver, worker_ref, resource_task, + constellation_chan, global.script_chan(), sender, receiver); Ok(worker) } diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index ebdb35a0fde..a99bcab8ebd 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -20,7 +20,7 @@ use dom::window::{base64_atob, base64_btoa}; use script_task::{ScriptChan, TimerSource, ScriptPort, ScriptMsg}; use timers::{IsInterval, TimerId, TimerManager, TimerCallback}; -use devtools_traits::ScriptToDevtoolsControlMsg; +use devtools_traits::{ScriptToDevtoolsControlMsg, DevtoolScriptControlMsg}; use msg::constellation_msg::{ConstellationChan, PipelineId, WorkerId}; use profile_traits::mem; @@ -35,6 +35,7 @@ use url::{Url, UrlParser}; use std::default::Default; use std::cell::Cell; use std::rc::Rc; +use std::sync::mpsc::Receiver; #[derive(JSTraceable, Copy, Clone, PartialEq)] pub enum WorkerGlobalScopeTypeId { @@ -56,6 +57,19 @@ pub struct WorkerGlobalScope { timers: TimerManager, mem_profiler_chan: mem::ProfilerChan, devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, + + /// Optional `IpcSender` for sending the `DevtoolScriptControlMsg` + /// to the server from within the worker + devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>, + + /// This `Receiver` will be ignored later if the corresponding + /// `IpcSender` doesn't exist + devtools_receiver: Receiver<DevtoolScriptControlMsg>, + + /// A flag to indicate whether the developer tools has requested live updates + /// from the worker + devtools_wants_updates: Cell<bool>, + constellation_chan: ConstellationChan, } @@ -66,6 +80,8 @@ impl WorkerGlobalScope { resource_task: ResourceTask, mem_profiler_chan: mem::ProfilerChan, devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, + devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>, + devtools_receiver: Receiver<DevtoolScriptControlMsg>, constellation_chan: ConstellationChan) -> WorkerGlobalScope { WorkerGlobalScope { @@ -81,6 +97,9 @@ impl WorkerGlobalScope { timers: TimerManager::new(), mem_profiler_chan: mem_profiler_chan, devtools_chan: devtools_chan, + devtools_sender: devtools_sender, + devtools_receiver: devtools_receiver, + devtools_wants_updates: Cell::new(false), constellation_chan: constellation_chan, } } @@ -93,6 +112,14 @@ impl WorkerGlobalScope { self.devtools_chan.clone() } + pub fn devtools_sender(&self) -> Option<IpcSender<DevtoolScriptControlMsg>> { + self.devtools_sender.clone() + } + + pub fn devtools_port(&self) -> &Receiver<DevtoolScriptControlMsg> { + &self.devtools_receiver + } + pub fn constellation_chan(&self) -> ConstellationChan { self.constellation_chan.clone() } @@ -251,6 +278,7 @@ pub trait WorkerGlobalScopeHelpers { fn new_script_pair(self) -> (Box<ScriptChan+Send>, Box<ScriptPort+Send>); fn process_event(self, msg: ScriptMsg); fn get_cx(self) -> *mut JSContext; + fn set_devtools_wants_updates(self, value: bool); } impl<'a> WorkerGlobalScopeHelpers for &'a WorkerGlobalScope { @@ -297,5 +325,8 @@ impl<'a> WorkerGlobalScopeHelpers for &'a WorkerGlobalScope { fn get_cx(self) -> *mut JSContext { self.runtime.cx() } -} + fn set_devtools_wants_updates(self, value: bool) { + self.devtools_wants_updates.set(value); + } +} diff --git a/components/script/lib.rs b/components/script/lib.rs index 640aad8e6e1..007d5651f75 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -120,4 +120,3 @@ pub fn init() { perform_platform_specific_initialization(); } - diff --git a/components/script/script_task.rs b/components/script/script_task.rs index bf23bca2db6..279ff364bda 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -26,6 +26,7 @@ use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, Documen use dom::bindings::codegen::InheritTypes::{ElementCast, EventTargetCast, NodeCast, EventCast}; use dom::bindings::conversions::FromJSValConvertible; use dom::bindings::conversions::StringificationBehavior; +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}; @@ -136,7 +137,7 @@ struct InProgressLoad { window_size: Option<WindowSizeData>, /// Channel to the layout task associated with this pipeline. layout_chan: LayoutChan, - /// The current viewport clipping rectangle applying to this pipelie, if any. + /// The current viewport clipping rectangle applying to this pipeline, if any. clip_rect: Option<Rect<f32>>, /// The requested URL of the load. url: Url, @@ -843,8 +844,11 @@ impl ScriptTask { fn handle_msg_from_devtools(&self, msg: DevtoolScriptControlMsg) { let page = self.root_page(); match msg { - DevtoolScriptControlMsg::EvaluateJS(id, s, reply) => - devtools::handle_evaluate_js(&page, id, s, reply), + DevtoolScriptControlMsg::EvaluateJS(id, s, reply) => { + let window = get_page(&page, id).window(); + let global_ref = GlobalRef::Window(window.r()); + devtools::handle_evaluate_js(&global_ref, s, reply) + }, DevtoolScriptControlMsg::GetRootNode(id, reply) => devtools::handle_get_root_node(&page, id, reply), DevtoolScriptControlMsg::GetDocumentElement(id, reply) => @@ -857,8 +861,11 @@ impl ScriptTask { devtools::handle_get_cached_messages(pipeline_id, message_types, reply), DevtoolScriptControlMsg::ModifyAttribute(id, node_id, modifications) => devtools::handle_modify_attribute(&page, id, node_id, modifications), - DevtoolScriptControlMsg::WantsLiveNotifications(pipeline_id, to_send) => - devtools::handle_wants_live_notifications(&page, pipeline_id, to_send), + DevtoolScriptControlMsg::WantsLiveNotifications(id, to_send) => { + let window = get_page(&page, id).window(); + let global_ref = GlobalRef::Window(window.r()); + devtools::handle_wants_live_notifications(&global_ref, to_send) + }, DevtoolScriptControlMsg::SetTimelineMarkers(_pipeline_id, marker_types, reply) => devtools::handle_set_timeline_markers(&page, self, marker_types, reply), DevtoolScriptControlMsg::DropTimelineMarkers(_pipeline_id, marker_types) => @@ -1828,7 +1835,6 @@ fn shut_down_layout(page_tree: &Rc<Page>, exit_type: PipelineExitType) { } } - pub fn get_page(page: &Rc<Page>, pipeline_id: PipelineId) -> Rc<Page> { page.find(pipeline_id).expect("ScriptTask: received an event \ message for a layout channel that is not associated with this script task.\ |