diff --git a/cef.gyp b/cef.gyp index 801189c02..354895b15 100644 --- a/cef.gyp +++ b/cef.gyp @@ -831,6 +831,8 @@ 'libcef/browser/cookie_manager_impl.h', 'libcef/browser/devtools_delegate.cc', 'libcef/browser/devtools_delegate.h', + 'libcef/browser/devtools_frontend.cc', + 'libcef/browser/devtools_frontend.h', 'libcef/browser/devtools_scheme_handler.cc', 'libcef/browser/devtools_scheme_handler.h', 'libcef/browser/download_item_impl.cc', diff --git a/include/capi/cef_browser_capi.h b/include/capi/cef_browser_capi.h index 626a63f36..4eb433e41 100644 --- a/include/capi/cef_browser_capi.h +++ b/include/capi/cef_browser_capi.h @@ -341,6 +341,20 @@ typedef struct _cef_browser_host_t { void (CEF_CALLBACK *stop_finding)(struct _cef_browser_host_t* self, int clearSelection); + /// + // Open developer tools in its own window. + /// + void (CEF_CALLBACK *show_dev_tools)(struct _cef_browser_host_t* self, + const struct _cef_window_info_t* windowInfo, + struct _cef_client_t* client, + const struct _cef_browser_settings_t* settings); + + /// + // Explicitly close the developer tools window if one exists for this browser + // instance. + /// + void (CEF_CALLBACK *close_dev_tools)(struct _cef_browser_host_t* self); + /// // Set whether mouse cursor change is disabled. /// diff --git a/include/cef_browser.h b/include/cef_browser.h index 50f7fb255..4e2a9f380 100644 --- a/include/cef_browser.h +++ b/include/cef_browser.h @@ -389,6 +389,21 @@ class CefBrowserHost : public virtual CefBase { /*--cef()--*/ virtual void StopFinding(bool clearSelection) =0; + /// + // Open developer tools in its own window. + /// + /*--cef()--*/ + virtual void ShowDevTools(const CefWindowInfo& windowInfo, + CefRefPtr client, + const CefBrowserSettings& settings) =0; + + /// + // Explicitly close the developer tools window if one exists for this browser + // instance. + /// + /*--cef()--*/ + virtual void CloseDevTools() =0; + /// // Set whether mouse cursor change is disabled. /// diff --git a/libcef/browser/browser_host_impl.cc b/libcef/browser/browser_host_impl.cc index e8cda15b9..f6d60d381 100644 --- a/libcef/browser/browser_host_impl.cc +++ b/libcef/browser/browser_host_impl.cc @@ -15,6 +15,7 @@ #include "libcef/browser/content_browser_client.h" #include "libcef/browser/context.h" #include "libcef/browser/devtools_delegate.h" +#include "libcef/browser/devtools_frontend.h" #include "libcef/browser/media_capture_devices_dispatcher.h" #include "libcef/browser/navigate_params.h" #include "libcef/browser/printing/print_view_manager.h" @@ -79,6 +80,29 @@ void CreateBrowserWithHelper(CreateBrowserHelper* helper) { delete helper; } +class ShowDevToolsHelper { + public: + ShowDevToolsHelper(CefRefPtr browser, + const CefWindowInfo& windowInfo, + CefRefPtr client, + const CefBrowserSettings& settings) + : browser_(browser), + window_info_(windowInfo), + client_(client), + settings_(settings) {} + + CefRefPtr browser_; + CefWindowInfo window_info_; + CefRefPtr client_; + CefBrowserSettings settings_; +}; + +void ShowDevToolsWithHelper(ShowDevToolsHelper* helper) { + helper->browser_->ShowDevTools(helper->window_info_, helper->client_, + helper->settings_); + delete helper; +} + // Convert a NativeWebKeyboardEvent to a CefKeyEvent. bool GetCefKeyEvent(const content::NativeWebKeyboardEvent& event, CefKeyEvent& cef_event) { @@ -286,6 +310,25 @@ CefRefPtr CefBrowserHost::CreateBrowserSync( return NULL; } + CefRefPtr browser = + CefBrowserHostImpl::Create(windowInfo, client, url, settings, NULL, false, + request_context); + return browser.get(); +} + + +// CefBrowserHostImpl static methods. +// ----------------------------------------------------------------------------- + +// static +CefRefPtr CefBrowserHostImpl::Create( + const CefWindowInfo& windowInfo, + CefRefPtr client, + const CefString& url, + const CefBrowserSettings& settings, + CefWindowHandle opener, + bool is_popup, + CefRefPtr request_context) { CefBrowserSettings new_settings = settings; // Verify that render handler is in place for a windowless browser. @@ -305,14 +348,13 @@ CefRefPtr CefBrowserHost::CreateBrowserSync( CefBrowserHostImpl::IsWindowRenderingDisabled(windowInfo)); scoped_refptr info = - CefContentBrowserClient::Get()->CreateBrowserInfo(); + CefContentBrowserClient::Get()->CreateBrowserInfo(is_popup); info->set_window_rendering_disabled( CefBrowserHostImpl::IsWindowRenderingDisabled(windowInfo)); - DCHECK(!info->is_popup()); CefRefPtr browser = - CefBrowserHostImpl::Create(windowInfo, new_settings, client, NULL, info, - NULL, request_context); + CefBrowserHostImpl::CreateInternal(windowInfo, new_settings, client, NULL, + info, opener, request_context); if (!url.empty()) { browser->LoadURL(CefFrameHostImpl::kMainFrameId, url, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string()); @@ -320,15 +362,8 @@ CefRefPtr CefBrowserHost::CreateBrowserSync( return browser.get(); } - -// CefBrowserHostImpl static methods. -// ----------------------------------------------------------------------------- - -CefBrowserHostImpl::~CefBrowserHostImpl() { -} - // static -CefRefPtr CefBrowserHostImpl::Create( +CefRefPtr CefBrowserHostImpl::CreateInternal( const CefWindowInfo& window_info, const CefBrowserSettings& settings, CefRefPtr client, @@ -445,9 +480,35 @@ CefRefPtr CefBrowserHostImpl::GetBrowserByRoutingID( } -// CefBrowserHost methods. +// CefBrowserHostImpl methods. // ----------------------------------------------------------------------------- +// WebContentsObserver that will be notified when the frontend WebContents is +// destroyed so that the inspected browser can clear its DevTools references. +class CefBrowserHostImpl::DevToolsWebContentsObserver : + public content::WebContentsObserver { + public: + DevToolsWebContentsObserver(CefBrowserHostImpl* browser, + content::WebContents* frontend_web_contents) + : WebContentsObserver(frontend_web_contents), + browser_(browser) { + } + + // WebContentsObserver methods: + virtual void WebContentsDestroyed( + content::WebContents* web_contents) OVERRIDE { + browser_->OnDevToolsWebContentsDestroyed(); + } + + private: + CefBrowserHostImpl* browser_; + + DISALLOW_COPY_AND_ASSIGN(DevToolsWebContentsObserver); +}; + +CefBrowserHostImpl::~CefBrowserHostImpl() { +} + CefRefPtr CefBrowserHostImpl::GetBrowser() { return this; } @@ -650,6 +711,43 @@ void CefBrowserHostImpl::StopFinding(bool clearSelection) { } } +void CefBrowserHostImpl::ShowDevTools( + const CefWindowInfo& windowInfo, + CefRefPtr client, + const CefBrowserSettings& settings) { + if (CEF_CURRENTLY_ON_UIT()) { + if (!web_contents_) + return; + + if (devtools_frontend_) { + devtools_frontend_->Focus(); + return; + } + + devtools_frontend_ = CefDevToolsFrontend::Show( + this, windowInfo, client, settings); + devtools_observer_.reset(new DevToolsWebContentsObserver( + this, devtools_frontend_->frontend_browser()->web_contents())); + } else { + ShowDevToolsHelper* helper = + new ShowDevToolsHelper(this, windowInfo, client, settings); + CEF_POST_TASK(CEF_UIT, base::Bind(ShowDevToolsWithHelper, helper)); + } +} + +void CefBrowserHostImpl::CloseDevTools() { + if (CEF_CURRENTLY_ON_UIT()) { + if (!devtools_frontend_) + return; + devtools_observer_.reset(); + devtools_frontend_->Close(); + devtools_frontend_ = NULL; + } else { + CEF_POST_TASK(CEF_UIT, + base::Bind(&CefBrowserHostImpl::CloseDevTools, this)); + } +} + void CefBrowserHostImpl::SetMouseCursorChangeDisabled(bool disabled) { base::AutoLock lock_scope(state_lock_); mouse_cursor_change_disabled_ = disabled; @@ -1737,9 +1835,11 @@ void CefBrowserHostImpl::WebContentsCreated( DCHECK(!info->is_popup()); } - CefRefPtr browser = CefBrowserHostImpl::Create( - pending_popup_info->window_info, pending_popup_info->settings, - pending_popup_info->client, new_contents, info, opener, NULL); + CefRefPtr browser = + CefBrowserHostImpl::CreateInternal(pending_popup_info->window_info, + pending_popup_info->settings, + pending_popup_info->client, + new_contents, info, opener, NULL); } void CefBrowserHostImpl::DidNavigateMainFramePostCommit( @@ -2136,6 +2236,7 @@ CefBrowserHostImpl::CefBrowserHostImpl( is_in_onsetfocus_(false), focus_on_editable_field_(false), mouse_cursor_change_disabled_(false), + devtools_frontend_(NULL), file_chooser_pending_(false) { DCHECK(!browser_info_->browser().get()); browser_info_->set_browser(this); @@ -2440,3 +2541,8 @@ void CefBrowserHostImpl::OnRunFileChooserDelegateCallback( // Notify our RenderViewHost in all cases. render_view_host->FilesSelectedInChooser(selected_files, mode); } + +void CefBrowserHostImpl::OnDevToolsWebContentsDestroyed() { + devtools_observer_.reset(); + devtools_frontend_ = NULL; +} diff --git a/libcef/browser/browser_host_impl.h b/libcef/browser/browser_host_impl.h index d32de2d48..ff2d80bbd 100644 --- a/libcef/browser/browser_host_impl.h +++ b/libcef/browser/browser_host_impl.h @@ -47,6 +47,7 @@ class URLRequest; struct Cef_Request_Params; struct Cef_Response_Params; class CefBrowserInfo; +class CefDevToolsFrontend; struct CefNavigateParams; class SiteInstance; @@ -81,12 +82,12 @@ class CefBrowserHostImpl : public CefBrowserHost, // Create a new CefBrowserHostImpl instance. static CefRefPtr Create( - const CefWindowInfo& window_info, - const CefBrowserSettings& settings, + const CefWindowInfo& windowInfo, CefRefPtr client, - content::WebContents* web_contents, - scoped_refptr browser_info, + const CefString& url, + const CefBrowserSettings& settings, CefWindowHandle opener, + bool is_popup, CefRefPtr request_context); // Returns the browser associated with the specified RenderViewHost. @@ -128,6 +129,10 @@ class CefBrowserHostImpl : public CefBrowserHost, virtual void Find(int identifier, const CefString& searchText, bool forward, bool matchCase, bool findNext) OVERRIDE; virtual void StopFinding(bool clearSelection) OVERRIDE; + virtual void ShowDevTools(const CefWindowInfo& windowInfo, + CefRefPtr client, + const CefBrowserSettings& settings) OVERRIDE; + virtual void CloseDevTools() OVERRIDE; virtual void SetMouseCursorChangeDisabled(bool disabled) OVERRIDE; virtual bool IsMouseCursorChangeDisabled() OVERRIDE; virtual bool IsWindowRenderingDisabled() OVERRIDE; @@ -274,6 +279,17 @@ class CefBrowserHostImpl : public CefBrowserHost, DestructionState destruction_state() const { return destruction_state_; } private: + class DevToolsWebContentsObserver; + + static CefRefPtr CreateInternal( + const CefWindowInfo& window_info, + const CefBrowserSettings& settings, + CefRefPtr client, + content::WebContents* web_contents, + scoped_refptr browser_info, + CefWindowHandle opener, + CefRefPtr request_context); + // content::WebContentsDelegate methods. virtual content::WebContents* OpenURLFromTab( content::WebContents* source, @@ -481,6 +497,8 @@ class CefBrowserHostImpl : public CefBrowserHost, content::FileChooserParams::Mode mode, const std::vector& file_paths); + void OnDevToolsWebContentsDestroyed(); + CefWindowInfo window_info_; CefBrowserSettings settings_; CefRefPtr client_; @@ -551,6 +569,13 @@ class CefBrowserHostImpl : public CefBrowserHost, // Used for creating and managing context menus. scoped_ptr menu_creator_; + // Track the lifespan of the frontend WebContents associated with this + // browser. + scoped_ptr devtools_observer_; + // CefDevToolsFrontend will delete itself when the frontend WebContents is + // destroyed. + CefDevToolsFrontend* devtools_frontend_; + // True if a file chooser is currently pending. bool file_chooser_pending_; diff --git a/libcef/browser/content_browser_client.cc b/libcef/browser/content_browser_client.cc index a1afcaada..e8ad6f6f4 100644 --- a/libcef/browser/content_browser_client.cc +++ b/libcef/browser/content_browser_client.cc @@ -301,11 +301,12 @@ CefContentBrowserClient* CefContentBrowserClient::Get() { CefContentClient::Get()->browser()); } -scoped_refptr CefContentBrowserClient::CreateBrowserInfo() { +scoped_refptr CefContentBrowserClient::CreateBrowserInfo( + bool is_popup) { base::AutoLock lock_scope(browser_info_lock_); scoped_refptr browser_info = - new CefBrowserInfo(++next_browser_id_, false); + new CefBrowserInfo(++next_browser_id_, is_popup); browser_info_list_.push_back(browser_info); return browser_info; } diff --git a/libcef/browser/content_browser_client.h b/libcef/browser/content_browser_client.h index 21b96198a..03c979592 100644 --- a/libcef/browser/content_browser_client.h +++ b/libcef/browser/content_browser_client.h @@ -50,7 +50,7 @@ class CefContentBrowserClient : public content::ContentBrowserClient { // to CefBrowserHostImpl::ShouldCreateWebContents on the UI thread. To resolve // this race CefBrowserInfo may be created when requested for the first time // and before the associated CefBrowserHostImpl is created. - scoped_refptr CreateBrowserInfo(); + scoped_refptr CreateBrowserInfo(bool is_popup); scoped_refptr GetOrCreateBrowserInfo(int render_process_id, int render_view_id); void RemoveBrowserInfo(scoped_refptr browser_info); diff --git a/libcef/browser/devtools_delegate.cc b/libcef/browser/devtools_delegate.cc index f2bce89db..944186300 100644 --- a/libcef/browser/devtools_delegate.cc +++ b/libcef/browser/devtools_delegate.cc @@ -1,6 +1,6 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. +// Copyright 2013 the Chromium Embedded Framework Authors. Portions Copyright +// 2012 The Chromium Authors. All rights reserved. Use of this source code is +// governed by a BSD-style license that can be found in the LICENSE file. #include "libcef/browser/devtools_delegate.h" #include "libcef/browser/devtools_scheme_handler.h" @@ -186,6 +186,11 @@ scoped_ptr return scoped_ptr(); } +std::string CefDevToolsDelegate::GetChromeDevToolsURL() { + return base::StringPrintf("%s://%s/devtools.html", + chrome::kChromeDevToolsScheme, scheme::kChromeDevToolsHost); +} + std::string CefDevToolsDelegate::GetDevToolsURL(content::RenderViewHost* rvh, bool http_scheme) { const CommandLine& command_line = *CommandLine::ForCurrentProcess(); @@ -202,7 +207,7 @@ std::string CefDevToolsDelegate::GetDevToolsURL(content::RenderViewHost* rvh, const std::string& page_id = agent_host->GetId(); const std::string& host = http_scheme ? base::StringPrintf("http://localhost:%d/devtools/", port) : - base::StringPrintf("%s://%s/devtools/", chrome::kChromeDevToolsScheme, + base::StringPrintf("%s://%s/", chrome::kChromeDevToolsScheme, scheme::kChromeDevToolsHost); return base::StringPrintf( diff --git a/libcef/browser/devtools_delegate.h b/libcef/browser/devtools_delegate.h index 8a5378ec4..bfedd8545 100644 --- a/libcef/browser/devtools_delegate.h +++ b/libcef/browser/devtools_delegate.h @@ -1,6 +1,6 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. +// Copyright 2013 the Chromium Embedded Framework Authors. Portions Copyright +// 2012 The Chromium Authors. All rights reserved. Use of this source code is +// governed by a BSD-style license that can be found in the LICENSE file. #ifndef CEF_LIBCEF_BROWSER_DEVTOOLS_DELEGATE_H_ #define CEF_LIBCEF_BROWSER_DEVTOOLS_DELEGATE_H_ @@ -42,6 +42,9 @@ class CefDevToolsDelegate : public content::DevToolsHttpHandlerDelegate { net::StreamListenSocket::Delegate* delegate, std::string* name) OVERRIDE; + // Returns the chrome-devtools URL. + std::string GetChromeDevToolsURL(); + // Returns the DevTools URL for the specified RenderViewHost. std::string GetDevToolsURL(content::RenderViewHost* rvh, bool http_scheme); diff --git a/libcef/browser/devtools_frontend.cc b/libcef/browser/devtools_frontend.cc new file mode 100644 index 000000000..5c497e732 --- /dev/null +++ b/libcef/browser/devtools_frontend.cc @@ -0,0 +1,93 @@ +// Copyright 2013 the Chromium Embedded Framework Authors. Portions Copyright +// 2012 The Chromium Authors. All rights reserved. Use of this source code is +// governed by a BSD-style license that can be found in the LICENSE file. + +#include "libcef/browser/devtools_frontend.h" + +#include "libcef/browser/content_browser_client.h" +#include "libcef/browser/devtools_delegate.h" +#include "libcef/browser/request_context_impl.h" + +#include "base/command_line.h" +#include "base/path_service.h" +#include "content/public/browser/devtools_http_handler.h" +#include "content/public/browser/devtools_manager.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_view.h" +#include "content/public/common/content_client.h" +#include "net/base/net_util.h" + +// static +CefDevToolsFrontend* CefDevToolsFrontend::Show( + CefRefPtr inspected_browser, + const CefWindowInfo& windowInfo, + CefRefPtr client, + const CefBrowserSettings& settings) { + CefRefPtr frontend_browser = + CefBrowserHostImpl::Create(windowInfo, client, CefString(), + settings, + inspected_browser->GetWindowHandle(), true, + inspected_browser->GetRequestContext()); + + // CefDevToolsFrontend will delete itself when the frontend WebContents is + // destroyed. + CefDevToolsFrontend* devtools_frontend = new CefDevToolsFrontend( + static_cast(frontend_browser.get()), + content::DevToolsAgentHost::GetOrCreateFor( + inspected_browser->GetWebContents()->GetRenderViewHost()).get()); + + // Need to load the URL after creating the DevTools objects. + CefDevToolsDelegate* delegate = + CefContentBrowserClient::Get()->devtools_delegate(); + frontend_browser->GetMainFrame()->LoadURL(delegate->GetChromeDevToolsURL()); + + devtools_frontend->Activate(); + devtools_frontend->Focus(); + + return devtools_frontend; +} + +void CefDevToolsFrontend::Activate() { + frontend_browser_->ActivateContents(web_contents()); +} + +void CefDevToolsFrontend::Focus() { + web_contents()->GetView()->Focus(); +} + +void CefDevToolsFrontend::Close() { + frontend_browser_->CloseBrowser(true); +} + +CefDevToolsFrontend::CefDevToolsFrontend( + CefRefPtr frontend_browser, + content::DevToolsAgentHost* agent_host) + : WebContentsObserver(frontend_browser->GetWebContents()), + frontend_browser_(frontend_browser), + agent_host_(agent_host) { + frontend_host_.reset( + content::DevToolsClientHost::CreateDevToolsFrontendHost( + web_contents(), this)); +} + +CefDevToolsFrontend::~CefDevToolsFrontend() { +} + +void CefDevToolsFrontend::RenderViewCreated( + content::RenderViewHost* render_view_host) { + content::DevToolsClientHost::SetupDevToolsFrontendClient( + web_contents()->GetRenderViewHost()); + content::DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor( + agent_host_.get(), frontend_host_.get()); +} + +void CefDevToolsFrontend::WebContentsDestroyed( + content::WebContents* web_contents) { + content::DevToolsManager::GetInstance()->ClientHostClosing( + frontend_host_.get()); + delete this; +} + +void CefDevToolsFrontend::InspectedContentsClosing() { + Close(); +} diff --git a/libcef/browser/devtools_frontend.h b/libcef/browser/devtools_frontend.h new file mode 100644 index 000000000..6d43efa9b --- /dev/null +++ b/libcef/browser/devtools_frontend.h @@ -0,0 +1,64 @@ +// Copyright 2013 the Chromium Embedded Framework Authors. Portions Copyright +// 2012 The Chromium Authors. All rights reserved. Use of this source code is +// governed by a BSD-style license that can be found in the LICENSE file. + +#ifndef CEF_LIBCEF_BROWSER_DEVTOOLS_FRONTEND_H_ +#define CEF_LIBCEF_BROWSER_DEVTOOLS_FRONTEND_H_ + +#include "libcef/browser/browser_host_impl.h" + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "content/public/browser/devtools_agent_host.h" +#include "content/public/browser/devtools_client_host.h" +#include "content/public/browser/devtools_frontend_host_delegate.h" +#include "content/public/browser/web_contents_observer.h" + +namespace content { +class RenderViewHost; +class WebContents; +} + +class CefDevToolsFrontend : public content::WebContentsObserver, + public content::DevToolsFrontendHostDelegate { + public: + static CefDevToolsFrontend* Show( + CefRefPtr inspected_browser, + const CefWindowInfo& windowInfo, + CefRefPtr client, + const CefBrowserSettings& settings); + + void Activate(); + void Focus(); + void Close(); + + CefRefPtr frontend_browser() const { + return frontend_browser_; + } + + private: + CefDevToolsFrontend(CefRefPtr frontend_browser, + content::DevToolsAgentHost* agent_host); + virtual ~CefDevToolsFrontend(); + + // WebContentsObserver overrides + virtual void RenderViewCreated( + content::RenderViewHost* render_view_host) OVERRIDE; + virtual void WebContentsDestroyed( + content::WebContents* web_contents) OVERRIDE; + + // DevToolsFrontendHostDelegate implementation + virtual void DispatchOnEmbedder(const std::string& message) OVERRIDE {} + + virtual void InspectedContentsClosing() OVERRIDE; + + CefRefPtr frontend_browser_; + scoped_refptr agent_host_; + scoped_ptr frontend_host_; + + DISALLOW_COPY_AND_ASSIGN(CefDevToolsFrontend); +}; + +#endif // CEF_LIBCEF_BROWSER_DEVTOOLS_FRONTEND_H_ diff --git a/libcef/common/scheme_registration.cc b/libcef/common/scheme_registration.cc index 86e06b311..0cd391a7e 100644 --- a/libcef/common/scheme_registration.cc +++ b/libcef/common/scheme_registration.cc @@ -12,7 +12,7 @@ namespace scheme { void AddInternalSchemes(std::vector* standard_schemes) { static CefContentClient::SchemeInfo schemes[] = { { chrome::kChromeUIScheme, true, true, true }, - { chrome::kChromeDevToolsScheme, true, true, false } + { chrome::kChromeDevToolsScheme, true, false, true } }; CefContentClient* client = CefContentClient::Get(); diff --git a/libcef_dll/cpptoc/browser_host_cpptoc.cc b/libcef_dll/cpptoc/browser_host_cpptoc.cc index e45cdc3ae..d2d03d88c 100644 --- a/libcef_dll/cpptoc/browser_host_cpptoc.cc +++ b/libcef_dll/cpptoc/browser_host_cpptoc.cc @@ -348,6 +348,55 @@ void CEF_CALLBACK browser_host_stop_finding(struct _cef_browser_host_t* self, clearSelection?true:false); } +void CEF_CALLBACK browser_host_show_dev_tools(struct _cef_browser_host_t* self, + const cef_window_info_t* windowInfo, struct _cef_client_t* client, + const struct _cef_browser_settings_t* settings) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: windowInfo; type: struct_byref_const + DCHECK(windowInfo); + if (!windowInfo) + return; + // Verify param: client; type: refptr_diff + DCHECK(client); + if (!client) + return; + // Verify param: settings; type: struct_byref_const + DCHECK(settings); + if (!settings) + return; + + // Translate param: windowInfo; type: struct_byref_const + CefWindowInfo windowInfoObj; + if (windowInfo) + windowInfoObj.Set(*windowInfo, false); + // Translate param: settings; type: struct_byref_const + CefBrowserSettings settingsObj; + if (settings) + settingsObj.Set(*settings, false); + + // Execute + CefBrowserHostCppToC::Get(self)->ShowDevTools( + windowInfoObj, + CefClientCToCpp::Wrap(client), + settingsObj); +} + +void CEF_CALLBACK browser_host_close_dev_tools( + struct _cef_browser_host_t* self) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + + // Execute + CefBrowserHostCppToC::Get(self)->CloseDevTools(); +} + void CEF_CALLBACK browser_host_set_mouse_cursor_change_disabled( struct _cef_browser_host_t* self, int disabled) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING @@ -635,6 +684,8 @@ CefBrowserHostCppToC::CefBrowserHostCppToC(CefBrowserHost* cls) struct_.struct_.print = browser_host_print; struct_.struct_.find = browser_host_find; struct_.struct_.stop_finding = browser_host_stop_finding; + struct_.struct_.show_dev_tools = browser_host_show_dev_tools; + struct_.struct_.close_dev_tools = browser_host_close_dev_tools; struct_.struct_.set_mouse_cursor_change_disabled = browser_host_set_mouse_cursor_change_disabled; struct_.struct_.is_mouse_cursor_change_disabled = diff --git a/libcef_dll/ctocpp/browser_host_ctocpp.cc b/libcef_dll/ctocpp/browser_host_ctocpp.cc index f55f230ec..8ded3a83e 100644 --- a/libcef_dll/ctocpp/browser_host_ctocpp.cc +++ b/libcef_dll/ctocpp/browser_host_ctocpp.cc @@ -292,6 +292,35 @@ void CefBrowserHostCToCpp::StopFinding(bool clearSelection) { clearSelection); } +void CefBrowserHostCToCpp::ShowDevTools(const CefWindowInfo& windowInfo, + CefRefPtr client, const CefBrowserSettings& settings) { + if (CEF_MEMBER_MISSING(struct_, show_dev_tools)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: client; type: refptr_diff + DCHECK(client.get()); + if (!client.get()) + return; + + // Execute + struct_->show_dev_tools(struct_, + &windowInfo, + CefClientCppToC::Wrap(client), + &settings); +} + +void CefBrowserHostCToCpp::CloseDevTools() { + if (CEF_MEMBER_MISSING(struct_, close_dev_tools)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + struct_->close_dev_tools(struct_); +} + void CefBrowserHostCToCpp::SetMouseCursorChangeDisabled(bool disabled) { if (CEF_MEMBER_MISSING(struct_, set_mouse_cursor_change_disabled)) return; diff --git a/libcef_dll/ctocpp/browser_host_ctocpp.h b/libcef_dll/ctocpp/browser_host_ctocpp.h index 40d7fd162..23dc9f217 100644 --- a/libcef_dll/ctocpp/browser_host_ctocpp.h +++ b/libcef_dll/ctocpp/browser_host_ctocpp.h @@ -57,6 +57,10 @@ class CefBrowserHostCToCpp virtual void Find(int identifier, const CefString& searchText, bool forward, bool matchCase, bool findNext) OVERRIDE; virtual void StopFinding(bool clearSelection) OVERRIDE; + virtual void ShowDevTools(const CefWindowInfo& windowInfo, + CefRefPtr client, + const CefBrowserSettings& settings) OVERRIDE; + virtual void CloseDevTools() OVERRIDE; virtual void SetMouseCursorChangeDisabled(bool disabled) OVERRIDE; virtual bool IsMouseCursorChangeDisabled() OVERRIDE; virtual bool IsWindowRenderingDisabled() OVERRIDE; diff --git a/tests/cefclient/client_handler.cpp b/tests/cefclient/client_handler.cpp index fe5e8b8b2..ef2b4f705 100644 --- a/tests/cefclient/client_handler.cpp +++ b/tests/cefclient/client_handler.cpp @@ -33,6 +33,7 @@ namespace { // Custom menu command Ids. enum client_menu_ids { CLIENT_ID_SHOW_DEVTOOLS = MENU_ID_USER_FIRST, + CLIENT_ID_CLOSE_DEVTOOLS, CLIENT_ID_TESTMENU_SUBMENU, CLIENT_ID_TESTMENU_CHECKITEM, CLIENT_ID_TESTMENU_RADIOITEM1, @@ -108,12 +109,6 @@ ClientHandler::ClientHandler() if (m_StartupURL.empty()) m_StartupURL = "http://www.google.com/"; - // Also use external dev tools if off-screen rendering is enabled since we - // disallow popup windows. - m_bExternalDevTools = - command_line->HasSwitch(cefclient::kExternalDevTools) || - AppIsOffScreenRenderingEnabled(); - m_bMouseCursorChangeDisabled = command_line->HasSwitch(cefclient::kMouseCursorChangeDisabled); } @@ -158,16 +153,9 @@ void ClientHandler::OnBeforeContextMenu( if (model->GetCount() > 0) model->AddSeparator(); - // Add a "Show DevTools" item to all context menus. + // Add DevTools items to all context menus. model->AddItem(CLIENT_ID_SHOW_DEVTOOLS, "&Show DevTools"); - - CefString devtools_url = browser->GetHost()->GetDevToolsURL(true); - if (devtools_url.empty() || - m_OpenDevToolsURLs.find(devtools_url) != m_OpenDevToolsURLs.end()) { - // Disable the menu option if DevTools isn't enabled or if a window is - // already open for the current URL. - model->SetEnabled(CLIENT_ID_SHOW_DEVTOOLS, false); - } + model->AddItem(CLIENT_ID_CLOSE_DEVTOOLS, "Close DevTools"); // Test context menu features. BuildTestMenu(model); @@ -184,6 +172,9 @@ bool ClientHandler::OnContextMenuCommand( case CLIENT_ID_SHOW_DEVTOOLS: ShowDevTools(browser); return true; + case CLIENT_ID_CLOSE_DEVTOOLS: + CloseDevTools(browser); + return true; default: // Allow default handling, if any. return ExecuteTestMenu(command_id); } @@ -361,12 +352,6 @@ void ClientHandler::OnBeforeClose(CefRefPtr browser) { m_OSRHandler = NULL; } } else if (browser->IsPopup()) { - // Remove the record for DevTools popup windows. - std::set::iterator it = - m_OpenDevToolsURLs.find(browser->GetMainFrame()->GetURL()); - if (it != m_OpenDevToolsURLs.end()) - m_OpenDevToolsURLs.erase(it); - // Remove from the browser popup list. BrowserList::iterator bit = m_PopupBrowsers.begin(); for (; bit != m_PopupBrowsers.end(); ++bit) { @@ -615,42 +600,18 @@ std::string ClientHandler::GetLastDownloadFile() { } void ClientHandler::ShowDevTools(CefRefPtr browser) { - std::string devtools_url = browser->GetHost()->GetDevToolsURL(true); - if (!devtools_url.empty()) { - if (m_bExternalDevTools) { - // Open DevTools in an external browser window. - LaunchExternalBrowser(devtools_url); - } else if (m_OpenDevToolsURLs.find(devtools_url) == - m_OpenDevToolsURLs.end()) { - // Open DevTools in a popup window. - m_OpenDevToolsURLs.insert(devtools_url); - browser->GetMainFrame()->ExecuteJavaScript( - "window.open('" + devtools_url + "');", "about:blank", 0); - } - } + CefWindowInfo windowInfo; + CefBrowserSettings settings; + +#if defined(OS_WIN) + windowInfo.SetAsPopup(browser->GetHost()->GetWindowHandle(), "DevTools"); +#endif + + browser->GetHost()->ShowDevTools(windowInfo, this, settings); } -// static -void ClientHandler::LaunchExternalBrowser(const std::string& url) { - if (CefCurrentlyOn(TID_PROCESS_LAUNCHER)) { - // Retrieve the current executable path. - CefString file_exe; - if (!CefGetPath(PK_FILE_EXE, file_exe)) - return; - - // Create the command line. - CefRefPtr command_line = - CefCommandLine::CreateCommandLine(); - command_line->SetProgram(file_exe); - command_line->AppendSwitchWithValue(cefclient::kUrl, url); - - // Launch the process. - CefLaunchProcess(command_line); - } else { - // Execute on the PROCESS_LAUNCHER thread. - CefPostTask(TID_PROCESS_LAUNCHER, - NewCefRunnableFunction(&ClientHandler::LaunchExternalBrowser, url)); - } +void ClientHandler::CloseDevTools(CefRefPtr browser) { + browser->GetHost()->CloseDevTools(); } void ClientHandler::BeginTracing() { diff --git a/tests/cefclient/client_handler.h b/tests/cefclient/client_handler.h index f9b832a6a..a992948f2 100644 --- a/tests/cefclient/client_handler.h +++ b/tests/cefclient/client_handler.h @@ -250,13 +250,11 @@ class ClientHandler : public CefClient, void SendNotification(NotificationType type); void ShowDevTools(CefRefPtr browser); + void CloseDevTools(CefRefPtr browser); // Returns the startup URL. std::string GetStartupURL() { return m_StartupURL; } - // Create an external browser window that loads the specified URL. - static void LaunchExternalBrowser(const std::string& url); - void BeginTracing(); void EndTracing(); @@ -322,12 +320,6 @@ class ClientHandler : public CefClient, // Registered delegates. ProcessMessageDelegateSet process_message_delegates_; - // If true DevTools will be opened in an external browser window. - bool m_bExternalDevTools; - - // List of open DevTools URLs if not using an external browser window. - std::set m_OpenDevToolsURLs; - // The startup URL. std::string m_StartupURL; diff --git a/tests/cefclient/client_switches.cpp b/tests/cefclient/client_switches.cpp index 98c0a6901..2a946cd90 100644 --- a/tests/cefclient/client_switches.cpp +++ b/tests/cefclient/client_switches.cpp @@ -21,7 +21,6 @@ namespace cefclient { const char kMultiThreadedMessageLoop[] = "multi-threaded-message-loop"; const char kCachePath[] = "cache-path"; const char kUrl[] = "url"; -const char kExternalDevTools[] = "external-devtools"; const char kOffScreenRenderingEnabled[] = "off-screen-rendering-enabled"; const char kTransparentPaintingEnabled[] = "transparent-painting-enabled"; const char kMouseCursorChangeDisabled[] = "mouse-cursor-change-disabled"; diff --git a/tests/cefclient/client_switches.h b/tests/cefclient/client_switches.h index f69d67713..2bd4b768e 100644 --- a/tests/cefclient/client_switches.h +++ b/tests/cefclient/client_switches.h @@ -13,7 +13,6 @@ namespace cefclient { extern const char kMultiThreadedMessageLoop[]; extern const char kCachePath[]; extern const char kUrl[]; -extern const char kExternalDevTools[]; extern const char kOffScreenRenderingEnabled[]; extern const char kTransparentPaintingEnabled[]; extern const char kMouseCursorChangeDisabled[]; diff --git a/tests/unittests/v8_unittest.cc b/tests/unittests/v8_unittest.cc index efd9e24ca..0544fd0d1 100644 --- a/tests/unittests/v8_unittest.cc +++ b/tests/unittests/v8_unittest.cc @@ -30,8 +30,6 @@ const char kV8OnUncaughtExceptionTestUrl[] = const char kV8TestMsg[] = "V8Test.Test"; const char kV8TestCmdArg[] = "v8-test"; const char kV8RunTestMsg[] = "V8Test.RunTest"; -const char kV8DevToolsURLMsg[] = "V8Test.DevToolsURL"; -const char kV8DevToolsLoadHookMsg[] = "V8Test.DevToolsLoadHook"; enum V8TestMode { V8TEST_NONE = 0, @@ -103,11 +101,11 @@ class V8BrowserTest : public ClientApp::BrowserDelegate { // Renderer side. -class V8RendererTest : public ClientApp::RenderDelegate { +class V8RendererTest : public ClientApp::RenderDelegate, + public CefLoadHandler { public: V8RendererTest() - : test_mode_(V8TEST_NONE), - devtools_url_("") { + : test_mode_(V8TEST_NONE) { } // Run a test when the process message is received from the browser. @@ -225,9 +223,6 @@ class V8RendererTest : public ClientApp::RenderDelegate { case V8TEST_ON_UNCAUGHT_EXCEPTION: RunOnUncaughtExceptionTest(); break; - case V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS: - RunOnUncaughtExceptionDevToolsTest(); - break; default: // Was a startup test. EXPECT_TRUE(startup_test_success_); @@ -1667,17 +1662,6 @@ class V8RendererTest : public ClientApp::RenderDelegate { "window.setTimeout(test, 0)", browser_->GetMainFrame()->GetURL(), 0); } - void RunOnUncaughtExceptionDevToolsTest() { - EXPECT_FALSE(browser_->IsPopup()); - test_context_ = - browser_->GetMainFrame()->GetV8Context(); - // Show DevTools. - EXPECT_FALSE(devtools_url_.empty()); - browser_->GetMainFrame()->ExecuteJavaScript( - "window.open('" + devtools_url_ + "');", - browser_->GetMainFrame()->GetURL(), 0); - } - // Test execution of a native function when the extension is loaded. void RunExtensionTest() { std::string code = "native function v8_extension_test();" @@ -1723,6 +1707,23 @@ class V8RendererTest : public ClientApp::RenderDelegate { RunStartupTest(); } + virtual CefRefPtr GetLoadHandler( + CefRefPtr app) OVERRIDE { + if (test_mode_ == V8TEST_NONE) + return NULL; + + return this; + } + + virtual void OnLoadEnd(CefRefPtr browser, + CefRefPtr frame, + int httpStatusCode) OVERRIDE { + if (test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS && + browser->IsPopup()) { + DevToolsLoadHook(browser); + } + } + virtual void OnContextCreated(CefRefPtr app, CefRefPtr browser, CefRefPtr frame, @@ -1731,12 +1732,11 @@ class V8RendererTest : public ClientApp::RenderDelegate { return; if (test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS) { - if (browser_.get() == NULL) { + if (!browser->IsPopup()) { app_ = app; browser_ = browser; + test_context_ = context; } - // The test is run from OnProcessMessageReceived(), after the message - // and the devtools url has been received from OnLoadEnd(). return; } @@ -1846,22 +1846,6 @@ class V8RendererTest : public ClientApp::RenderDelegate { } } - virtual void OnBrowserDestroyed(CefRefPtr app, - CefRefPtr browser) OVERRIDE { - if (test_mode_ == V8TEST_NONE) - return; - - if (test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS) { - if (browser->IsPopup()) { - // After window destruction there is still a call to - // ScriptController::setCaptureCallStackForUncaughtExceptions(0), - // for which we have to wait. - CefPostDelayedTask(TID_RENDERER, NewCefRunnableMethod( - this, &V8RendererTest::DevToolsClosed), 1000); - } - } - } - virtual bool OnProcessMessageReceived(CefRefPtr app, CefRefPtr browser, CefProcessId source_process, @@ -1870,29 +1854,8 @@ class V8RendererTest : public ClientApp::RenderDelegate { if (test_mode_ == V8TEST_NONE) return false; - if (test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS) { - EXPECT_TRUE(browser.get()); - EXPECT_EQ(PID_BROWSER, source_process); - EXPECT_TRUE(message.get()); - EXPECT_TRUE(message->IsReadOnly()); - - if (message->GetName() == kV8DevToolsURLMsg) { - EXPECT_FALSE(browser->IsPopup()); - devtools_url_ = message->GetArgumentList()->GetString(0); - EXPECT_FALSE(devtools_url_.empty()); - if (!TestFailed()) { - CefPostTask(TID_RENDERER, - NewCefRunnableMethod(this, &V8RendererTest::RunTest)); - } - } else if (message->GetName() == kV8DevToolsLoadHookMsg) { - EXPECT_TRUE(browser->IsPopup()); - DevToolsLoadHook(browser); - } else { - EXPECT_TRUE(false) << "not reached"; - return false; - } - return true; - } else if (message->GetName() == kV8RunTestMsg) { + const std::string& message_name = message->GetName(); + if (message_name == kV8RunTestMsg) { // Run the test asynchronously. CefPostTask(TID_RENDERER, NewCefRunnableMethod(this, &V8RendererTest::RunTest)); @@ -1961,18 +1924,20 @@ class V8RendererTest : public ClientApp::RenderDelegate { void DevToolsLoaded(CefRefPtr browser) { EXPECT_TRUE(browser->IsPopup()); - EXPECT_NE(browser->GetIdentifier(), browser_->GetIdentifier()); + // |browser_| will be NULL if the DevTools window is opened in a separate + // render process. + const int other_browser_id = + (browser_.get() ? browser_->GetIdentifier() : -1); + EXPECT_NE(browser->GetIdentifier(), other_browser_id); + + // Close the DevTools window. This will trigger OnBeforeClose in the browser + // process. CefRefPtr retval; CefRefPtr exception; EXPECT_TRUE(browser->GetMainFrame()->GetV8Context()->Eval( "window.close()", retval, exception)); } - void DevToolsClosed() { - browser_->GetMainFrame()->ExecuteJavaScript( - "window.setTimeout(test, 0);", browser_->GetMainFrame()->GetURL(), 0); - } - protected: // Return from the test. void DestroyTest() { @@ -1998,7 +1963,6 @@ class V8RendererTest : public ClientApp::RenderDelegate { browser_ = NULL; test_context_ = NULL; test_object_ = NULL; - devtools_url_ = ""; } // Return the V8 context. @@ -2011,7 +1975,6 @@ class V8RendererTest : public ClientApp::RenderDelegate { CefRefPtr app_; CefRefPtr browser_; V8TestMode test_mode_; - std::string devtools_url_; CefRefPtr test_context_; CefRefPtr test_object_; @@ -2060,34 +2023,43 @@ class V8TestHandler : public TestHandler { } } + virtual void OnBeforeClose(CefRefPtr browser) OVERRIDE { + if (test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS && + browser->IsPopup()) { + // Generate the uncaught exception in the main browser. + GetBrowser()->GetMainFrame()->ExecuteJavaScript( + "window.setTimeout(test, 0);", + GetBrowser()->GetMainFrame()->GetURL(), 0); + } + + TestHandler::OnBeforeClose(browser); + } + virtual void OnLoadEnd(CefRefPtr browser, CefRefPtr frame, int httpStatusCode) OVERRIDE { if (test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS) { - if (browser->IsPopup()) { - EXPECT_STREQ( - GetBrowser()->GetHost()->GetDevToolsURL(true).ToString().c_str(), - frame->GetURL().ToString().c_str()); - CefRefPtr return_msg = - CefProcessMessage::Create(kV8DevToolsLoadHookMsg); - EXPECT_TRUE(browser->SendProcessMessage(PID_RENDERER, return_msg)); - } else { - // Send the DevTools url message only for the main browser. - CefRefPtr return_msg = - CefProcessMessage::Create(kV8DevToolsURLMsg); - EXPECT_TRUE(return_msg->GetArgumentList()->SetString(0, - browser->GetHost()->GetDevToolsURL(true))); - EXPECT_TRUE(browser->SendProcessMessage(PID_RENDERER, return_msg)); - } - } else { - const std::string& url = frame->GetURL(); - if (url != kV8NavTestUrl && url != kV8ContextParentTestUrl && - url.find("http://tests/") != std::string::npos) { - // Run the test. - CefRefPtr return_msg = - CefProcessMessage::Create(kV8RunTestMsg); - EXPECT_TRUE(browser->SendProcessMessage(PID_RENDERER, return_msg)); + if (!browser->IsPopup()) { + // Create the DevTools window. + CefWindowInfo windowInfo; + CefBrowserSettings settings; + +#if defined(OS_WIN) + windowInfo.SetAsPopup(browser->GetHost()->GetWindowHandle(), "DevTools"); +#endif + + browser->GetHost()->ShowDevTools(windowInfo, this, settings); } + return; + } + + const std::string& url = frame->GetURL(); + if (url != kV8NavTestUrl && url != kV8ContextParentTestUrl && + url.find("http://tests/") != std::string::npos) { + // Run the test. + CefRefPtr return_msg = + CefProcessMessage::Create(kV8RunTestMsg); + EXPECT_TRUE(browser->SendProcessMessage(PID_RENDERER, return_msg)); } } @@ -2100,6 +2072,9 @@ class V8TestHandler : public TestHandler { EXPECT_TRUE(message.get()); EXPECT_TRUE(message->IsReadOnly()); + const std::string& message_name = message->GetName(); + EXPECT_STREQ(kV8TestMsg, message_name.c_str()); + got_message_.yes(); if (message->GetArgumentList()->GetBool(0))