1 // Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "libcef/browser/chrome/chrome_browser_host_impl.h"
6
7 #include "libcef/browser/browser_platform_delegate.h"
8 #include "libcef/browser/chrome/browser_platform_delegate_chrome.h"
9 #include "libcef/browser/thread_util.h"
10 #include "libcef/browser/views/browser_view_impl.h"
11 #include "libcef/common/net/url_util.h"
12 #include "libcef/features/runtime_checks.h"
13
14 #include "base/logging.h"
15 #include "base/notreached.h"
16 #include "chrome/browser/printing/print_view_manager_common.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/browser/ui/browser_commands.h"
20 #include "chrome/browser/ui/browser_navigator.h"
21 #include "chrome/browser/ui/browser_tabstrip.h"
22 #include "chrome/browser/ui/browser_window.h"
23 #include "chrome/browser/ui/tabs/tab_strip_model.h"
24 #include "chrome/common/pref_names.h"
25
26 #if defined(TOOLKIT_VIEWS)
27 #include "libcef/browser/chrome/views/chrome_browser_frame.h"
28 #include "libcef/browser/chrome/views/chrome_browser_view.h"
29 #endif
30
31 // static
Create(const CefBrowserCreateParams & params)32 CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::Create(
33 const CefBrowserCreateParams& params) {
34 auto browser = CreateBrowser(params);
35
36 GURL url = url_util::MakeGURL(params.url, /*fixup=*/true);
37 if (url.is_empty()) {
38 // Chrome will navigate to kChromeUINewTabURL by default. We want to keep
39 // the current CEF behavior of not navigating at all. Use a special URL that
40 // will be recognized in HandleNonNavigationAboutURL.
41 url = GURL("chrome://ignore/");
42 }
43
44 // Add a new tab. This will indirectly create a new tab WebContents and
45 // call ChromeBrowserDelegate::OnWebContentsCreated to create the associated
46 // ChromeBrowserHostImpl.
47 chrome::AddTabAt(browser, url, /*index=*/TabStripModel::kNoTab,
48 /*foreground=*/true);
49
50 // The new tab WebContents.
51 auto web_contents = browser->tab_strip_model()->GetActiveWebContents();
52 CHECK(web_contents);
53
54 // The associated ChromeBrowserHostImpl.
55 auto browser_host =
56 ChromeBrowserHostImpl::GetBrowserForContents(web_contents);
57 CHECK(browser_host);
58
59 return browser_host;
60 }
61
62 // static
GetBrowserForHost(const content::RenderViewHost * host)63 CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::GetBrowserForHost(
64 const content::RenderViewHost* host) {
65 REQUIRE_CHROME_RUNTIME();
66 auto browser = CefBrowserHostBase::GetBrowserForHost(host);
67 return static_cast<ChromeBrowserHostImpl*>(browser.get());
68 }
69
70 // static
GetBrowserForHost(const content::RenderFrameHost * host)71 CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::GetBrowserForHost(
72 const content::RenderFrameHost* host) {
73 REQUIRE_CHROME_RUNTIME();
74 auto browser = CefBrowserHostBase::GetBrowserForHost(host);
75 return static_cast<ChromeBrowserHostImpl*>(browser.get());
76 }
77
78 // static
GetBrowserForContents(const content::WebContents * contents)79 CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::GetBrowserForContents(
80 const content::WebContents* contents) {
81 REQUIRE_CHROME_RUNTIME();
82 auto browser = CefBrowserHostBase::GetBrowserForContents(contents);
83 return static_cast<ChromeBrowserHostImpl*>(browser.get());
84 }
85
86 // static
GetBrowserForGlobalId(const content::GlobalRenderFrameHostId & global_id)87 CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::GetBrowserForGlobalId(
88 const content::GlobalRenderFrameHostId& global_id) {
89 REQUIRE_CHROME_RUNTIME();
90 auto browser = CefBrowserHostBase::GetBrowserForGlobalId(global_id);
91 return static_cast<ChromeBrowserHostImpl*>(browser.get());
92 }
93
94 ChromeBrowserHostImpl::~ChromeBrowserHostImpl() = default;
95
AddNewContents(std::unique_ptr<content::WebContents> contents)96 void ChromeBrowserHostImpl::AddNewContents(
97 std::unique_ptr<content::WebContents> contents) {
98 DCHECK(contents);
99 DCHECK(!browser_);
100
101 // We should already be associated with the WebContents.
102 DCHECK_EQ(GetWebContents(), contents.get());
103
104 CefBrowserCreateParams params;
105 params.request_context = request_context();
106 #if defined(TOOLKIT_VIEWS)
107 params.browser_view = GetBrowserView();
108 #endif
109
110 // Create the new Browser representation.
111 auto browser = CreateBrowser(params);
112
113 // Add the WebContents to the Browser.
114 browser->tab_strip_model()->AddWebContents(
115 std::move(contents), /*index=*/TabStripModel::kNoTab,
116 ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL,
117 TabStripModel::ADD_ACTIVE);
118
119 SetBrowser(browser);
120 }
121
OnWebContentsDestroyed(content::WebContents * web_contents)122 void ChromeBrowserHostImpl::OnWebContentsDestroyed(
123 content::WebContents* web_contents) {
124 platform_delegate_->WebContentsDestroyed(web_contents);
125 DestroyBrowser();
126 }
127
OnSetFocus(cef_focus_source_t source)128 void ChromeBrowserHostImpl::OnSetFocus(cef_focus_source_t source) {
129 if (!CEF_CURRENTLY_ON_UIT()) {
130 CEF_POST_TASK(CEF_UIT, base::BindOnce(&ChromeBrowserHostImpl::OnSetFocus,
131 this, source));
132 return;
133 }
134
135 if (contents_delegate_->OnSetFocus(source))
136 return;
137
138 if (browser_) {
139 const int tab_index = GetCurrentTabIndex();
140 if (tab_index != TabStripModel::kNoTab) {
141 chrome::SelectNumberedTab(browser_, tab_index);
142 }
143 }
144 }
145
CloseBrowser(bool force_close)146 void ChromeBrowserHostImpl::CloseBrowser(bool force_close) {
147 // Always do this asynchronously because TabStripModel is not re-entrant.
148 CEF_POST_TASK(CEF_UIT, base::BindOnce(&ChromeBrowserHostImpl::DoCloseBrowser,
149 this, force_close));
150 }
151
TryCloseBrowser()152 bool ChromeBrowserHostImpl::TryCloseBrowser() {
153 // TODO(chrome): Handle the case where the browser may not close immediately.
154 CloseBrowser(true);
155 return true;
156 }
157
SetFocus(bool focus)158 void ChromeBrowserHostImpl::SetFocus(bool focus) {
159 if (focus) {
160 OnSetFocus(FOCUS_SOURCE_SYSTEM);
161 }
162 }
163
GetWindowHandle()164 CefWindowHandle ChromeBrowserHostImpl::GetWindowHandle() {
165 NOTIMPLEMENTED();
166 return kNullWindowHandle;
167 }
168
GetOpenerWindowHandle()169 CefWindowHandle ChromeBrowserHostImpl::GetOpenerWindowHandle() {
170 NOTIMPLEMENTED();
171 return kNullWindowHandle;
172 }
173
GetZoomLevel()174 double ChromeBrowserHostImpl::GetZoomLevel() {
175 NOTIMPLEMENTED();
176 return 0.0;
177 }
178
SetZoomLevel(double zoomLevel)179 void ChromeBrowserHostImpl::SetZoomLevel(double zoomLevel) {
180 NOTIMPLEMENTED();
181 }
182
RunFileDialog(FileDialogMode mode,const CefString & title,const CefString & default_file_path,const std::vector<CefString> & accept_filters,int selected_accept_filter,CefRefPtr<CefRunFileDialogCallback> callback)183 void ChromeBrowserHostImpl::RunFileDialog(
184 FileDialogMode mode,
185 const CefString& title,
186 const CefString& default_file_path,
187 const std::vector<CefString>& accept_filters,
188 int selected_accept_filter,
189 CefRefPtr<CefRunFileDialogCallback> callback) {
190 NOTIMPLEMENTED();
191 callback->OnFileDialogDismissed(0, {});
192 }
193
Print()194 void ChromeBrowserHostImpl::Print() {
195 if (!CEF_CURRENTLY_ON_UIT()) {
196 CEF_POST_TASK(CEF_UIT, base::BindOnce(&ChromeBrowserHostImpl::Print, this));
197 return;
198 }
199
200 if (browser_) {
201 // Like chrome::Print() but specifying the WebContents.
202 printing::StartPrint(GetWebContents(),
203 /*print_renderer=*/mojo::NullAssociatedRemote(),
204 browser_->profile()->GetPrefs()->GetBoolean(
205 prefs::kPrintPreviewDisabled),
206 /*has_selection=*/false);
207 }
208 }
209
PrintToPDF(const CefString & path,const CefPdfPrintSettings & settings,CefRefPtr<CefPdfPrintCallback> callback)210 void ChromeBrowserHostImpl::PrintToPDF(
211 const CefString& path,
212 const CefPdfPrintSettings& settings,
213 CefRefPtr<CefPdfPrintCallback> callback) {
214 NOTIMPLEMENTED();
215 callback->OnPdfPrintFinished(CefString(), false);
216 }
217
Find(const CefString & searchText,bool forward,bool matchCase,bool findNext)218 void ChromeBrowserHostImpl::Find(const CefString& searchText,
219 bool forward,
220 bool matchCase,
221 bool findNext) {
222 NOTIMPLEMENTED();
223 }
224
StopFinding(bool clearSelection)225 void ChromeBrowserHostImpl::StopFinding(bool clearSelection) {
226 NOTIMPLEMENTED();
227 }
228
ShowDevTools(const CefWindowInfo & windowInfo,CefRefPtr<CefClient> client,const CefBrowserSettings & settings,const CefPoint & inspect_element_at)229 void ChromeBrowserHostImpl::ShowDevTools(const CefWindowInfo& windowInfo,
230 CefRefPtr<CefClient> client,
231 const CefBrowserSettings& settings,
232 const CefPoint& inspect_element_at) {
233 NOTIMPLEMENTED();
234 }
235
CloseDevTools()236 void ChromeBrowserHostImpl::CloseDevTools() {
237 NOTIMPLEMENTED();
238 }
239
HasDevTools()240 bool ChromeBrowserHostImpl::HasDevTools() {
241 NOTIMPLEMENTED();
242 return false;
243 }
244
IsWindowRenderingDisabled()245 bool ChromeBrowserHostImpl::IsWindowRenderingDisabled() {
246 return false;
247 }
248
WasResized()249 void ChromeBrowserHostImpl::WasResized() {
250 NOTIMPLEMENTED();
251 }
252
WasHidden(bool hidden)253 void ChromeBrowserHostImpl::WasHidden(bool hidden) {
254 NOTIMPLEMENTED();
255 }
256
NotifyScreenInfoChanged()257 void ChromeBrowserHostImpl::NotifyScreenInfoChanged() {
258 NOTIMPLEMENTED();
259 }
260
Invalidate(PaintElementType type)261 void ChromeBrowserHostImpl::Invalidate(PaintElementType type) {
262 NOTIMPLEMENTED();
263 }
264
SendExternalBeginFrame()265 void ChromeBrowserHostImpl::SendExternalBeginFrame() {
266 NOTIMPLEMENTED();
267 }
268
SendTouchEvent(const CefTouchEvent & event)269 void ChromeBrowserHostImpl::SendTouchEvent(const CefTouchEvent& event) {
270 NOTIMPLEMENTED();
271 }
272
SendCaptureLostEvent()273 void ChromeBrowserHostImpl::SendCaptureLostEvent() {
274 NOTIMPLEMENTED();
275 }
276
NotifyMoveOrResizeStarted()277 void ChromeBrowserHostImpl::NotifyMoveOrResizeStarted() {
278 NOTIMPLEMENTED();
279 }
280
GetWindowlessFrameRate()281 int ChromeBrowserHostImpl::GetWindowlessFrameRate() {
282 return 0;
283 }
284
SetWindowlessFrameRate(int frame_rate)285 void ChromeBrowserHostImpl::SetWindowlessFrameRate(int frame_rate) {}
286
ImeSetComposition(const CefString & text,const std::vector<CefCompositionUnderline> & underlines,const CefRange & replacement_range,const CefRange & selection_range)287 void ChromeBrowserHostImpl::ImeSetComposition(
288 const CefString& text,
289 const std::vector<CefCompositionUnderline>& underlines,
290 const CefRange& replacement_range,
291 const CefRange& selection_range) {
292 NOTIMPLEMENTED();
293 }
294
ImeCommitText(const CefString & text,const CefRange & replacement_range,int relative_cursor_pos)295 void ChromeBrowserHostImpl::ImeCommitText(const CefString& text,
296 const CefRange& replacement_range,
297 int relative_cursor_pos) {
298 NOTIMPLEMENTED();
299 }
ImeFinishComposingText(bool keep_selection)300 void ChromeBrowserHostImpl::ImeFinishComposingText(bool keep_selection) {
301 NOTIMPLEMENTED();
302 }
303
ImeCancelComposition()304 void ChromeBrowserHostImpl::ImeCancelComposition() {
305 NOTIMPLEMENTED();
306 }
307
DragTargetDragEnter(CefRefPtr<CefDragData> drag_data,const CefMouseEvent & event,DragOperationsMask allowed_ops)308 void ChromeBrowserHostImpl::DragTargetDragEnter(
309 CefRefPtr<CefDragData> drag_data,
310 const CefMouseEvent& event,
311 DragOperationsMask allowed_ops) {
312 NOTIMPLEMENTED();
313 }
314
DragTargetDragOver(const CefMouseEvent & event,DragOperationsMask allowed_ops)315 void ChromeBrowserHostImpl::DragTargetDragOver(const CefMouseEvent& event,
316 DragOperationsMask allowed_ops) {
317 NOTIMPLEMENTED();
318 }
319
DragTargetDragLeave()320 void ChromeBrowserHostImpl::DragTargetDragLeave() {
321 NOTIMPLEMENTED();
322 }
323
DragTargetDrop(const CefMouseEvent & event)324 void ChromeBrowserHostImpl::DragTargetDrop(const CefMouseEvent& event) {
325 NOTIMPLEMENTED();
326 }
327
DragSourceSystemDragEnded()328 void ChromeBrowserHostImpl::DragSourceSystemDragEnded() {
329 NOTIMPLEMENTED();
330 }
331
DragSourceEndedAt(int x,int y,DragOperationsMask op)332 void ChromeBrowserHostImpl::DragSourceEndedAt(int x,
333 int y,
334 DragOperationsMask op) {
335 NOTIMPLEMENTED();
336 }
337
SetAudioMuted(bool mute)338 void ChromeBrowserHostImpl::SetAudioMuted(bool mute) {
339 NOTIMPLEMENTED();
340 }
341
IsAudioMuted()342 bool ChromeBrowserHostImpl::IsAudioMuted() {
343 NOTIMPLEMENTED();
344 return false;
345 }
346
SetAccessibilityState(cef_state_t accessibility_state)347 void ChromeBrowserHostImpl::SetAccessibilityState(
348 cef_state_t accessibility_state) {
349 NOTIMPLEMENTED();
350 }
351
SetAutoResizeEnabled(bool enabled,const CefSize & min_size,const CefSize & max_size)352 void ChromeBrowserHostImpl::SetAutoResizeEnabled(bool enabled,
353 const CefSize& min_size,
354 const CefSize& max_size) {
355 NOTIMPLEMENTED();
356 }
357
GetExtension()358 CefRefPtr<CefExtension> ChromeBrowserHostImpl::GetExtension() {
359 return nullptr;
360 }
361
IsBackgroundHost()362 bool ChromeBrowserHostImpl::IsBackgroundHost() {
363 return false;
364 }
365
Navigate(const content::OpenURLParams & params)366 bool ChromeBrowserHostImpl::Navigate(const content::OpenURLParams& params) {
367 CEF_REQUIRE_UIT();
368 if (GetCurrentTabIndex() == TabStripModel::kNoTab) {
369 // We can't navigate via the Browser because we don't have a current tab.
370 return CefBrowserHostBase::Navigate(params);
371 }
372
373 if (browser_) {
374 GURL gurl = params.url;
375 if (!url_util::FixupGURL(gurl))
376 return false;
377
378 // This is generally equivalent to calling Browser::OpenURL, except:
379 // 1. It doesn't trigger a call to CefRequestHandler::OnOpenURLFromTab, and
380 // 2. It navigates in this CefBrowserHost's WebContents instead of
381 // (a) creating a new WebContents, or (b) using the Browser's active
382 // WebContents (which may not be the same), and
383 // 3. There is no risk of triggering chrome's popup blocker.
384 NavigateParams nav_params(browser_, gurl, params.transition);
385 nav_params.FillNavigateParamsFromOpenURLParams(params);
386
387 // Always navigate in the current tab.
388 nav_params.disposition = WindowOpenDisposition::CURRENT_TAB;
389 nav_params.source_contents = GetWebContents();
390
391 nav_params.tabstrip_add_types = TabStripModel::ADD_NONE;
392 if (params.user_gesture)
393 nav_params.window_action = NavigateParams::SHOW_WINDOW;
394 ::Navigate(&nav_params);
395 return true;
396 }
397 return false;
398 }
399
ChromeBrowserHostImpl(const CefBrowserSettings & settings,CefRefPtr<CefClient> client,std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,scoped_refptr<CefBrowserInfo> browser_info,CefRefPtr<CefRequestContextImpl> request_context)400 ChromeBrowserHostImpl::ChromeBrowserHostImpl(
401 const CefBrowserSettings& settings,
402 CefRefPtr<CefClient> client,
403 std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
404 scoped_refptr<CefBrowserInfo> browser_info,
405 CefRefPtr<CefRequestContextImpl> request_context)
406 : CefBrowserHostBase(settings,
407 client,
408 std::move(platform_delegate),
409 browser_info,
410 request_context) {}
411
412 // static
CreateBrowser(const CefBrowserCreateParams & params)413 Browser* ChromeBrowserHostImpl::CreateBrowser(
414 const CefBrowserCreateParams& params) {
415 // Get or create the request context and profile.
416 CefRefPtr<CefRequestContextImpl> request_context_impl =
417 CefRequestContextImpl::GetOrCreateForRequestContext(
418 params.request_context);
419 CHECK(request_context_impl);
420 auto cef_browser_context = request_context_impl->GetBrowserContext();
421 CHECK(cef_browser_context);
422 auto profile = cef_browser_context->AsProfile();
423 CHECK(profile);
424
425 Browser::CreateParams chrome_params =
426 Browser::CreateParams(profile, /*user_gesture=*/false);
427
428 // Pass |params| to cef::BrowserDelegate::Create from the Browser constructor.
429 chrome_params.cef_params = base::MakeRefCounted<DelegateCreateParams>(params);
430
431 #if defined(TOOLKIT_VIEWS)
432 // Configure Browser creation to use the existing Views-based
433 // Widget/BrowserFrame (ChromeBrowserFrame) and BrowserView/BrowserWindow
434 // (ChromeBrowserView). See views/chrome_browser_frame.h for related
435 // documentation.
436 ChromeBrowserView* chrome_browser_view = nullptr;
437 if (params.browser_view) {
438 // Don't show most controls.
439 chrome_params.type = Browser::TYPE_POPUP;
440 // Don't show title bar or address.
441 chrome_params.trusted_source = true;
442
443 auto view_impl =
444 static_cast<CefBrowserViewImpl*>(params.browser_view.get());
445
446 chrome_browser_view =
447 static_cast<ChromeBrowserView*>(view_impl->root_view());
448 chrome_params.window = chrome_browser_view;
449
450 auto chrome_widget =
451 static_cast<ChromeBrowserFrame*>(chrome_browser_view->GetWidget());
452 chrome_browser_view->set_frame(chrome_widget);
453 }
454 #endif // defined(TOOLKIT_VIEWS)
455
456 // Create the Browser. This will indirectly create the ChomeBrowserDelegate.
457 // The same params will be used to create a new Browser if the tab is dragged
458 // out of the existing Browser. The returned Browser is owned by the
459 // associated BrowserView.
460 auto browser = Browser::Create(chrome_params);
461
462 bool show_browser = true;
463
464 #if defined(TOOLKIT_VIEWS)
465 if (chrome_browser_view) {
466 // Initialize the BrowserFrame and BrowserView and create the controls that
467 // require access to the Browser.
468 chrome_browser_view->InitBrowser(base::WrapUnique(browser),
469 params.browser_view);
470
471 // Don't show the browser by default.
472 show_browser = false;
473 }
474 #endif
475
476 if (show_browser) {
477 browser->window()->Show();
478 }
479
480 return browser;
481 }
482
Attach(content::WebContents * web_contents,CefRefPtr<ChromeBrowserHostImpl> opener)483 void ChromeBrowserHostImpl::Attach(content::WebContents* web_contents,
484 CefRefPtr<ChromeBrowserHostImpl> opener) {
485 DCHECK(web_contents);
486
487 if (opener) {
488 // Give the opener browser's platform delegate an opportunity to modify the
489 // new browser's platform delegate.
490 opener->platform_delegate_->PopupWebContentsCreated(
491 settings_, client_, web_contents, platform_delegate_.get(),
492 /*is_devtools_popup=*/false);
493 }
494
495 platform_delegate_->WebContentsCreated(web_contents,
496 /*own_web_contents=*/false);
497 contents_delegate_->ObserveWebContents(web_contents);
498
499 // Associate the platform delegate with this browser.
500 platform_delegate_->BrowserCreated(this);
501
502 // Associate the base class with the WebContents.
503 InitializeBrowser();
504
505 // Notify that the browser has been created. These must be delivered in the
506 // expected order.
507
508 // 1. Notify the browser's LifeSpanHandler. This must always be the first
509 // notification for the browser.
510 {
511 // The WebContents won't be added to the Browser's TabStripModel until later
512 // in the current call stack. Block navigation until that time.
513 auto navigation_lock = browser_info_->CreateNavigationLock();
514 OnAfterCreated();
515 }
516
517 // 2. Notify the platform delegate. With Views this will result in a call to
518 // CefBrowserViewDelegate::OnBrowserCreated().
519 platform_delegate_->NotifyBrowserCreated();
520
521 if (opener && opener->platform_delegate_) {
522 // 3. Notify the opener browser's platform delegate. With Views this will
523 // result in a call to CefBrowserViewDelegate::OnPopupBrowserViewCreated().
524 opener->platform_delegate_->PopupBrowserCreated(
525 this,
526 /*is_devtools_popup=*/false);
527 }
528 }
529
SetBrowser(Browser * browser)530 void ChromeBrowserHostImpl::SetBrowser(Browser* browser) {
531 CEF_REQUIRE_UIT();
532 browser_ = browser;
533 static_cast<CefBrowserPlatformDelegateChrome*>(platform_delegate_.get())
534 ->set_chrome_browser(browser);
535 }
536
WindowDestroyed()537 void ChromeBrowserHostImpl::WindowDestroyed() {
538 CEF_REQUIRE_UIT();
539 #if defined(TOOLKIT_VIEWS)
540 if (browser_ && is_views_hosted_) {
541 auto chrome_browser_view =
542 static_cast<ChromeBrowserView*>(browser_->window());
543 chrome_browser_view->Destroyed();
544 }
545 #endif
546
547 platform_delegate_->CloseHostWindow();
548 }
549
DestroyBrowser()550 void ChromeBrowserHostImpl::DestroyBrowser() {
551 CEF_REQUIRE_UIT();
552 browser_ = nullptr;
553
554 OnBeforeClose();
555 OnBrowserDestroyed();
556
557 // Disassociate the platform delegate from this browser.
558 platform_delegate_->BrowserDestroyed(this);
559
560 CefBrowserHostBase::DestroyBrowser();
561 }
562
DoCloseBrowser(bool force_close)563 void ChromeBrowserHostImpl::DoCloseBrowser(bool force_close) {
564 CEF_REQUIRE_UIT();
565 if (browser_) {
566 // Like chrome::CloseTab() but specifying the WebContents.
567 const int tab_index = GetCurrentTabIndex();
568 if (tab_index != TabStripModel::kNoTab) {
569 // TODO(chrome): Handle the case where this method returns false,
570 // indicating that the contents were not closed immediately.
571 browser_->tab_strip_model()->CloseWebContentsAt(
572 tab_index, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB |
573 TabStripModel::CLOSE_USER_GESTURE);
574 }
575 }
576 }
577
GetCurrentTabIndex() const578 int ChromeBrowserHostImpl::GetCurrentTabIndex() const {
579 CEF_REQUIRE_UIT();
580 if (browser_) {
581 return browser_->tab_strip_model()->GetIndexOfWebContents(GetWebContents());
582 }
583 return TabStripModel::kNoTab;
584 }
585