Enable using external WebContents as devtools

This commit is contained in:
Cheng Zhao 2017-11-30 16:37:26 +09:00
parent aab35073ee
commit 5e4914700e
6 changed files with 87 additions and 44 deletions

View file

@ -896,9 +896,10 @@ void WebContents::DevToolsOpened() {
"DevToolsAPI.setInspectedTabId", &tab_id, nullptr, nullptr); "DevToolsAPI.setInspectedTabId", &tab_id, nullptr, nullptr);
// Inherit owner window in devtools. // Inherit owner window in devtools.
if (owner_window()) auto* devtools = managed_web_contents()->GetDevToolsWebContents();
handle->SetOwnerWindow(managed_web_contents()->GetDevToolsWebContents(), if (owner_window() &&
owner_window()); !devtools->GetUserData(NativeWindowRelay::UserDataKey()))
handle->SetOwnerWindow(devtools, owner_window());
Emit("devtools-opened"); Emit("devtools-opened");
} }
@ -1808,6 +1809,11 @@ void WebContents::SetEmbedder(const WebContents* embedder) {
} }
} }
void WebContents::SetDevToolsWebContents(const WebContents* devtools) {
if (managed_web_contents())
managed_web_contents()->SetDevToolsWebContents(devtools->web_contents());
}
v8::Local<v8::Value> WebContents::GetNativeView() const { v8::Local<v8::Value> WebContents::GetNativeView() const {
gfx::NativeView ptr = web_contents()->GetNativeView(); gfx::NativeView ptr = web_contents()->GetNativeView();
auto buffer = node::Buffer::Copy( auto buffer = node::Buffer::Copy(
@ -1929,6 +1935,7 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
.SetMethod("copyImageAt", &WebContents::CopyImageAt) .SetMethod("copyImageAt", &WebContents::CopyImageAt)
.SetMethod("capturePage", &WebContents::CapturePage) .SetMethod("capturePage", &WebContents::CapturePage)
.SetMethod("setEmbedder", &WebContents::SetEmbedder) .SetMethod("setEmbedder", &WebContents::SetEmbedder)
.SetMethod("setDevToolsWebContents", &WebContents::SetDevToolsWebContents)
.SetMethod("getNativeView", &WebContents::GetNativeView) .SetMethod("getNativeView", &WebContents::GetNativeView)
.SetMethod("setWebRTCIPHandlingPolicy", .SetMethod("setWebRTCIPHandlingPolicy",
&WebContents::SetWebRTCIPHandlingPolicy) &WebContents::SetWebRTCIPHandlingPolicy)

View file

@ -126,6 +126,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
void Print(mate::Arguments* args); void Print(mate::Arguments* args);
std::vector<printing::PrinterBasicInfo> GetPrinterList(); std::vector<printing::PrinterBasicInfo> GetPrinterList();
void SetEmbedder(const WebContents* embedder); void SetEmbedder(const WebContents* embedder);
void SetDevToolsWebContents(const WebContents* devtools);
v8::Local<v8::Value> GetNativeView() const; v8::Local<v8::Value> GetNativeView() const;
// Print current page as PDF. // Print current page as PDF.

View file

@ -391,6 +391,10 @@ class NativeWindowRelay :
explicit NativeWindowRelay(base::WeakPtr<NativeWindow> window) explicit NativeWindowRelay(base::WeakPtr<NativeWindow> window)
: key(UserDataKey()), window(window) {} : key(UserDataKey()), window(window) {}
static void* UserDataKey() {
return content::WebContentsUserData<NativeWindowRelay>::UserDataKey();
}
void* key; void* key;
base::WeakPtr<NativeWindow> window; base::WeakPtr<NativeWindow> window;

View file

@ -37,6 +37,7 @@ class InspectableWebContents {
virtual void SetDelegate(InspectableWebContentsDelegate* delegate) = 0; virtual void SetDelegate(InspectableWebContentsDelegate* delegate) = 0;
virtual InspectableWebContentsDelegate* GetDelegate() const = 0; virtual InspectableWebContentsDelegate* GetDelegate() const = 0;
virtual void SetDevToolsWebContents(content::WebContents* devtools) = 0;
virtual void SetDockState(const std::string& state) = 0; virtual void SetDockState(const std::string& state) = 0;
virtual void ShowDevTools() = 0; virtual void ShowDevTools() = 0;
virtual void CloseDevTools() = 0; virtual void CloseDevTools() = 0;

View file

@ -242,13 +242,14 @@ InspectableWebContentsImpl::InspectableWebContentsImpl(
InspectableWebContentsImpl::~InspectableWebContentsImpl() { InspectableWebContentsImpl::~InspectableWebContentsImpl() {
// Unsubscribe from devtools and Clean up resources. // Unsubscribe from devtools and Clean up resources.
if (devtools_web_contents_) { if (GetDevToolsWebContents()) {
devtools_web_contents_->SetDelegate(nullptr); if (managed_devtools_web_contents_)
managed_devtools_web_contents_->SetDelegate(nullptr);
// Calling this also unsubscribes the observer, so WebContentsDestroyed // Calling this also unsubscribes the observer, so WebContentsDestroyed
// won't be called again. // won't be called again.
WebContentsDestroyed(); WebContentsDestroyed();
} }
// Let destructor destroy devtools_web_contents_. // Let destructor destroy managed_devtools_web_contents_.
} }
InspectableWebContentsView* InspectableWebContentsImpl::GetView() const { InspectableWebContentsView* InspectableWebContentsImpl::GetView() const {
@ -261,7 +262,10 @@ content::WebContents* InspectableWebContentsImpl::GetWebContents() const {
content::WebContents* InspectableWebContentsImpl::GetDevToolsWebContents() content::WebContents* InspectableWebContentsImpl::GetDevToolsWebContents()
const { const {
return devtools_web_contents_.get(); if (external_devtools_web_contents_)
return external_devtools_web_contents_;
else
return managed_devtools_web_contents_.get();
} }
void InspectableWebContentsImpl::InspectElement(int x, int y) { void InspectableWebContentsImpl::InspectElement(int x, int y) {
@ -288,43 +292,56 @@ void InspectableWebContentsImpl::SetDockState(const std::string& state) {
} }
} }
void InspectableWebContentsImpl::SetDevToolsWebContents(
content::WebContents* devtools) {
if (!managed_devtools_web_contents_)
external_devtools_web_contents_ = devtools;
}
void InspectableWebContentsImpl::ShowDevTools() { void InspectableWebContentsImpl::ShowDevTools() {
if (embedder_message_dispatcher_) {
if (managed_devtools_web_contents_)
view_->ShowDevTools();
return;
}
// Show devtools only after it has done loading, this is to make sure the // Show devtools only after it has done loading, this is to make sure the
// SetIsDocked is called *BEFORE* ShowDevTools. // SetIsDocked is called *BEFORE* ShowDevTools.
if (!devtools_web_contents_) { embedder_message_dispatcher_.reset(
embedder_message_dispatcher_.reset( DevToolsEmbedderMessageDispatcher::CreateForDevToolsFrontend(this));
DevToolsEmbedderMessageDispatcher::CreateForDevToolsFrontend(this));
content::WebContents::CreateParams create_params( if (!external_devtools_web_contents_) { // no external devtools
web_contents_->GetBrowserContext()); managed_devtools_web_contents_.reset(
devtools_web_contents_.reset(content::WebContents::Create(create_params)); content::WebContents::Create(
content::WebContents::CreateParams(
Observe(devtools_web_contents_.get()); web_contents_->GetBrowserContext())));
devtools_web_contents_->SetDelegate(this); managed_devtools_web_contents_->SetDelegate(this);
AttachTo(content::DevToolsAgentHost::GetOrCreateFor(web_contents_.get()));
devtools_web_contents_->GetController().LoadURL(
GetDevToolsURL(can_dock_),
content::Referrer(),
ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
std::string());
} else {
view_->ShowDevTools();
} }
Observe(GetDevToolsWebContents());
AttachTo(content::DevToolsAgentHost::GetOrCreateFor(web_contents_.get()));
GetDevToolsWebContents()->GetController().LoadURL(
GetDevToolsURL(can_dock_),
content::Referrer(),
ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
std::string());
} }
void InspectableWebContentsImpl::CloseDevTools() { void InspectableWebContentsImpl::CloseDevTools() {
if (devtools_web_contents_) { if (GetDevToolsWebContents()) {
frontend_loaded_ = false; frontend_loaded_ = false;
view_->CloseDevTools(); if (managed_devtools_web_contents_) {
devtools_web_contents_.reset(); view_->CloseDevTools();
managed_devtools_web_contents_.reset();
}
embedder_message_dispatcher_.reset();
web_contents_->Focus(); web_contents_->Focus();
} }
} }
bool InspectableWebContentsImpl::IsDevToolsViewShowing() { bool InspectableWebContentsImpl::IsDevToolsViewShowing() {
return devtools_web_contents_ && view_->IsDevToolsViewShowing(); return managed_devtools_web_contents_ && view_->IsDevToolsViewShowing();
} }
void InspectableWebContentsImpl::AttachTo( void InspectableWebContentsImpl::AttachTo(
@ -347,7 +364,7 @@ void InspectableWebContentsImpl::CallClientFunction(
const base::Value* arg1, const base::Value* arg1,
const base::Value* arg2, const base::Value* arg2,
const base::Value* arg3) { const base::Value* arg3) {
if (!devtools_web_contents_) if (!GetDevToolsWebContents())
return; return;
std::string javascript = function_name + "("; std::string javascript = function_name + "(";
@ -365,7 +382,7 @@ void InspectableWebContentsImpl::CallClientFunction(
} }
} }
javascript.append(");"); javascript.append(");");
devtools_web_contents_->GetMainFrame()->ExecuteJavaScript( GetDevToolsWebContents()->GetMainFrame()->ExecuteJavaScript(
base::UTF8ToUTF16(javascript)); base::UTF8ToUTF16(javascript));
} }
@ -400,7 +417,8 @@ void InspectableWebContentsImpl::CloseWindow() {
void InspectableWebContentsImpl::LoadCompleted() { void InspectableWebContentsImpl::LoadCompleted() {
frontend_loaded_ = true; frontend_loaded_ = true;
view_->ShowDevTools(); if (managed_devtools_web_contents_)
view_->ShowDevTools();
// If the devtools can dock, "SetIsDocked" will be called by devtools itself. // If the devtools can dock, "SetIsDocked" will be called by devtools itself.
if (!can_dock_) { if (!can_dock_) {
@ -415,7 +433,7 @@ void InspectableWebContentsImpl::LoadCompleted() {
} }
base::string16 javascript = base::UTF8ToUTF16( base::string16 javascript = base::UTF8ToUTF16(
"Components.dockController.setDockSide(\"" + dock_state_ + "\");"); "Components.dockController.setDockSide(\"" + dock_state_ + "\");");
devtools_web_contents_->GetMainFrame()->ExecuteJavaScript(javascript); GetDevToolsWebContents()->GetMainFrame()->ExecuteJavaScript(javascript);
} }
if (view_->GetDelegate()) if (view_->GetDelegate())
@ -428,15 +446,17 @@ void InspectableWebContentsImpl::SetInspectedPageBounds(const gfx::Rect& rect) {
return; return;
contents_resizing_strategy_.CopyFrom(strategy); contents_resizing_strategy_.CopyFrom(strategy);
view_->SetContentsResizingStrategy(contents_resizing_strategy_); if (managed_devtools_web_contents_)
view_->SetContentsResizingStrategy(contents_resizing_strategy_);
} }
void InspectableWebContentsImpl::InspectElementCompleted() { void InspectableWebContentsImpl::InspectElementCompleted() {
} }
void InspectableWebContentsImpl::InspectedURLChanged(const std::string& url) { void InspectableWebContentsImpl::InspectedURLChanged(const std::string& url) {
view_->SetTitle(base::UTF8ToUTF16(base::StringPrintf(kTitleFormat, if (managed_devtools_web_contents_)
url.c_str()))); view_->SetTitle(base::UTF8ToUTF16(base::StringPrintf(kTitleFormat,
url.c_str())));
} }
void InspectableWebContentsImpl::LoadNetworkResource( void InspectableWebContentsImpl::LoadNetworkResource(
@ -452,8 +472,8 @@ void InspectableWebContentsImpl::LoadNetworkResource(
return; return;
} }
auto browser_context = auto* browser_context = static_cast<BrowserContext*>(
static_cast<BrowserContext*>(devtools_web_contents_->GetBrowserContext()); GetDevToolsWebContents()->GetBrowserContext());
net::URLFetcher* fetcher = net::URLFetcher* fetcher =
(net::URLFetcher::Create(gurl, net::URLFetcher::GET, this)).release(); (net::URLFetcher::Create(gurl, net::URLFetcher::GET, this)).release();
@ -468,7 +488,8 @@ void InspectableWebContentsImpl::LoadNetworkResource(
void InspectableWebContentsImpl::SetIsDocked(const DispatchCallback& callback, void InspectableWebContentsImpl::SetIsDocked(const DispatchCallback& callback,
bool docked) { bool docked) {
view_->SetIsDocked(docked); if (managed_devtools_web_contents_)
view_->SetIsDocked(docked);
if (!callback.is_null()) if (!callback.is_null())
callback.Run(nullptr); callback.Run(nullptr);
} }
@ -640,7 +661,7 @@ void InspectableWebContentsImpl::DispatchProtocolMessage(
if (message.length() < kMaxMessageChunkSize) { if (message.length() < kMaxMessageChunkSize) {
base::string16 javascript = base::UTF8ToUTF16( base::string16 javascript = base::UTF8ToUTF16(
"DevToolsAPI.dispatchMessage(" + message + ");"); "DevToolsAPI.dispatchMessage(" + message + ");");
devtools_web_contents_->GetMainFrame()->ExecuteJavaScript(javascript); GetDevToolsWebContents()->GetMainFrame()->ExecuteJavaScript(javascript);
return; return;
} }
@ -664,13 +685,15 @@ void InspectableWebContentsImpl::RenderFrameHostChanged(
frontend_host_.reset(content::DevToolsFrontendHost::Create( frontend_host_.reset(content::DevToolsFrontendHost::Create(
new_host, new_host,
base::Bind(&InspectableWebContentsImpl::HandleMessageFromDevToolsFrontend, base::Bind(&InspectableWebContentsImpl::HandleMessageFromDevToolsFrontend,
base::Unretained(this)))); weak_factory_.GetWeakPtr())));
} }
void InspectableWebContentsImpl::WebContentsDestroyed() { void InspectableWebContentsImpl::WebContentsDestroyed() {
frontend_loaded_ = false; frontend_loaded_ = false;
external_devtools_web_contents_ = nullptr;
Observe(nullptr); Observe(nullptr);
Detach(); Detach();
embedder_message_dispatcher_.reset();
for (const auto& pair : pending_requests_) for (const auto& pair : pending_requests_)
delete pair.first; delete pair.first;
@ -758,7 +781,7 @@ void InspectableWebContentsImpl::ReadyToCommitNavigation(
content::NavigationHandle* navigation_handle) { content::NavigationHandle* navigation_handle) {
if (navigation_handle->IsInMainFrame()) { if (navigation_handle->IsInMainFrame()) {
if (navigation_handle->GetRenderFrameHost() == if (navigation_handle->GetRenderFrameHost() ==
devtools_web_contents_->GetMainFrame() && GetDevToolsWebContents()->GetMainFrame() &&
frontend_host_) { frontend_host_) {
return; return;
} }

View file

@ -48,6 +48,7 @@ class InspectableWebContentsImpl :
void SetDelegate(InspectableWebContentsDelegate* delegate) override; void SetDelegate(InspectableWebContentsDelegate* delegate) override;
InspectableWebContentsDelegate* GetDelegate() const override; InspectableWebContentsDelegate* GetDelegate() const override;
void SetDevToolsWebContents(content::WebContents* devtools) override;
void SetDockState(const std::string& state) override; void SetDockState(const std::string& state) override;
void ShowDevTools() override; void ShowDevTools() override;
void CloseDevTools() override; void CloseDevTools() override;
@ -192,7 +193,13 @@ class InspectableWebContentsImpl :
PrefService* pref_service_; // weak reference. PrefService* pref_service_; // weak reference.
std::unique_ptr<content::WebContents> web_contents_; std::unique_ptr<content::WebContents> web_contents_;
std::unique_ptr<content::WebContents> devtools_web_contents_;
// The default devtools created by this class when we don't have an external
// one assigned by SetDevToolsWebContents.
std::unique_ptr<content::WebContents> managed_devtools_web_contents_;
// The external devtools assigned by SetDevToolsWebContents.
content::WebContents* external_devtools_web_contents_ = nullptr;
std::unique_ptr<InspectableWebContentsView> view_; std::unique_ptr<InspectableWebContentsView> view_;
using ExtensionsAPIs = std::map<std::string, std::string>; using ExtensionsAPIs = std::map<std::string, std::string>;