diff --git a/components/devtools/actor.rs b/components/devtools/actor.rs index f6aca6923d9..158092ee1a8 100644 --- a/components/devtools/actor.rs +++ b/components/devtools/actor.rs @@ -159,7 +159,13 @@ impl ActorRegistry { msg: &Map, stream: &mut TcpStream, ) -> Result<(), ()> { - let to = msg.get("to").unwrap().as_str().unwrap(); + let to = match msg.get("to") { + Some(to) => to.as_str().unwrap(), + None => { + warn!("Received unexpected message: {:?}", msg); + return Err(()); + }, + }; match self.actors.get(to) { None => debug!("message received for unknown actor \"{}\"", to), diff --git a/components/devtools/actors/browsing_context.rs b/components/devtools/actors/browsing_context.rs index b90d84d04bd..708c9f69de9 100644 --- a/components/devtools/actors/browsing_context.rs +++ b/components/devtools/actors/browsing_context.rs @@ -12,8 +12,8 @@ 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::tab::TabDescriptorActor; use crate::actors::thread::ThreadActor; use crate::actors::timeline::TimelineActor; use crate::protocol::JsonPacketStream; @@ -130,6 +130,7 @@ pub struct BrowsingContextActor { pub performance: String, pub styleSheets: String, pub thread: String, + pub tab: String, pub streams: RefCell>, pub browsing_context_id: BrowsingContextId, pub active_pipeline: Cell, @@ -266,6 +267,9 @@ impl BrowsingContextActor { let thread = ThreadActor::new(actors.new_name("context")); let DevtoolsPageInfo { title, url } = page_info; + + let tabdesc = TabDescriptorActor::new(actors, name.clone()); + let target = BrowsingContextActor { name: name, script_chan: script_sender, @@ -278,6 +282,7 @@ impl BrowsingContextActor { profiler: profiler.name(), performance: performance.name(), styleSheets: styleSheets.name(), + tab: tabdesc.name(), thread: thread.name(), streams: RefCell::new(Vec::new()), browsing_context_id: id, @@ -291,9 +296,8 @@ impl BrowsingContextActor { actors.register(Box::new(performance)); actors.register(Box::new(styleSheets)); actors.register(Box::new(thread)); + actors.register(Box::new(tabdesc)); - let root = actors.find_mut::("root"); - root.tabs.push(target.name.clone()); target } diff --git a/components/devtools/actors/root.rs b/components/devtools/actors/root.rs index 0010afd3b9f..1965d973728 100644 --- a/components/devtools/actors/root.rs +++ b/components/devtools/actors/root.rs @@ -7,9 +7,9 @@ /// Connection point for all new remote devtools interactions, providing lists of know actors /// that perform more specific actions (targets, addons, browser chrome, etc.) use crate::actor::{Actor, ActorMessageStatus, ActorRegistry}; -use crate::actors::browsing_context::{BrowsingContextActor, BrowsingContextActorMsg}; use crate::actors::device::DeviceActor; use crate::actors::performance::PerformanceActor; +use crate::actors::tab::{TabDescriptorActor, TabDescriptorActorMsg}; use crate::actors::worker::{WorkerActor, WorkerMsg}; use crate::protocol::{ActorDescription, JsonPacketStream}; use serde_json::{Map, Value}; @@ -45,13 +45,13 @@ struct GetRootReply { struct ListTabsReply { from: String, selected: u32, - tabs: Vec, + tabs: Vec, } #[derive(Serialize)] struct GetTabReply { from: String, - tab: BrowsingContextActorMsg, + tab: TabDescriptorActorMsg, } #[derive(Serialize)] @@ -181,7 +181,11 @@ impl Actor for RootActor { tabs: self .tabs .iter() - .map(|target| registry.find::(target).encodable()) + .map(|target| { + registry + .find::(target) + .encodable(®istry) + }) .collect(), }; stream.write_json_packet(&actor); @@ -211,10 +215,10 @@ impl Actor for RootActor { }, "getTab" => { - let tab = registry.find::(&self.tabs[0]); + let tab = registry.find::(&self.tabs[0]); let reply = GetTabReply { from: self.name(), - tab: tab.encodable(), + tab: tab.encodable(®istry), }; stream.write_json_packet(&reply); ActorMessageStatus::Processed diff --git a/components/devtools/actors/tab.rs b/components/devtools/actors/tab.rs new file mode 100644 index 00000000000..1f83d246233 --- /dev/null +++ b/components/devtools/actors/tab.rs @@ -0,0 +1,101 @@ +/* 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 https://mozilla.org/MPL/2.0/. */ + +use crate::actor::{Actor, ActorMessageStatus, ActorRegistry}; +use crate::actors::browsing_context::{BrowsingContextActor, BrowsingContextActorMsg}; +use crate::actors::root::RootActor; +use crate::protocol::JsonPacketStream; +use serde_json::{Map, Value}; +use std::net::TcpStream; + +#[derive(Serialize)] +pub struct TabDescriptorTraits { + getFavicon: bool, + hasTabInfo: bool, + watcher: bool, +} + +#[derive(Serialize)] +pub struct TabDescriptorActorMsg { + actor: String, + title: String, + url: String, + outerWindowID: u32, + browsingContextId: u32, + traits: TabDescriptorTraits, +} + +#[derive(Serialize)] +struct GetTargetReply { + from: String, + frame: BrowsingContextActorMsg, +} + +pub struct TabDescriptorActor { + name: String, + browsing_context_actor: String, +} + +impl Actor for TabDescriptorActor { + fn name(&self) -> String { + self.name.clone() + } + + fn handle_message( + &self, + registry: &ActorRegistry, + msg_type: &str, + _msg: &Map, + stream: &mut TcpStream, + ) -> Result { + Ok(match msg_type { + "getTarget" => { + let frame = registry + .find::(&self.browsing_context_actor) + .encodable(); + stream.write_json_packet(&GetTargetReply { + from: self.name(), + frame, + }); + ActorMessageStatus::Processed + }, + _ => ActorMessageStatus::Ignored, + }) + } +} + +impl TabDescriptorActor { + pub(crate) fn new( + actors: &mut ActorRegistry, + browsing_context_actor: String, + ) -> TabDescriptorActor { + let name = actors.new_name("tabDescription"); + let root = actors.find_mut::("root"); + root.tabs.push(name.clone()); + TabDescriptorActor { + name: name, + browsing_context_actor, + } + } + + pub fn encodable(&self, registry: &ActorRegistry) -> TabDescriptorActorMsg { + let ctx_actor = registry.find::(&self.browsing_context_actor); + + let title = ctx_actor.title.borrow().clone(); + let url = ctx_actor.url.borrow().clone(); + + TabDescriptorActorMsg { + title, + url, + actor: self.name(), + browsingContextId: ctx_actor.browsing_context_id.index.0.get(), + outerWindowID: ctx_actor.active_pipeline.get().index.0.get(), + traits: TabDescriptorTraits { + getFavicon: false, + hasTabInfo: true, + watcher: false, + }, + } + } +} diff --git a/components/devtools/lib.rs b/components/devtools/lib.rs index aafd8860590..62238c656ee 100644 --- a/components/devtools/lib.rs +++ b/components/devtools/lib.rs @@ -66,6 +66,7 @@ mod actors { pub mod profiler; pub mod root; pub mod stylesheets; + pub mod tab; pub mod thread; pub mod timeline; pub mod worker; diff --git a/support/hololens/ServoApp/Devtools/Client.cpp b/support/hololens/ServoApp/Devtools/Client.cpp index b3bc3b9c7b6..f854647ce0a 100644 --- a/support/hololens/ServoApp/Devtools/Client.cpp +++ b/support/hololens/ServoApp/Devtools/Client.cpp @@ -113,24 +113,11 @@ void DevtoolsClient::HandleMessage(JsonObject obj) { } else if (obj.HasKey(L"tab")) { // Got the current tab. auto tab = obj.GetNamedObject(L"tab"); - if (tab.HasKey(L"actor")) { - // Attach to tab, and ask for cached messaged - JsonObject msg1; - mConsoleActor = tab.GetNamedValue(L"consoleActor"); - msg1.Insert(L"to", tab.GetNamedValue(L"actor")); - msg1.Insert(L"type", JsonValue::CreateStringValue(L"attach")); - Send(msg1); - JsonObject msg2; - msg2.Insert(L"to", *mConsoleActor); - msg2.Insert(L"type", - JsonValue::CreateStringValue(L"getCachedMessages")); - JsonArray types; - types.Append(JsonValue::CreateStringValue(L"PageError")); - types.Append(JsonValue::CreateStringValue(L"ConsoleAPI")); - msg2.Insert(L"messageTypes", types); - Send(msg2); - return; - } + JsonObject out; + out.Insert(L"to", tab.GetNamedValue(L"actor")); + out.Insert(L"type", JsonValue::CreateStringValue(L"getTarget")); + Send(out); + return; } } else if (obj.HasKey(L"resultID")) { // evaluateJSAsync response. @@ -163,6 +150,23 @@ void DevtoolsClient::HandleMessage(JsonObject obj) { // FIXME: log if there is a non-200 HTTP response return; } + } else if (obj.HasKey(L"frame")) { + auto frame = obj.GetNamedObject(L"frame"); + // Attach to tab, and ask for cached messaged + JsonObject msg1; + mConsoleActor = frame.GetNamedValue(L"consoleActor"); + msg1.Insert(L"to", frame.GetNamedValue(L"actor")); + msg1.Insert(L"type", JsonValue::CreateStringValue(L"attach")); + Send(msg1); + JsonObject msg2; + msg2.Insert(L"to", *mConsoleActor); + msg2.Insert(L"type", JsonValue::CreateStringValue(L"getCachedMessages")); + JsonArray types; + types.Append(JsonValue::CreateStringValue(L"PageError")); + types.Append(JsonValue::CreateStringValue(L"ConsoleAPI")); + msg2.Insert(L"messageTypes", types); + Send(msg2); + return; } else if (obj.HasKey(L"messages")) { // Response to getCachedMessages for (auto messageValue : obj.GetNamedArray(L"messages")) {