// Copyright 2016 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/views/browser_view_impl.h" #include "libcef/browser/alloy/alloy_browser_host_impl.h" #include "libcef/browser/browser_util.h" #include "libcef/browser/context.h" #include "libcef/browser/thread_util.h" #include "libcef/browser/views/window_impl.h" #include "libcef/features/runtime_checks.h" #include "content/public/browser/native_web_keyboard_event.h" #include "ui/content_accelerators/accelerator_util.h" // static CefRefPtr CefBrowserView::CreateBrowserView( CefRefPtr client, const CefString& url, const CefBrowserSettings& settings, CefRefPtr extra_info, CefRefPtr request_context, CefRefPtr delegate) { return CefBrowserViewImpl::Create(client, url, settings, extra_info, request_context, delegate); } // static CefRefPtr CefBrowserView::GetForBrowser( CefRefPtr browser) { REQUIRE_ALLOY_RUNTIME(); CEF_REQUIRE_UIT_RETURN(nullptr); AlloyBrowserHostImpl* browser_impl = static_cast(browser.get()); if (browser_impl && browser_impl->IsViewsHosted()) return browser_impl->GetBrowserView(); return nullptr; } // static CefRefPtr CefBrowserViewImpl::Create( CefRefPtr client, const CefString& url, const CefBrowserSettings& settings, CefRefPtr extra_info, CefRefPtr request_context, CefRefPtr delegate) { REQUIRE_ALLOY_RUNTIME(); CEF_REQUIRE_UIT_RETURN(nullptr); CefRefPtr browser_view = new CefBrowserViewImpl(delegate); browser_view->SetPendingBrowserCreateParams(client, url, settings, extra_info, request_context); browser_view->Initialize(); browser_view->SetDefaults(settings); return browser_view; } // static CefRefPtr CefBrowserViewImpl::CreateForPopup( const CefBrowserSettings& settings, CefRefPtr delegate) { REQUIRE_ALLOY_RUNTIME(); CEF_REQUIRE_UIT_RETURN(nullptr); CefRefPtr browser_view = new CefBrowserViewImpl(delegate); browser_view->Initialize(); browser_view->SetDefaults(settings); return browser_view; } void CefBrowserViewImpl::WebContentsCreated( content::WebContents* web_contents) { if (root_view()) root_view()->SetWebContents(web_contents); } void CefBrowserViewImpl::BrowserCreated( CefBrowserHostBase* browser, base::RepeatingClosure on_bounds_changed) { browser_ = browser; on_bounds_changed_ = on_bounds_changed; } void CefBrowserViewImpl::BrowserDestroyed(CefBrowserHostBase* browser) { DCHECK_EQ(browser, browser_); browser_ = nullptr; if (root_view()) root_view()->SetWebContents(nullptr); } bool CefBrowserViewImpl::HandleKeyboardEvent( const content::NativeWebKeyboardEvent& event) { if (!root_view()) return false; views::FocusManager* focus_manager = root_view()->GetFocusManager(); if (!focus_manager) return false; if (HandleAccelerator(event, focus_manager)) return true; // Give the CefWindowDelegate a chance to handle the event. CefRefPtr window = view_util::GetWindowFor(root_view()->GetWidget()); CefWindowImpl* window_impl = static_cast(window.get()); if (window_impl) { CefKeyEvent cef_event; if (browser_util::GetCefKeyEvent(event, cef_event) && window_impl->OnKeyEvent(cef_event)) { return true; } } // Proceed with default native handling. return unhandled_keyboard_event_handler_.HandleKeyboardEvent(event, focus_manager); } CefRefPtr CefBrowserViewImpl::GetBrowser() { CEF_REQUIRE_VALID_RETURN(nullptr); return browser_; } void CefBrowserViewImpl::SetPreferAccelerators(bool prefer_accelerators) { CEF_REQUIRE_VALID_RETURN_VOID(); if (root_view()) root_view()->set_allow_accelerators(prefer_accelerators); } void CefBrowserViewImpl::SetBackgroundColor(cef_color_t color) { CEF_REQUIRE_VALID_RETURN_VOID(); ParentClass::SetBackgroundColor(color); if (root_view()) root_view()->SetResizeBackgroundColor(color); } void CefBrowserViewImpl::Detach() { ParentClass::Detach(); // root_view() will be nullptr now. DCHECK(!root_view()); if (browser_) { // |browser_| will disappear when WindowDestroyed() indirectly calls // BrowserDestroyed() so keep a reference. CefRefPtr browser = browser_; // Force the browser to be destroyed. static_cast(browser.get())->WindowDestroyed(); } } void CefBrowserViewImpl::GetDebugInfo(base::DictionaryValue* info, bool include_children) { ParentClass::GetDebugInfo(info, include_children); if (browser_) info->SetString("url", browser_->GetMainFrame()->GetURL().ToString()); } void CefBrowserViewImpl::OnBrowserViewAdded() { if (!browser_ && pending_browser_create_params_) { // Top-level browsers will be created when this view is added to the views // hierarchy. pending_browser_create_params_->browser_view = this; AlloyBrowserHostImpl::Create(*pending_browser_create_params_); DCHECK(browser_); pending_browser_create_params_.reset(nullptr); } } void CefBrowserViewImpl::OnBoundsChanged() { if (!on_bounds_changed_.is_null()) on_bounds_changed_.Run(); } CefBrowserViewImpl::CefBrowserViewImpl( CefRefPtr delegate) : ParentClass(delegate) {} void CefBrowserViewImpl::SetPendingBrowserCreateParams( CefRefPtr client, const CefString& url, const CefBrowserSettings& settings, CefRefPtr extra_info, CefRefPtr request_context) { DCHECK(!pending_browser_create_params_); pending_browser_create_params_.reset(new CefBrowserCreateParams()); pending_browser_create_params_->client = client; pending_browser_create_params_->url = GURL(url.ToString()); pending_browser_create_params_->settings = settings; pending_browser_create_params_->extra_info = extra_info; pending_browser_create_params_->request_context = request_context; } void CefBrowserViewImpl::SetDefaults(const CefBrowserSettings& settings) { SetBackgroundColor( CefContext::Get()->GetBackgroundColor(&settings, STATE_DISABLED)); } CefBrowserViewView* CefBrowserViewImpl::CreateRootView() { return new CefBrowserViewView(delegate(), this); } void CefBrowserViewImpl::InitializeRootView() { static_cast(root_view())->Initialize(); } bool CefBrowserViewImpl::HandleAccelerator( const content::NativeWebKeyboardEvent& event, views::FocusManager* focus_manager) { // Previous calls to TranslateMessage can generate Char events as well as // RawKeyDown events, even if the latter triggered an accelerator. In these // cases, we discard the Char events. if (event.GetType() == blink::WebInputEvent::Type::kChar && ignore_next_char_event_) { ignore_next_char_event_ = false; return true; } // It's necessary to reset this flag, because a RawKeyDown event may not // always generate a Char event. ignore_next_char_event_ = false; if (event.GetType() == blink::WebInputEvent::Type::kRawKeyDown) { ui::Accelerator accelerator = ui::GetAcceleratorFromNativeWebKeyboardEvent(event); // This is tricky: we want to set ignore_next_char_event_ if // ProcessAccelerator returns true. But ProcessAccelerator might delete // |this| if the accelerator is a "close tab" one. So we speculatively // set the flag and fix it if no event was handled. ignore_next_char_event_ = true; if (focus_manager->ProcessAccelerator(accelerator)) return true; // ProcessAccelerator didn't handle the accelerator, so we know both // that |this| is still valid, and that we didn't want to set the flag. ignore_next_char_event_ = false; } return false; }