1 // Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be found
3 // in the LICENSE file.
4
5 #include "libcef/browser/views/browser_view_impl.h"
6
7 #include "libcef/browser/browser_host_base.h"
8 #include "libcef/browser/browser_util.h"
9 #include "libcef/browser/chrome/views/chrome_browser_view.h"
10 #include "libcef/browser/context.h"
11 #include "libcef/browser/request_context_impl.h"
12 #include "libcef/browser/thread_util.h"
13 #include "libcef/browser/views/window_impl.h"
14
15 #include "content/public/browser/native_web_keyboard_event.h"
16 #include "ui/content_accelerators/accelerator_util.h"
17
18 // static
CreateBrowserView(CefRefPtr<CefClient> client,const CefString & url,const CefBrowserSettings & settings,CefRefPtr<CefDictionaryValue> extra_info,CefRefPtr<CefRequestContext> request_context,CefRefPtr<CefBrowserViewDelegate> delegate)19 CefRefPtr<CefBrowserView> CefBrowserView::CreateBrowserView(
20 CefRefPtr<CefClient> client,
21 const CefString& url,
22 const CefBrowserSettings& settings,
23 CefRefPtr<CefDictionaryValue> extra_info,
24 CefRefPtr<CefRequestContext> request_context,
25 CefRefPtr<CefBrowserViewDelegate> delegate) {
26 return CefBrowserViewImpl::Create(client, url, settings, extra_info,
27 request_context, delegate);
28 }
29
30 // static
GetForBrowser(CefRefPtr<CefBrowser> browser)31 CefRefPtr<CefBrowserView> CefBrowserView::GetForBrowser(
32 CefRefPtr<CefBrowser> browser) {
33 CEF_REQUIRE_UIT_RETURN(nullptr);
34
35 CefBrowserHostBase* browser_impl =
36 static_cast<CefBrowserHostBase*>(browser.get());
37 if (browser_impl && browser_impl->is_views_hosted())
38 return browser_impl->GetBrowserView();
39 return nullptr;
40 }
41
42 // static
Create(CefRefPtr<CefClient> client,const CefString & url,const CefBrowserSettings & settings,CefRefPtr<CefDictionaryValue> extra_info,CefRefPtr<CefRequestContext> request_context,CefRefPtr<CefBrowserViewDelegate> delegate)43 CefRefPtr<CefBrowserViewImpl> CefBrowserViewImpl::Create(
44 CefRefPtr<CefClient> client,
45 const CefString& url,
46 const CefBrowserSettings& settings,
47 CefRefPtr<CefDictionaryValue> extra_info,
48 CefRefPtr<CefRequestContext> request_context,
49 CefRefPtr<CefBrowserViewDelegate> delegate) {
50 CEF_REQUIRE_UIT_RETURN(nullptr);
51
52 if (!request_context) {
53 request_context = CefRequestContext::GetGlobalContext();
54 }
55
56 // Verify that the browser context is valid. Do this here instead of risking
57 // potential browser creation failure when this view is added to the window.
58 auto request_context_impl =
59 static_cast<CefRequestContextImpl*>(request_context.get());
60 if (!request_context_impl->VerifyBrowserContext()) {
61 return nullptr;
62 }
63
64 CefRefPtr<CefBrowserViewImpl> browser_view = new CefBrowserViewImpl(delegate);
65 browser_view->SetPendingBrowserCreateParams(client, url, settings, extra_info,
66 request_context);
67 browser_view->Initialize();
68 browser_view->SetDefaults(settings);
69 return browser_view;
70 }
71
72 // static
CreateForPopup(const CefBrowserSettings & settings,CefRefPtr<CefBrowserViewDelegate> delegate)73 CefRefPtr<CefBrowserViewImpl> CefBrowserViewImpl::CreateForPopup(
74 const CefBrowserSettings& settings,
75 CefRefPtr<CefBrowserViewDelegate> delegate) {
76 CEF_REQUIRE_UIT_RETURN(nullptr);
77
78 CefRefPtr<CefBrowserViewImpl> browser_view = new CefBrowserViewImpl(delegate);
79 browser_view->Initialize();
80 browser_view->SetDefaults(settings);
81 return browser_view;
82 }
83
WebContentsCreated(content::WebContents * web_contents)84 void CefBrowserViewImpl::WebContentsCreated(
85 content::WebContents* web_contents) {
86 if (web_view())
87 web_view()->SetWebContents(web_contents);
88 }
89
BrowserCreated(CefBrowserHostBase * browser,base::RepeatingClosure on_bounds_changed)90 void CefBrowserViewImpl::BrowserCreated(
91 CefBrowserHostBase* browser,
92 base::RepeatingClosure on_bounds_changed) {
93 browser_ = browser;
94 on_bounds_changed_ = on_bounds_changed;
95 }
96
BrowserDestroyed(CefBrowserHostBase * browser)97 void CefBrowserViewImpl::BrowserDestroyed(CefBrowserHostBase* browser) {
98 DCHECK_EQ(browser, browser_);
99 browser_ = nullptr;
100
101 if (web_view())
102 web_view()->SetWebContents(nullptr);
103 }
104
HandleKeyboardEvent(const content::NativeWebKeyboardEvent & event)105 bool CefBrowserViewImpl::HandleKeyboardEvent(
106 const content::NativeWebKeyboardEvent& event) {
107 if (!root_view())
108 return false;
109
110 views::FocusManager* focus_manager = root_view()->GetFocusManager();
111 if (!focus_manager)
112 return false;
113
114 if (HandleAccelerator(event, focus_manager))
115 return true;
116
117 // Give the CefWindowDelegate a chance to handle the event.
118 CefRefPtr<CefWindow> window =
119 view_util::GetWindowFor(root_view()->GetWidget());
120 CefWindowImpl* window_impl = static_cast<CefWindowImpl*>(window.get());
121 if (window_impl) {
122 CefKeyEvent cef_event;
123 if (browser_util::GetCefKeyEvent(event, cef_event) &&
124 window_impl->OnKeyEvent(cef_event)) {
125 return true;
126 }
127 }
128
129 // Proceed with default native handling.
130 return unhandled_keyboard_event_handler_.HandleKeyboardEvent(event,
131 focus_manager);
132 }
133
GetBrowser()134 CefRefPtr<CefBrowser> CefBrowserViewImpl::GetBrowser() {
135 CEF_REQUIRE_VALID_RETURN(nullptr);
136 return browser_;
137 }
138
GetChromeToolbar()139 CefRefPtr<CefView> CefBrowserViewImpl::GetChromeToolbar() {
140 CEF_REQUIRE_VALID_RETURN(nullptr);
141 if (cef::IsChromeRuntimeEnabled()) {
142 return static_cast<ChromeBrowserView*>(root_view())->cef_toolbar();
143 }
144
145 return nullptr;
146 }
147
SetPreferAccelerators(bool prefer_accelerators)148 void CefBrowserViewImpl::SetPreferAccelerators(bool prefer_accelerators) {
149 CEF_REQUIRE_VALID_RETURN_VOID();
150 if (web_view())
151 web_view()->set_allow_accelerators(prefer_accelerators);
152 }
153
RequestFocus()154 void CefBrowserViewImpl::RequestFocus() {
155 CEF_REQUIRE_VALID_RETURN_VOID();
156 // Always execute asynchronously to work around issue #3040.
157 CEF_POST_TASK(CEF_UIT,
158 base::BindOnce(&CefBrowserViewImpl::RequestFocusInternal,
159 weak_ptr_factory_.GetWeakPtr()));
160 }
161
SetBackgroundColor(cef_color_t color)162 void CefBrowserViewImpl::SetBackgroundColor(cef_color_t color) {
163 CEF_REQUIRE_VALID_RETURN_VOID();
164 ParentClass::SetBackgroundColor(color);
165 if (web_view())
166 web_view()->SetResizeBackgroundColor(color);
167 }
168
Detach()169 void CefBrowserViewImpl::Detach() {
170 ParentClass::Detach();
171
172 // root_view() will be nullptr now.
173 DCHECK(!root_view());
174
175 if (browser_) {
176 // With the Alloy runtime |browser_| will disappear when WindowDestroyed()
177 // indirectly calls BrowserDestroyed() so keep a reference.
178 CefRefPtr<CefBrowserHostBase> browser = browser_;
179
180 // Force the browser to be destroyed.
181 browser->WindowDestroyed();
182 }
183 }
184
GetDebugInfo(base::DictionaryValue * info,bool include_children)185 void CefBrowserViewImpl::GetDebugInfo(base::DictionaryValue* info,
186 bool include_children) {
187 ParentClass::GetDebugInfo(info, include_children);
188 if (browser_)
189 info->SetString("url", browser_->GetMainFrame()->GetURL().ToString());
190 }
191
OnBrowserViewAdded()192 void CefBrowserViewImpl::OnBrowserViewAdded() {
193 if (!browser_ && pending_browser_create_params_) {
194 // Top-level browsers will be created when this view is added to the views
195 // hierarchy.
196 pending_browser_create_params_->browser_view = this;
197
198 CefBrowserHostBase::Create(*pending_browser_create_params_);
199 DCHECK(browser_);
200
201 pending_browser_create_params_.reset(nullptr);
202 }
203 }
204
OnBoundsChanged()205 void CefBrowserViewImpl::OnBoundsChanged() {
206 if (!on_bounds_changed_.is_null())
207 on_bounds_changed_.Run();
208 }
209
CefBrowserViewImpl(CefRefPtr<CefBrowserViewDelegate> delegate)210 CefBrowserViewImpl::CefBrowserViewImpl(
211 CefRefPtr<CefBrowserViewDelegate> delegate)
212 : ParentClass(delegate), weak_ptr_factory_(this) {}
213
SetPendingBrowserCreateParams(CefRefPtr<CefClient> client,const CefString & url,const CefBrowserSettings & settings,CefRefPtr<CefDictionaryValue> extra_info,CefRefPtr<CefRequestContext> request_context)214 void CefBrowserViewImpl::SetPendingBrowserCreateParams(
215 CefRefPtr<CefClient> client,
216 const CefString& url,
217 const CefBrowserSettings& settings,
218 CefRefPtr<CefDictionaryValue> extra_info,
219 CefRefPtr<CefRequestContext> request_context) {
220 DCHECK(!pending_browser_create_params_);
221 pending_browser_create_params_.reset(new CefBrowserCreateParams());
222 pending_browser_create_params_->client = client;
223 pending_browser_create_params_->url = url;
224 pending_browser_create_params_->settings = settings;
225 pending_browser_create_params_->extra_info = extra_info;
226 pending_browser_create_params_->request_context = request_context;
227 }
228
SetDefaults(const CefBrowserSettings & settings)229 void CefBrowserViewImpl::SetDefaults(const CefBrowserSettings& settings) {
230 SetBackgroundColor(
231 CefContext::Get()->GetBackgroundColor(&settings, STATE_DISABLED));
232 }
233
CreateRootView()234 views::View* CefBrowserViewImpl::CreateRootView() {
235 if (cef::IsChromeRuntimeEnabled()) {
236 return new ChromeBrowserView(delegate(), this);
237 }
238
239 return new CefBrowserViewView(delegate(), this);
240 }
241
InitializeRootView()242 void CefBrowserViewImpl::InitializeRootView() {
243 if (cef::IsChromeRuntimeEnabled()) {
244 static_cast<ChromeBrowserView*>(root_view())->Initialize();
245 } else {
246 static_cast<CefBrowserViewView*>(root_view())->Initialize();
247 }
248 }
249
web_view() const250 views::WebView* CefBrowserViewImpl::web_view() const {
251 if (cef::IsChromeRuntimeEnabled()) {
252 return static_cast<ChromeBrowserView*>(root_view())->contents_web_view();
253 }
254
255 return static_cast<CefBrowserViewView*>(root_view());
256 }
257
HandleAccelerator(const content::NativeWebKeyboardEvent & event,views::FocusManager * focus_manager)258 bool CefBrowserViewImpl::HandleAccelerator(
259 const content::NativeWebKeyboardEvent& event,
260 views::FocusManager* focus_manager) {
261 // Previous calls to TranslateMessage can generate Char events as well as
262 // RawKeyDown events, even if the latter triggered an accelerator. In these
263 // cases, we discard the Char events.
264 if (event.GetType() == blink::WebInputEvent::Type::kChar &&
265 ignore_next_char_event_) {
266 ignore_next_char_event_ = false;
267 return true;
268 }
269
270 // It's necessary to reset this flag, because a RawKeyDown event may not
271 // always generate a Char event.
272 ignore_next_char_event_ = false;
273
274 if (event.GetType() == blink::WebInputEvent::Type::kRawKeyDown) {
275 ui::Accelerator accelerator =
276 ui::GetAcceleratorFromNativeWebKeyboardEvent(event);
277
278 // This is tricky: we want to set ignore_next_char_event_ if
279 // ProcessAccelerator returns true. But ProcessAccelerator might delete
280 // |this| if the accelerator is a "close tab" one. So we speculatively
281 // set the flag and fix it if no event was handled.
282 ignore_next_char_event_ = true;
283
284 if (focus_manager->ProcessAccelerator(accelerator))
285 return true;
286
287 // ProcessAccelerator didn't handle the accelerator, so we know both
288 // that |this| is still valid, and that we didn't want to set the flag.
289 ignore_next_char_event_ = false;
290 }
291
292 return false;
293 }
294
RequestFocusInternal()295 void CefBrowserViewImpl::RequestFocusInternal() {
296 ParentClass::RequestFocus();
297 }
298