1 // Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4
5 #include "libcef/browser/devtools/devtools_manager.h"
6
7 #include "libcef/browser/devtools/devtools_controller.h"
8 #include "libcef/browser/devtools/devtools_frontend.h"
9 #include "libcef/features/runtime.h"
10
11 #include "content/public/browser/web_contents.h"
12
13 namespace {
14
15 // May be created on any thread but will be destroyed on the UI thread.
16 class CefDevToolsRegistrationImpl : public CefRegistration,
17 public CefDevToolsController::Observer {
18 public:
CefDevToolsRegistrationImpl(CefRefPtr<CefDevToolsMessageObserver> observer)19 explicit CefDevToolsRegistrationImpl(
20 CefRefPtr<CefDevToolsMessageObserver> observer)
21 : observer_(observer) {
22 DCHECK(observer_);
23 }
24
25 CefDevToolsRegistrationImpl(const CefDevToolsRegistrationImpl&) = delete;
26 CefDevToolsRegistrationImpl& operator=(const CefDevToolsRegistrationImpl&) =
27 delete;
28
~CefDevToolsRegistrationImpl()29 ~CefDevToolsRegistrationImpl() override {
30 CEF_REQUIRE_UIT();
31
32 // May be null if OnDevToolsControllerDestroyed was called.
33 if (!controller_)
34 return;
35
36 controller_->RemoveObserver(this);
37 }
38
Initialize(CefBrowserHostBase * browser,base::WeakPtr<CefDevToolsController> controller)39 void Initialize(CefBrowserHostBase* browser,
40 base::WeakPtr<CefDevToolsController> controller) {
41 CEF_REQUIRE_UIT();
42 DCHECK(browser && controller);
43 DCHECK(!browser_ && !controller_);
44 browser_ = browser;
45 controller_ = controller;
46
47 controller_->AddObserver(this);
48 }
49
50 private:
51 // CefDevToolsController::Observer methods:
OnDevToolsMessage(const base::StringPiece & message)52 bool OnDevToolsMessage(const base::StringPiece& message) override {
53 CEF_REQUIRE_UIT();
54 return observer_->OnDevToolsMessage(browser_, message.data(),
55 message.size());
56 }
57
OnDevToolsMethodResult(int message_id,bool success,const base::StringPiece & result)58 void OnDevToolsMethodResult(int message_id,
59 bool success,
60 const base::StringPiece& result) override {
61 CEF_REQUIRE_UIT();
62 observer_->OnDevToolsMethodResult(browser_, message_id, success,
63 result.data(), result.size());
64 }
65
OnDevToolsEvent(const base::StringPiece & method,const base::StringPiece & params)66 void OnDevToolsEvent(const base::StringPiece& method,
67 const base::StringPiece& params) override {
68 CEF_REQUIRE_UIT();
69 observer_->OnDevToolsEvent(browser_, std::string(method), params.data(),
70 params.size());
71 }
72
OnDevToolsAgentAttached()73 void OnDevToolsAgentAttached() override {
74 CEF_REQUIRE_UIT();
75 observer_->OnDevToolsAgentAttached(browser_);
76 }
77
OnDevToolsAgentDetached()78 void OnDevToolsAgentDetached() override {
79 CEF_REQUIRE_UIT();
80 observer_->OnDevToolsAgentDetached(browser_);
81 }
82
OnDevToolsControllerDestroyed()83 void OnDevToolsControllerDestroyed() override {
84 CEF_REQUIRE_UIT();
85 browser_ = nullptr;
86 controller_.reset();
87 }
88
89 CefRefPtr<CefDevToolsMessageObserver> observer_;
90
91 CefBrowserHostBase* browser_ = nullptr;
92 base::WeakPtr<CefDevToolsController> controller_;
93
94 IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefDevToolsRegistrationImpl);
95 };
96
97 } // namespace
98
CefDevToolsManager(CefBrowserHostBase * inspected_browser)99 CefDevToolsManager::CefDevToolsManager(CefBrowserHostBase* inspected_browser)
100 : inspected_browser_(inspected_browser), weak_ptr_factory_(this) {
101 CEF_REQUIRE_UIT();
102 }
103
~CefDevToolsManager()104 CefDevToolsManager::~CefDevToolsManager() {
105 CEF_REQUIRE_UIT();
106 }
107
ShowDevTools(const CefWindowInfo & windowInfo,CefRefPtr<CefClient> client,const CefBrowserSettings & settings,const CefPoint & inspect_element_at)108 void CefDevToolsManager::ShowDevTools(const CefWindowInfo& windowInfo,
109 CefRefPtr<CefClient> client,
110 const CefBrowserSettings& settings,
111 const CefPoint& inspect_element_at) {
112 CEF_REQUIRE_UIT();
113 if (devtools_frontend_) {
114 if (!inspect_element_at.IsEmpty()) {
115 devtools_frontend_->InspectElementAt(inspect_element_at.x,
116 inspect_element_at.y);
117 }
118 devtools_frontend_->Focus();
119 return;
120 }
121
122 if (cef::IsChromeRuntimeEnabled()) {
123 NOTIMPLEMENTED();
124 } else {
125 auto alloy_browser = static_cast<AlloyBrowserHostImpl*>(inspected_browser_);
126 devtools_frontend_ = CefDevToolsFrontend::Show(
127 alloy_browser, windowInfo, client, settings, inspect_element_at,
128 base::BindOnce(&CefDevToolsManager::OnFrontEndDestroyed,
129 weak_ptr_factory_.GetWeakPtr()));
130 }
131 }
132
CloseDevTools()133 void CefDevToolsManager::CloseDevTools() {
134 CEF_REQUIRE_UIT();
135 if (!devtools_frontend_)
136 return;
137 devtools_frontend_->Close();
138 }
139
HasDevTools()140 bool CefDevToolsManager::HasDevTools() {
141 CEF_REQUIRE_UIT();
142 return !!devtools_frontend_;
143 }
144
SendDevToolsMessage(const void * message,size_t message_size)145 bool CefDevToolsManager::SendDevToolsMessage(const void* message,
146 size_t message_size) {
147 CEF_REQUIRE_UIT();
148 if (!message || message_size == 0)
149 return false;
150
151 if (!EnsureController())
152 return false;
153
154 return devtools_controller_->SendDevToolsMessage(
155 base::StringPiece(static_cast<const char*>(message), message_size));
156 }
157
ExecuteDevToolsMethod(int message_id,const CefString & method,CefRefPtr<CefDictionaryValue> params)158 int CefDevToolsManager::ExecuteDevToolsMethod(
159 int message_id,
160 const CefString& method,
161 CefRefPtr<CefDictionaryValue> params) {
162 CEF_REQUIRE_UIT();
163 if (method.empty())
164 return 0;
165
166 if (!EnsureController())
167 return 0;
168
169 if (params && params->IsValid()) {
170 CefDictionaryValueImpl* impl =
171 static_cast<CefDictionaryValueImpl*>(params.get());
172 CefValueController::AutoLock lock_scope(impl->controller());
173 return devtools_controller_->ExecuteDevToolsMethod(message_id, method,
174 impl->GetValueUnsafe());
175 } else {
176 return devtools_controller_->ExecuteDevToolsMethod(message_id, method,
177 nullptr);
178 }
179 }
180
181 // static
CreateRegistration(CefRefPtr<CefDevToolsMessageObserver> observer)182 CefRefPtr<CefRegistration> CefDevToolsManager::CreateRegistration(
183 CefRefPtr<CefDevToolsMessageObserver> observer) {
184 DCHECK(observer);
185 return new CefDevToolsRegistrationImpl(observer);
186 }
187
InitializeRegistrationOnUIThread(CefRefPtr<CefRegistration> registration)188 void CefDevToolsManager::InitializeRegistrationOnUIThread(
189 CefRefPtr<CefRegistration> registration) {
190 CEF_REQUIRE_UIT();
191
192 if (!EnsureController())
193 return;
194
195 static_cast<CefDevToolsRegistrationImpl*>(registration.get())
196 ->Initialize(inspected_browser_, devtools_controller_->GetWeakPtr());
197 }
198
OnFrontEndDestroyed()199 void CefDevToolsManager::OnFrontEndDestroyed() {
200 devtools_frontend_ = nullptr;
201 }
202
EnsureController()203 bool CefDevToolsManager::EnsureController() {
204 if (!devtools_controller_) {
205 devtools_controller_.reset(new CefDevToolsController(
206 inspected_browser_->contents_delegate()->web_contents()));
207 }
208 return true;
209 }
210