// Copyright (c) 2020 The Chromium Embedded Framework 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/devtools_manager.h" #include "libcef/browser/devtools/devtools_controller.h" #include "libcef/browser/devtools/devtools_frontend.h" #include "libcef/features/runtime.h" #include "content/public/browser/web_contents.h" namespace { // May be created on any thread but will be destroyed on the UI thread. class CefDevToolsRegistrationImpl : public CefRegistration, public CefDevToolsController::Observer { public: explicit CefDevToolsRegistrationImpl( CefRefPtr observer) : observer_(observer) { DCHECK(observer_); } CefDevToolsRegistrationImpl(const CefDevToolsRegistrationImpl&) = delete; CefDevToolsRegistrationImpl& operator=(const CefDevToolsRegistrationImpl&) = delete; ~CefDevToolsRegistrationImpl() override { CEF_REQUIRE_UIT(); // May be null if OnDevToolsControllerDestroyed was called. if (!controller_) return; controller_->RemoveObserver(this); } void Initialize(CefBrowserHostBase* browser, base::WeakPtr controller) { CEF_REQUIRE_UIT(); DCHECK(browser && controller); DCHECK(!browser_ && !controller_); browser_ = browser; controller_ = controller; controller_->AddObserver(this); } private: // CefDevToolsController::Observer methods: bool OnDevToolsMessage(const base::StringPiece& message) override { CEF_REQUIRE_UIT(); return observer_->OnDevToolsMessage(browser_, message.data(), message.size()); } void OnDevToolsMethodResult(int message_id, bool success, const base::StringPiece& result) override { CEF_REQUIRE_UIT(); observer_->OnDevToolsMethodResult(browser_, message_id, success, result.data(), result.size()); } void OnDevToolsEvent(const base::StringPiece& method, const base::StringPiece& params) override { CEF_REQUIRE_UIT(); observer_->OnDevToolsEvent(browser_, std::string(method), params.data(), params.size()); } void OnDevToolsAgentAttached() override { CEF_REQUIRE_UIT(); observer_->OnDevToolsAgentAttached(browser_); } void OnDevToolsAgentDetached() override { CEF_REQUIRE_UIT(); observer_->OnDevToolsAgentDetached(browser_); } void OnDevToolsControllerDestroyed() override { CEF_REQUIRE_UIT(); browser_ = nullptr; controller_.reset(); } CefRefPtr observer_; CefBrowserHostBase* browser_ = nullptr; base::WeakPtr controller_; IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefDevToolsRegistrationImpl); }; } // namespace CefDevToolsManager::CefDevToolsManager(CefBrowserHostBase* inspected_browser) : inspected_browser_(inspected_browser), weak_ptr_factory_(this) { CEF_REQUIRE_UIT(); } CefDevToolsManager::~CefDevToolsManager() { CEF_REQUIRE_UIT(); } void CefDevToolsManager::ShowDevTools(const CefWindowInfo& windowInfo, CefRefPtr client, const CefBrowserSettings& settings, const CefPoint& inspect_element_at) { CEF_REQUIRE_UIT(); if (devtools_frontend_) { if (!inspect_element_at.IsEmpty()) { devtools_frontend_->InspectElementAt(inspect_element_at.x, inspect_element_at.y); } devtools_frontend_->Focus(); return; } if (cef::IsChromeRuntimeEnabled()) { NOTIMPLEMENTED(); } else { auto alloy_browser = static_cast(inspected_browser_); devtools_frontend_ = CefDevToolsFrontend::Show( alloy_browser, windowInfo, client, settings, inspect_element_at, base::BindOnce(&CefDevToolsManager::OnFrontEndDestroyed, weak_ptr_factory_.GetWeakPtr())); } } void CefDevToolsManager::CloseDevTools() { CEF_REQUIRE_UIT(); if (!devtools_frontend_) return; devtools_frontend_->Close(); } bool CefDevToolsManager::HasDevTools() { CEF_REQUIRE_UIT(); return !!devtools_frontend_; } bool CefDevToolsManager::SendDevToolsMessage(const void* message, size_t message_size) { CEF_REQUIRE_UIT(); if (!message || message_size == 0) return false; if (!EnsureController()) return false; return devtools_controller_->SendDevToolsMessage( base::StringPiece(static_cast(message), message_size)); } int CefDevToolsManager::ExecuteDevToolsMethod( int message_id, const CefString& method, CefRefPtr params) { CEF_REQUIRE_UIT(); if (method.empty()) return 0; if (!EnsureController()) return 0; if (params && params->IsValid()) { CefDictionaryValueImpl* impl = static_cast(params.get()); CefValueController::AutoLock lock_scope(impl->controller()); return devtools_controller_->ExecuteDevToolsMethod(message_id, method, impl->GetValueUnsafe()); } else { return devtools_controller_->ExecuteDevToolsMethod(message_id, method, nullptr); } } // static CefRefPtr CefDevToolsManager::CreateRegistration( CefRefPtr observer) { DCHECK(observer); return new CefDevToolsRegistrationImpl(observer); } void CefDevToolsManager::InitializeRegistrationOnUIThread( CefRefPtr registration) { CEF_REQUIRE_UIT(); if (!EnsureController()) return; static_cast(registration.get()) ->Initialize(inspected_browser_, devtools_controller_->GetWeakPtr()); } void CefDevToolsManager::OnFrontEndDestroyed() { devtools_frontend_ = nullptr; } bool CefDevToolsManager::EnsureController() { if (!devtools_controller_) { devtools_controller_.reset(new CefDevToolsController( inspected_browser_->contents_delegate()->web_contents())); } return true; }