diff options
-rw-r--r-- | components/devtools/actors/browsing_context.rs | 152 | ||||
-rw-r--r-- | components/devtools/actors/console.rs | 90 | ||||
-rw-r--r-- | components/devtools/actors/inspector.rs | 16 | ||||
-rw-r--r-- | components/devtools/lib.rs | 221 | ||||
-rw-r--r-- | components/devtools_traits/lib.rs | 17 | ||||
-rw-r--r-- | components/script/dom/window.rs | 12 | ||||
-rw-r--r-- | components/script/dom/worker.rs | 2 | ||||
-rw-r--r-- | components/script/script_thread.rs | 20 | ||||
-rw-r--r-- | components/script/serviceworker_manager.rs | 6 |
9 files changed, 350 insertions, 186 deletions
diff --git a/components/devtools/actors/browsing_context.rs b/components/devtools/actors/browsing_context.rs index bdc468f9f84..01c153a0d1b 100644 --- a/components/devtools/actors/browsing_context.rs +++ b/components/devtools/actors/browsing_context.rs @@ -8,10 +8,22 @@ //! Supports dynamic attaching and detaching which control notifications of navigation, etc. use crate::actor::{Actor, ActorMessageStatus, ActorRegistry}; -use crate::actors::console::ConsoleActor; +use crate::actors::emulation::EmulationActor; +use crate::actors::inspector::InspectorActor; +use crate::actors::performance::PerformanceActor; +use crate::actors::profiler::ProfilerActor; +use crate::actors::root::RootActor; +use crate::actors::stylesheets::StyleSheetsActor; +use crate::actors::thread::ThreadActor; +use crate::actors::timeline::TimelineActor; use crate::protocol::JsonPacketStream; use devtools_traits::DevtoolScriptControlMsg::{self, WantsLiveNotifications}; +use devtools_traits::DevtoolsPageInfo; +use devtools_traits::NavigationState; +use ipc_channel::ipc::IpcSender; +use msg::constellation_msg::{BrowsingContextId, PipelineId}; use serde_json::{Map, Value}; +use std::cell::{Cell, RefCell}; use std::net::TcpStream; #[derive(Serialize)] @@ -118,6 +130,10 @@ pub struct BrowsingContextActor { pub performance: String, pub styleSheets: String, pub thread: String, + pub streams: RefCell<Vec<TcpStream>>, + pub browsing_context_id: BrowsingContextId, + pub active_pipeline: Cell<PipelineId>, + pub script_chan: IpcSender<DevtoolScriptControlMsg>, } impl Actor for BrowsingContextActor { @@ -127,7 +143,7 @@ impl Actor for BrowsingContextActor { fn handle_message( &self, - registry: &ActorRegistry, + _registry: &ActorRegistry, msg_type: &str, msg: &Map<String, Value>, stream: &mut TcpStream, @@ -137,10 +153,9 @@ impl Actor for BrowsingContextActor { if let Some(options) = msg.get("options").and_then(|o| o.as_object()) { if let Some(val) = options.get("performReload") { if val.as_bool().unwrap_or(false) { - let console_actor = registry.find::<ConsoleActor>(&self.console); - let _ = console_actor + let _ = self .script_chan - .send(DevtoolScriptControlMsg::Reload(console_actor.pipeline)); + .send(DevtoolScriptControlMsg::Reload(self.active_pipeline.get())); } } } @@ -165,32 +180,25 @@ impl Actor for BrowsingContextActor { watchpoints: false, }, }; - let console_actor = registry.find::<ConsoleActor>(&self.console); - console_actor - .streams - .borrow_mut() - .push(stream.try_clone().unwrap()); + self.streams.borrow_mut().push(stream.try_clone().unwrap()); stream.write_json_packet(&msg); - console_actor - .script_chan - .send(WantsLiveNotifications(console_actor.pipeline, true)) + self.script_chan + .send(WantsLiveNotifications(self.active_pipeline.get(), true)) .unwrap(); ActorMessageStatus::Processed }, - //FIXME: The current implementation won't work for multiple connections. Need to ensure 105 + //FIXME: The current implementation won't work for multiple connections. Need to ensure // that the correct stream is removed. "detach" => { let msg = BrowsingContextDetachedReply { from: self.name(), type_: "detached".to_owned(), }; - let console_actor = registry.find::<ConsoleActor>(&self.console); - console_actor.streams.borrow_mut().pop(); + self.streams.borrow_mut().pop(); stream.write_json_packet(&msg); - console_actor - .script_chan - .send(WantsLiveNotifications(console_actor.pipeline, false)) + self.script_chan + .send(WantsLiveNotifications(self.active_pipeline.get(), false)) .unwrap(); ActorMessageStatus::Processed }, @@ -224,6 +232,70 @@ impl Actor for BrowsingContextActor { } impl BrowsingContextActor { + pub(crate) fn new( + console: String, + id: BrowsingContextId, + page_info: DevtoolsPageInfo, + pipeline: PipelineId, + script_sender: IpcSender<DevtoolScriptControlMsg>, + actors: &mut ActorRegistry, + ) -> BrowsingContextActor { + let emulation = EmulationActor::new(actors.new_name("emulation")); + + let name = actors.new_name("target"); + + let inspector = InspectorActor { + name: actors.new_name("inspector"), + walker: RefCell::new(None), + pageStyle: RefCell::new(None), + highlighter: RefCell::new(None), + script_chan: script_sender.clone(), + browsing_context: name.clone(), + }; + + let timeline = + TimelineActor::new(actors.new_name("timeline"), pipeline, script_sender.clone()); + + let profiler = ProfilerActor::new(actors.new_name("profiler")); + let performance = PerformanceActor::new(actors.new_name("performance")); + + // the strange switch between styleSheets and stylesheets is due + // to an inconsistency in devtools. See Bug #1498893 in bugzilla + let styleSheets = StyleSheetsActor::new(actors.new_name("stylesheets")); + let thread = ThreadActor::new(actors.new_name("context")); + + let DevtoolsPageInfo { title, url } = page_info; + let target = BrowsingContextActor { + name: name, + script_chan: script_sender, + title: String::from(title), + url: url.into_string(), + console: console, + emulation: emulation.name(), + inspector: inspector.name(), + timeline: timeline.name(), + profiler: profiler.name(), + performance: performance.name(), + styleSheets: styleSheets.name(), + thread: thread.name(), + streams: RefCell::new(Vec::new()), + browsing_context_id: id, + active_pipeline: Cell::new(pipeline), + }; + + actors.register(Box::new(emulation)); + actors.register(Box::new(inspector)); + actors.register(Box::new(timeline)); + actors.register(Box::new(profiler)); + actors.register(Box::new(performance)); + actors.register(Box::new(styleSheets)); + actors.register(Box::new(thread)); + + let root = actors.find_mut::<RootActor>("root"); + root.tabs.push(target.name.clone()); + target + } + pub fn encodable(&self) -> BrowsingContextActorMsg { BrowsingContextActorMsg { actor: self.name(), @@ -232,8 +304,10 @@ impl BrowsingContextActor { }, title: self.title.clone(), url: self.url.clone(), - browsingContextId: 0, //FIXME should come from constellation - outerWindowID: 0, //FIXME: this should probably be the pipeline id + //FIXME: shouldn't ignore pipeline namespace field + browsingContextId: self.browsing_context_id.index.0.get(), + //FIXME: shouldn't ignore pipeline namespace field + outerWindowID: self.active_pipeline.get().index.0.get(), consoleActor: self.console.clone(), emulationActor: self.emulation.clone(), inspectorActor: self.inspector.clone(), @@ -243,4 +317,40 @@ impl BrowsingContextActor { styleSheetsActor: self.styleSheets.clone(), } } + + pub(crate) fn navigate(&self, state: NavigationState) { + let (pipeline, title, url, state) = match state { + NavigationState::Start(url) => (None, None, url, "start"), + NavigationState::Stop(pipeline, info) => { + (Some(pipeline), Some(info.title), info.url, "stop") + }, + }; + if let Some(p) = pipeline { + self.active_pipeline.set(p); + } + let msg = TabNavigated { + from: self.name(), + type_: "tabNavigated".to_owned(), + url: url.as_str().to_owned(), + title: title, + nativeConsoleAPI: true, + state: state.to_owned(), + isFrameSwitching: false, + }; + for stream in &mut *self.streams.borrow_mut() { + stream.write_json_packet(&msg); + } + } +} + +#[derive(Serialize)] +struct TabNavigated { + from: String, + #[serde(rename = "type")] + type_: String, + url: String, + title: Option<String>, + nativeConsoleAPI: bool, + state: String, + isFrameSwitching: bool, } diff --git a/components/devtools/actors/console.rs b/components/devtools/actors/console.rs index 845e39075b1..8c07c324e6d 100644 --- a/components/devtools/actors/console.rs +++ b/components/devtools/actors/console.rs @@ -8,6 +8,7 @@ //! inspection, JS evaluation, autocompletion) in Servo. use crate::actor::{Actor, ActorMessageStatus, ActorRegistry}; +use crate::actors::browsing_context::BrowsingContextActor; use crate::actors::object::ObjectActor; use crate::protocol::JsonPacketStream; use crate::{ConsoleAPICall, ConsoleMessage, ConsoleMsg, PageErrorMsg}; @@ -17,10 +18,11 @@ use devtools_traits::EvaluateJSReply::{NullValue, NumberValue, VoidValue}; use devtools_traits::{ CachedConsoleMessageTypes, ConsoleAPI, DevtoolScriptControlMsg, LogLevel, PageError, }; -use ipc_channel::ipc::{self, IpcSender}; +use ipc_channel::ipc; use msg::constellation_msg::PipelineId; use serde_json::{self, Map, Number, Value}; use std::cell::RefCell; +use std::collections::HashMap; use std::net::TcpStream; use time::precise_time_ns; use uuid::Uuid; @@ -106,10 +108,8 @@ struct SetPreferencesReply { pub struct ConsoleActor { pub name: String, - pub pipeline: PipelineId, - pub script_chan: IpcSender<DevtoolScriptControlMsg>, - pub streams: RefCell<Vec<TcpStream>>, - pub cached_events: RefCell<Vec<CachedConsoleMessage>>, + pub browsing_context: String, + pub cached_events: RefCell<HashMap<PipelineId, Vec<CachedConsoleMessage>>>, } impl ConsoleActor { @@ -118,11 +118,13 @@ impl ConsoleActor { registry: &ActorRegistry, msg: &Map<String, Value>, ) -> Result<EvaluateJSReply, ()> { + let browsing_context = registry.find::<BrowsingContextActor>(&self.browsing_context); let input = msg.get("text").unwrap().as_str().unwrap().to_owned(); let (chan, port) = ipc::channel().unwrap(); - self.script_chan + browsing_context + .script_chan .send(DevtoolScriptControlMsg::EvaluateJS( - self.pipeline, + browsing_context.active_pipeline.get(), input.clone(), chan, )) @@ -191,21 +193,35 @@ impl ConsoleActor { std::result::Result::Ok(reply) } - pub(crate) fn handle_page_error(&self, page_error: PageError) { + pub(crate) fn handle_page_error( + &self, + page_error: PageError, + pipeline: PipelineId, + browsing_context: &BrowsingContextActor, + ) { self.cached_events .borrow_mut() + .entry(pipeline) + .or_insert(vec![]) .push(CachedConsoleMessage::PageError(page_error.clone())); - let msg = PageErrorMsg { - from: self.name(), - type_: "pageError".to_owned(), - pageError: page_error, - }; - for stream in &mut *self.streams.borrow_mut() { - stream.write_json_packet(&msg); + if browsing_context.active_pipeline.get() == pipeline { + let msg = PageErrorMsg { + from: self.name(), + type_: "pageError".to_owned(), + pageError: page_error, + }; + for stream in &mut *browsing_context.streams.borrow_mut() { + stream.write_json_packet(&msg); + } } } - pub(crate) fn handle_console_api(&self, console_message: ConsoleMessage) { + pub(crate) fn handle_console_api( + &self, + console_message: ConsoleMessage, + pipeline: PipelineId, + browsing_context: &BrowsingContextActor, + ) { let level = match console_message.logLevel { LogLevel::Debug => "debug", LogLevel::Info => "info", @@ -216,6 +232,8 @@ impl ConsoleActor { .to_owned(); self.cached_events .borrow_mut() + .entry(pipeline) + .or_insert(vec![]) .push(CachedConsoleMessage::ConsoleAPI(ConsoleAPI { type_: "ConsoleAPI".to_owned(), level: level.clone(), @@ -226,20 +244,22 @@ impl ConsoleActor { private: false, arguments: vec![console_message.message.clone()], })); - let msg = ConsoleAPICall { - from: self.name(), - type_: "consoleAPICall".to_owned(), - message: ConsoleMsg { - level: level, - timeStamp: precise_time_ns(), - arguments: vec![console_message.message], - filename: console_message.filename, - lineNumber: console_message.lineNumber, - columnNumber: console_message.columnNumber, - }, - }; - for stream in &mut *self.streams.borrow_mut() { - stream.write_json_packet(&msg); + if browsing_context.active_pipeline.get() == pipeline { + let msg = ConsoleAPICall { + from: self.name(), + type_: "consoleAPICall".to_owned(), + message: ConsoleMsg { + level: level, + timeStamp: precise_time_ns(), + arguments: vec![console_message.message], + filename: console_message.filename, + lineNumber: console_message.lineNumber, + columnNumber: console_message.columnNumber, + }, + }; + for stream in &mut *browsing_context.streams.borrow_mut() { + stream.write_json_packet(&msg); + } } } } @@ -275,8 +295,16 @@ impl Actor for ConsoleActor { s => debug!("unrecognized message type requested: \"{}\"", s), }; } + let browsing_context = + registry.find::<BrowsingContextActor>(&self.browsing_context); let mut messages = vec![]; - for event in self.cached_events.borrow().iter() { + for event in self + .cached_events + .borrow() + .get(&browsing_context.active_pipeline.get()) + .unwrap_or(&vec![]) + .iter() + { let include = match event { CachedConsoleMessage::PageError(_) if message_types.contains(CachedConsoleMessageTypes::PAGE_ERROR) => diff --git a/components/devtools/actors/inspector.rs b/components/devtools/actors/inspector.rs index cd3e5bf323c..d2f0929ac89 100644 --- a/components/devtools/actors/inspector.rs +++ b/components/devtools/actors/inspector.rs @@ -6,6 +6,7 @@ //! (http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/inspector.js). use crate::actor::{Actor, ActorMessageStatus, ActorRegistry}; +use crate::actors::browsing_context::BrowsingContextActor; use crate::protocol::JsonPacketStream; use devtools_traits::DevtoolScriptControlMsg::{GetChildren, GetDocumentElement, GetRootNode}; use devtools_traits::DevtoolScriptControlMsg::{GetLayout, ModifyAttribute}; @@ -22,7 +23,7 @@ pub struct InspectorActor { pub pageStyle: RefCell<Option<String>>, pub highlighter: RefCell<Option<String>>, pub script_chan: IpcSender<DevtoolScriptControlMsg>, - pub pipeline: PipelineId, + pub browsing_context: String, } #[derive(Serialize)] @@ -596,13 +597,15 @@ impl Actor for InspectorActor { _msg: &Map<String, Value>, stream: &mut TcpStream, ) -> Result<ActorMessageStatus, ()> { + let browsing_context = registry.find::<BrowsingContextActor>(&self.browsing_context); + let pipeline = browsing_context.active_pipeline.get(); Ok(match msg_type { "getWalker" => { if self.walker.borrow().is_none() { let walker = WalkerActor { name: registry.new_name("walker"), script_chan: self.script_chan.clone(), - pipeline: self.pipeline, + pipeline: pipeline, }; let mut walker_name = self.walker.borrow_mut(); *walker_name = Some(walker.name()); @@ -610,13 +613,10 @@ impl Actor for InspectorActor { } let (tx, rx) = ipc::channel().unwrap(); - self.script_chan - .send(GetRootNode(self.pipeline, tx)) - .unwrap(); + self.script_chan.send(GetRootNode(pipeline, tx)).unwrap(); let root_info = rx.recv().unwrap().ok_or(())?; - let node = - root_info.encode(registry, false, self.script_chan.clone(), self.pipeline); + let node = root_info.encode(registry, false, self.script_chan.clone(), pipeline); let msg = GetWalkerReply { from: self.name(), @@ -634,7 +634,7 @@ impl Actor for InspectorActor { let style = PageStyleActor { name: registry.new_name("pageStyle"), script_chan: self.script_chan.clone(), - pipeline: self.pipeline, + pipeline: pipeline, }; let mut pageStyle = self.pageStyle.borrow_mut(); *pageStyle = Some(style.name()); diff --git a/components/devtools/lib.rs b/components/devtools/lib.rs index 661d6ac94e1..6d9bd938e14 100644 --- a/components/devtools/lib.rs +++ b/components/devtools/lib.rs @@ -21,29 +21,24 @@ use crate::actor::{Actor, ActorRegistry}; use crate::actors::browsing_context::BrowsingContextActor; use crate::actors::console::ConsoleActor; use crate::actors::device::DeviceActor; -use crate::actors::emulation::EmulationActor; use crate::actors::framerate::FramerateActor; -use crate::actors::inspector::InspectorActor; use crate::actors::network_event::{EventActor, NetworkEventActor, ResponseStartMsg}; use crate::actors::performance::PerformanceActor; use crate::actors::preference::PreferenceActor; use crate::actors::process::ProcessActor; -use crate::actors::profiler::ProfilerActor; use crate::actors::root::RootActor; -use crate::actors::stylesheets::StyleSheetsActor; -use crate::actors::thread::ThreadActor; -use crate::actors::timeline::TimelineActor; use crate::actors::worker::WorkerActor; use crate::protocol::JsonPacketStream; use crossbeam_channel::{unbounded, Receiver, Sender}; use devtools_traits::{ChromeToDevtoolsControlMsg, ConsoleMessage, DevtoolsControlMsg}; -use devtools_traits::{DevtoolScriptControlMsg, DevtoolsPageInfo, LogLevel, NetworkEvent}; +use devtools_traits::{ + DevtoolScriptControlMsg, DevtoolsPageInfo, LogLevel, NavigationState, NetworkEvent, +}; use devtools_traits::{PageError, ScriptToDevtoolsControlMsg, WorkerId}; use embedder_traits::{EmbedderMsg, EmbedderProxy, PromptDefinition, PromptOrigin, PromptResult}; use ipc_channel::ipc::{self, IpcSender}; -use msg::constellation_msg::PipelineId; +use msg::constellation_msg::{BrowsingContextId, PipelineId}; use std::borrow::ToOwned; -use std::cell::RefCell; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::HashMap; use std::net::{Shutdown, TcpListener, TcpStream}; @@ -198,7 +193,8 @@ fn run_server( let mut accepted_connections: Vec<TcpStream> = Vec::new(); - let mut actor_pipelines: HashMap<PipelineId, String> = HashMap::new(); + let mut browsing_contexts: HashMap<BrowsingContextId, String> = HashMap::new(); + let mut pipelines: HashMap<PipelineId, BrowsingContextId> = HashMap::new(); let mut actor_requests: HashMap<String, String> = HashMap::new(); let mut actor_workers: HashMap<(PipelineId, WorkerId), String> = HashMap::new(); @@ -243,91 +239,65 @@ fn run_server( framerate_actor.add_tick(tick); } + fn handle_navigate( + actors: Arc<Mutex<ActorRegistry>>, + browsing_contexts: &HashMap<BrowsingContextId, String>, + browsing_context: BrowsingContextId, + state: NavigationState, + ) { + let actor_name = browsing_contexts.get(&browsing_context).unwrap(); + actors + .lock() + .unwrap() + .find::<BrowsingContextActor>(actor_name) + .navigate(state); + } + // We need separate actor representations for each script global that exists; // clients can theoretically connect to multiple globals simultaneously. // TODO: move this into the root or target modules? fn handle_new_global( actors: Arc<Mutex<ActorRegistry>>, - ids: (PipelineId, Option<WorkerId>), + ids: (Option<BrowsingContextId>, PipelineId, Option<WorkerId>), script_sender: IpcSender<DevtoolScriptControlMsg>, - actor_pipelines: &mut HashMap<PipelineId, String>, + browsing_contexts: &mut HashMap<BrowsingContextId, String>, + pipelines: &mut HashMap<PipelineId, BrowsingContextId>, actor_workers: &mut HashMap<(PipelineId, WorkerId), String>, page_info: DevtoolsPageInfo, ) { let mut actors = actors.lock().unwrap(); - let (pipeline, worker_id) = ids; - - //TODO: move all this actor creation into a constructor method on BrowsingContextActor - let ( - target, - console, - emulation, - inspector, - timeline, - profiler, - performance, - styleSheets, - thread, - ) = { - let console = ConsoleActor { - name: actors.new_name("console"), - script_chan: script_sender.clone(), - pipeline: pipeline, - streams: RefCell::new(Vec::new()), - cached_events: RefCell::new(Vec::new()), - }; - - let emulation = EmulationActor::new(actors.new_name("emulation")); - - let inspector = InspectorActor { - name: actors.new_name("inspector"), - walker: RefCell::new(None), - pageStyle: RefCell::new(None), - highlighter: RefCell::new(None), - script_chan: script_sender.clone(), - pipeline: pipeline, - }; - - let timeline = TimelineActor::new(actors.new_name("timeline"), pipeline, script_sender); - - let profiler = ProfilerActor::new(actors.new_name("profiler")); - let performance = PerformanceActor::new(actors.new_name("performance")); - - // the strange switch between styleSheets and stylesheets is due - // to an inconsistency in devtools. See Bug #1498893 in bugzilla - let styleSheets = StyleSheetsActor::new(actors.new_name("stylesheets")); - let thread = ThreadActor::new(actors.new_name("context")); - - let DevtoolsPageInfo { title, url } = page_info; - let target = BrowsingContextActor { - name: actors.new_name("target"), - title: String::from(title), - url: url.into_string(), - console: console.name(), - emulation: emulation.name(), - inspector: inspector.name(), - timeline: timeline.name(), - profiler: profiler.name(), - performance: performance.name(), - styleSheets: styleSheets.name(), - thread: thread.name(), - }; + let (browsing_context, pipeline, worker_id) = ids; + + let console_name = actors.new_name("console"); + + let browsing_context_name = if let Some(browsing_context) = browsing_context { + pipelines.insert(pipeline, browsing_context); + if let Some(actor) = browsing_contexts.get(&browsing_context) { + actor.to_owned() + } else { + let browsing_context_actor = BrowsingContextActor::new( + console_name.clone(), + browsing_context, + page_info, + pipeline, + script_sender.clone(), + &mut *actors, + ); + let name = browsing_context_actor.name(); + browsing_contexts.insert(browsing_context, name.clone()); + actors.register(Box::new(browsing_context_actor)); + name + } + } else { + "".to_owned() + }; - let root = actors.find_mut::<RootActor>("root"); - root.tabs.push(target.name.clone()); - - ( - target, - console, - emulation, - inspector, - timeline, - profiler, - performance, - styleSheets, - thread, - ) + // XXXjdm this new actor is useless if it's not a new worker global + let console = ConsoleActor { + name: console_name, + cached_events: Default::default(), + browsing_context: browsing_context_name, }; if let Some(id) = worker_id { @@ -336,36 +306,39 @@ fn run_server( console: console.name(), id: id, }; + let root = actors.find_mut::<RootActor>("root"); + root.tabs.push(worker.name.clone()); + actor_workers.insert((pipeline, id), worker.name.clone()); actors.register(Box::new(worker)); } - actor_pipelines.insert(pipeline, target.name.clone()); - actors.register(Box::new(target)); actors.register(Box::new(console)); - actors.register(Box::new(emulation)); - actors.register(Box::new(inspector)); - actors.register(Box::new(timeline)); - actors.register(Box::new(profiler)); - actors.register(Box::new(performance)); - actors.register(Box::new(styleSheets)); - actors.register(Box::new(thread)); } fn handle_page_error( actors: Arc<Mutex<ActorRegistry>>, id: PipelineId, page_error: PageError, - actor_pipelines: &HashMap<PipelineId, String>, + browsing_contexts: &HashMap<BrowsingContextId, String>, + pipelines: &HashMap<PipelineId, BrowsingContextId>, ) { - let console_actor_name = - match find_console_actor(actors.clone(), id, None, &HashMap::new(), actor_pipelines) { - Some(name) => name, - None => return, - }; + let console_actor_name = match find_console_actor( + actors.clone(), + id, + None, + &HashMap::new(), + browsing_contexts, + pipelines, + ) { + Some(name) => name, + None => return, + }; let actors = actors.lock().unwrap(); let console_actor = actors.find::<ConsoleActor>(&console_actor_name); - console_actor.handle_page_error(page_error); + let browsing_context_actor = + actors.find::<BrowsingContextActor>(&console_actor.browsing_context); + console_actor.handle_page_error(page_error, id, &browsing_context_actor); } fn handle_console_message( @@ -373,37 +346,43 @@ fn run_server( id: PipelineId, worker_id: Option<WorkerId>, console_message: ConsoleMessage, - actor_pipelines: &HashMap<PipelineId, String>, + browsing_contexts: &HashMap<BrowsingContextId, String>, actor_workers: &HashMap<(PipelineId, WorkerId), String>, + pipelines: &HashMap<PipelineId, BrowsingContextId>, ) { let console_actor_name = match find_console_actor( actors.clone(), id, worker_id, actor_workers, - actor_pipelines, + browsing_contexts, + pipelines, ) { Some(name) => name, None => return, }; let actors = actors.lock().unwrap(); let console_actor = actors.find::<ConsoleActor>(&console_actor_name); - console_actor.handle_console_api(console_message); + let browsing_context_actor = + actors.find::<BrowsingContextActor>(&console_actor.browsing_context); + console_actor.handle_console_api(console_message, id, &browsing_context_actor); } fn find_console_actor( actors: Arc<Mutex<ActorRegistry>>, - id: PipelineId, + pipeline: PipelineId, worker_id: Option<WorkerId>, actor_workers: &HashMap<(PipelineId, WorkerId), String>, - actor_pipelines: &HashMap<PipelineId, String>, + browsing_contexts: &HashMap<BrowsingContextId, String>, + pipelines: &HashMap<PipelineId, BrowsingContextId>, ) -> Option<String> { let actors = actors.lock().unwrap(); if let Some(worker_id) = worker_id { - let actor_name = (*actor_workers).get(&(id, worker_id))?; + let actor_name = (*actor_workers).get(&(pipeline, worker_id))?; Some(actors.find::<WorkerActor>(actor_name).console.clone()) } else { - let actor_name = (*actor_pipelines).get(&id)?; + let id = pipelines.get(&pipeline)?; + let actor_name = browsing_contexts.get(id)?; Some( actors .find::<BrowsingContextActor>(actor_name) @@ -416,9 +395,10 @@ fn run_server( fn handle_network_event( actors: Arc<Mutex<ActorRegistry>>, mut connections: Vec<TcpStream>, - actor_pipelines: &HashMap<PipelineId, String>, + browsing_contexts: &HashMap<BrowsingContextId, String>, actor_requests: &mut HashMap<String, String>, actor_workers: &HashMap<(PipelineId, WorkerId), String>, + pipelines: &HashMap<PipelineId, BrowsingContextId>, pipeline_id: PipelineId, request_id: String, network_event: NetworkEvent, @@ -428,7 +408,8 @@ fn run_server( pipeline_id, None, actor_workers, - actor_pipelines, + browsing_contexts, + pipelines, ) { Some(name) => name, None => return, @@ -610,10 +591,15 @@ fn run_server( actors.clone(), ids, script_sender, - &mut actor_pipelines, + &mut browsing_contexts, + &mut pipelines, &mut actor_workers, pageinfo, ), + DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::Navigate( + browsing_context, + state, + )) => handle_navigate(actors.clone(), &browsing_contexts, browsing_context, state), DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::ConsoleAPI( id, console_message, @@ -623,13 +609,20 @@ fn run_server( id, worker_id, console_message, - &actor_pipelines, + &browsing_contexts, &actor_workers, + &pipelines, ), DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::ReportPageError( id, page_error, - )) => handle_page_error(actors.clone(), id, page_error, &actor_pipelines), + )) => handle_page_error( + actors.clone(), + id, + page_error, + &browsing_contexts, + &pipelines, + ), DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::ReportCSSError( id, css_error, @@ -646,8 +639,9 @@ fn run_server( id, None, console_message, - &actor_pipelines, + &browsing_contexts, &actor_workers, + &pipelines, ) }, DevtoolsControlMsg::FromChrome(ChromeToDevtoolsControlMsg::NetworkEvent( @@ -667,9 +661,10 @@ fn run_server( handle_network_event( actors.clone(), connections, - &actor_pipelines, + &browsing_contexts, &mut actor_requests, &actor_workers, + &pipelines, pipeline_id, request_id, network_event, diff --git a/components/devtools_traits/lib.rs b/components/devtools_traits/lib.rs index 5396d64fade..f55e0990588 100644 --- a/components/devtools_traits/lib.rs +++ b/components/devtools_traits/lib.rs @@ -21,7 +21,7 @@ extern crate serde; use http::method::Method; use http::HeaderMap; use ipc_channel::ipc::IpcSender; -use msg::constellation_msg::PipelineId; +use msg::constellation_msg::{BrowsingContextId, PipelineId}; use servo_url::ServoUrl; use std::net::TcpStream; use time::{self, Duration, Tm}; @@ -29,7 +29,7 @@ use uuid::Uuid; // Information would be attached to NewGlobal to be received and show in devtools. // Extend these fields if we need more information. -#[derive(Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct DevtoolsPageInfo { pub title: String, pub url: ServoUrl, @@ -65,16 +65,27 @@ pub enum ChromeToDevtoolsControlMsg { NetworkEvent(String, NetworkEvent), } +/// The state of a page navigation. +#[derive(Debug, Deserialize, Serialize)] +pub enum NavigationState { + /// A browsing context is about to navigate to a given URL. + Start(ServoUrl), + /// A browsing context has completed navigating to the provided pipeline. + Stop(PipelineId, DevtoolsPageInfo), +} + #[derive(Debug, Deserialize, Serialize)] /// Events that the devtools server must act upon. pub enum ScriptToDevtoolsControlMsg { /// A new global object was created, associated with a particular pipeline. /// The means of communicating directly with it are provided. NewGlobal( - (PipelineId, Option<WorkerId>), + (Option<BrowsingContextId>, PipelineId, Option<WorkerId>), IpcSender<DevtoolScriptControlMsg>, DevtoolsPageInfo, ), + /// The given browsing context is performing a navigation. + Navigate(BrowsingContextId, NavigationState), /// A particular page has invoked the console API. ConsoleAPI(PipelineId, ConsoleMessage, Option<WorkerId>), /// An animation frame with the given timestamp was processed in a script thread. diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 9f37ec2240a..c23efc961ee 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -2008,15 +2008,21 @@ impl Window { // Step 8 if doc.prompt_to_unload(false) { - if self.window_proxy().parent().is_some() { + let window_proxy = self.window_proxy(); + if window_proxy.parent().is_some() { // Step 10 // If browsingContext is a nested browsing context, // then put it in the delaying load events mode. - self.window_proxy().start_delaying_load_events_mode(); + window_proxy.start_delaying_load_events_mode(); } // TODO: step 11, navigationType. // Step 12, 13 - ScriptThread::navigate(pipeline_id, load_data, replace); + ScriptThread::navigate( + window_proxy.browsing_context_id(), + pipeline_id, + load_data, + replace, + ); }; } diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs index d040d7d7468..9c0cc91273a 100644 --- a/components/script/dom/worker.rs +++ b/components/script/dom/worker.rs @@ -105,7 +105,7 @@ impl Worker { url: worker_url.clone(), }; let _ = chan.send(ScriptToDevtoolsControlMsg::NewGlobal( - (pipeline_id, Some(worker_id)), + (None, pipeline_id, Some(worker_id)), devtools_sender.clone(), page_info, )); diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 7a672851ba6..7431bcf1032 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -93,7 +93,7 @@ use canvas_traits::webgl::WebGLPipeline; use crossbeam_channel::{unbounded, Receiver, Sender}; use devtools_traits::CSSError; use devtools_traits::{DevtoolScriptControlMsg, DevtoolsPageInfo}; -use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId}; +use devtools_traits::{NavigationState, ScriptToDevtoolsControlMsg, WorkerId}; use embedder_traits::{EmbedderMsg, EventLoopWaker}; use euclid::default::{Point2D, Rect}; use euclid::Vector2D; @@ -947,6 +947,7 @@ impl ScriptThread { /// Step 13 of https://html.spec.whatwg.org/multipage/#navigate pub fn navigate( + browsing_context: BrowsingContextId, pipeline_id: PipelineId, mut load_data: LoadData, replace: HistoryEntryReplacement, @@ -985,6 +986,12 @@ impl ScriptThread { .queue(task, global.upcast()) .expect("Enqueing navigate js task on the DOM manipulation task source failed"); } else { + if let Some(ref sender) = script_thread.devtools_chan { + let _ = sender.send(ScriptToDevtoolsControlMsg::Navigate( + browsing_context, NavigationState::Start(load_data.url.clone()) + )); + } + script_thread .script_sender .send((pipeline_id, ScriptMsg::LoadUrl(load_data, replace))) @@ -3338,7 +3345,7 @@ impl ScriptThread { self.notify_devtools( document.Title(), final_url.clone(), - (incomplete.pipeline_id, None), + (incomplete.browsing_context_id, incomplete.pipeline_id, None), ); let parse_input = DOMString::new(); @@ -3369,7 +3376,7 @@ impl ScriptThread { &self, title: DOMString, url: ServoUrl, - ids: (PipelineId, Option<WorkerId>), + (bc, p, w): (BrowsingContextId, PipelineId, Option<WorkerId>), ) { if let Some(ref chan) = self.devtools_chan { let page_info = DevtoolsPageInfo { @@ -3377,11 +3384,14 @@ impl ScriptThread { url: url, }; chan.send(ScriptToDevtoolsControlMsg::NewGlobal( - ids, + (Some(bc), p, w), self.devtools_sender.clone(), - page_info, + page_info.clone(), )) .unwrap(); + + let state = NavigationState::Stop(p, page_info); + let _ = chan.send(ScriptToDevtoolsControlMsg::Navigate(bc, state)); } } diff --git a/components/script/serviceworker_manager.rs b/components/script/serviceworker_manager.rs index 83bf1dbf312..0383d7bf6da 100644 --- a/components/script/serviceworker_manager.rs +++ b/components/script/serviceworker_manager.rs @@ -87,7 +87,11 @@ impl ServiceWorkerManager { url: scope_things.script_url.clone(), }; let _ = chan.send(ScriptToDevtoolsControlMsg::NewGlobal( - (scope_things.init.pipeline_id, Some(scope_things.worker_id)), + ( + None, + scope_things.init.pipeline_id, + Some(scope_things.worker_id), + ), devtools_sender, page_info, )); |