diff --git chrome/browser/ui/browser_command_controller.cc chrome/browser/ui/browser_command_controller.cc index 408fcb87b6bf3..4efc0e48dcb5a 100644 --- chrome/browser/ui/browser_command_controller.cc +++ chrome/browser/ui/browser_command_controller.cc @@ -368,8 +368,10 @@ bool BrowserCommandController::ExecuteCommandWithDisposition( // CommandUpdaterDelegate and CommandUpdater declare this function so we // choose to not implement CommandUpdaterDelegate inside this class and // therefore command_updater_ doesn't have the delegate set). - if (!SupportsCommand(id) || !IsCommandEnabled(id)) + if (!SupportsCommand(id) || !IsCommandEnabled(id)) { + LOG(WARNING) << "Invalid/disabled command " << id; return false; + } // No commands are enabled if there is not yet any selected tab. // TODO(pkasting): It seems like we should not need this, because either @@ -979,11 +981,13 @@ void BrowserCommandController::TabRestoreServiceLoaded( // BrowserCommandController, private: bool BrowserCommandController::IsShowingMainUI() { - return browser_->SupportsWindowFeature(Browser::FEATURE_TABSTRIP); + return browser_->SupportsWindowFeature(Browser::FEATURE_TABSTRIP) || + browser_->toolbar_overridden(); } bool BrowserCommandController::IsShowingLocationBar() { - return browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR); + return browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR) || + browser_->toolbar_overridden(); } void BrowserCommandController::InitCommandState() { diff --git chrome/browser/ui/views/frame/browser_frame.cc chrome/browser/ui/views/frame/browser_frame.cc index 28cb0acd5a55d..f22ac22d04245 100644 --- chrome/browser/ui/views/frame/browser_frame.cc +++ chrome/browser/ui/views/frame/browser_frame.cc @@ -73,15 +73,23 @@ bool IsUsingGtkTheme(Profile* profile) { //////////////////////////////////////////////////////////////////////////////// // BrowserFrame, public: +BrowserFrame::BrowserFrame() : BrowserFrame(nullptr) {} + BrowserFrame::BrowserFrame(BrowserView* browser_view) : native_browser_frame_(nullptr), root_view_(nullptr), browser_frame_view_(nullptr), - browser_view_(browser_view) { - browser_view_->set_frame(this); + browser_view_(nullptr) { set_is_secondary_widget(false); // Don't focus anything on creation, selecting a tab will set the focus. set_focus_on_creation(false); + if (browser_view) + InitBrowserView(browser_view); +} + +void BrowserFrame::InitBrowserView(BrowserView* browser_view) { + browser_view_ = browser_view; + browser_view_->set_frame(this); } BrowserFrame::~BrowserFrame() {} @@ -141,6 +149,12 @@ gfx::Rect BrowserFrame::GetBoundsForTabStripRegion( } int BrowserFrame::GetTopInset() const { + if (!browser_frame_view_) { + // With CEF the browser may already be part of a larger Views layout. Zero + // out the adjustment in BrowserView::GetTopInsetInBrowserView() so that + // the browser isn't shifted to the top of the window. + return browser_view_->y(); + } return browser_frame_view_->GetTopInset(false); } @@ -175,15 +189,21 @@ void BrowserFrame::GetWindowPlacement(gfx::Rect* bounds, content::KeyboardEventProcessingResult BrowserFrame::PreHandleKeyboardEvent( const content::NativeWebKeyboardEvent& event) { + if (!native_browser_frame_) + return content::KeyboardEventProcessingResult::NOT_HANDLED; return native_browser_frame_->PreHandleKeyboardEvent(event); } bool BrowserFrame::HandleKeyboardEvent( const content::NativeWebKeyboardEvent& event) { + if (!native_browser_frame_) + return false; return native_browser_frame_->HandleKeyboardEvent(event); } void BrowserFrame::OnBrowserViewInitViewsComplete() { + if (!browser_frame_view_) + return; browser_frame_view_->OnBrowserViewInitViewsComplete(); } @@ -244,6 +264,8 @@ const ui::ThemeProvider* BrowserFrame::GetThemeProvider() const { ui::ColorProviderManager::InitializerSupplier* BrowserFrame::GetCustomTheme() const { + if (!browser_view_) + return nullptr; Browser* browser = browser_view_->browser(); auto* app_controller = browser->app_controller(); // Ignore GTK+ for web apps with window-controls-overlay as the @@ -369,7 +391,8 @@ void BrowserFrame::SelectNativeTheme() { // Select between regular, dark and GTK theme. ui::NativeTheme* native_theme = ui::NativeTheme::GetInstanceForNativeUi(); - if (browser_view_->browser()->profile()->IsIncognitoProfile()) { + if (browser_view_ && + browser_view_->browser()->profile()->IsIncognitoProfile()) { // If the flag is enabled, then no matter if we are using the default theme // or not we always use the dark ui instance. if (base::FeatureList::IsEnabled( diff --git chrome/browser/ui/views/frame/browser_frame.h chrome/browser/ui/views/frame/browser_frame.h index 6a1e9abbc66aa..aa9e3ebe2599c 100644 --- chrome/browser/ui/views/frame/browser_frame.h +++ chrome/browser/ui/views/frame/browser_frame.h @@ -53,7 +53,9 @@ enum class TabDragKind { // This is a virtual interface that allows system specific browser frames. class BrowserFrame : public views::Widget, public views::ContextMenuController { public: + BrowserFrame(); explicit BrowserFrame(BrowserView* browser_view); + void InitBrowserView(BrowserView* browser_view); BrowserFrame(const BrowserFrame&) = delete; BrowserFrame& operator=(const BrowserFrame&) = delete; diff --git chrome/browser/ui/views/frame/browser_view.cc chrome/browser/ui/views/frame/browser_view.cc index 3c6fcbebb84bb..f2eb23d39e5ee 100644 --- chrome/browser/ui/views/frame/browser_view.cc +++ chrome/browser/ui/views/frame/browser_view.cc @@ -291,11 +291,10 @@ using content::WebContents; using views::ColumnSet; using web_modal::WebContentsModalDialogHost; -namespace { +// static +const char BrowserView::kBrowserViewKey[] = "__BROWSER_VIEW__"; -// The name of a key to store on the window handle so that other code can -// locate this object using just the handle. -const char* const kBrowserViewKey = "__BROWSER_VIEW__"; +namespace { #if BUILDFLAG(IS_CHROMEOS_ASH) // UMA histograms that record animation smoothness for tab loading animation. @@ -677,11 +676,22 @@ class BrowserView::SidePanelButtonHighlighter : public views::ViewObserver { /////////////////////////////////////////////////////////////////////////////// // BrowserView, public: +BrowserView::BrowserView() : BrowserView(nullptr) {} + BrowserView::BrowserView(std::unique_ptr browser) : views::ClientView(nullptr, nullptr), - browser_(std::move(browser)), accessibility_mode_observer_( std::make_unique(this)) { + if (browser) + InitBrowser(std::move(browser)); +} + +void BrowserView::InitBrowser(std::unique_ptr browser) { + DCHECK(!browser_); + browser_ = std::move(browser); + + immersive_mode_controller_ = chrome::CreateImmersiveModeController(); + SetShowIcon(::ShouldShowWindowIcon(browser_.get())); // In forced app mode, all size controls are always disabled. Otherwise, use @@ -695,7 +705,6 @@ BrowserView::BrowserView(std::unique_ptr browser) } browser_->tab_strip_model()->AddObserver(this); - immersive_mode_controller_ = chrome::CreateImmersiveModeController(); // Top container holds tab strip region and toolbar and lives at the front of // the view hierarchy. @@ -741,8 +750,15 @@ BrowserView::BrowserView(std::unique_ptr browser) contents_container->SetLayoutManager(std::make_unique( devtools_web_view_, contents_web_view_)); - toolbar_ = top_container_->AddChildView( - std::make_unique(browser_.get(), this)); + toolbar_ = OverrideCreateToolbar(browser_.get(), this); + if (!toolbar_) { + toolbar_ = new ToolbarView(browser_.get(), this, absl::nullopt); + } else { + browser_->set_toolbar_overridden(true); + // Update state that depends on the above flag. + browser_->command_controller()->FullscreenStateChanged(); + } + top_container_->AddChildView(base::WrapUnique(toolbar_.get())); contents_separator_ = top_container_->AddChildView(std::make_unique()); @@ -1579,6 +1595,8 @@ bool BrowserView::ShouldHideUIForFullscreen() const { if (immersive_mode_controller_->IsEnabled()) return false; + if (!frame_->GetFrameView()) + return false; return frame_->GetFrameView()->ShouldHideTopUIForFullscreen(); } @@ -2725,7 +2743,8 @@ BrowserView::GetNativeViewHostsForTopControlsSlide() const { } void BrowserView::ReparentTopContainerForEndOfImmersive() { - overlay_view_->SetVisible(false); + if (overlay_view_) + overlay_view_->SetVisible(false); top_container()->DestroyLayer(); AddChildViewAt(top_container(), 0); EnsureFocusOrder(); @@ -3214,8 +3233,10 @@ void BrowserView::Layout() { // TODO(jamescook): Why was this in the middle of layout code? toolbar_->location_bar()->omnibox_view()->SetFocusBehavior( - IsToolbarVisible() ? FocusBehavior::ALWAYS : FocusBehavior::NEVER); - frame()->GetFrameView()->UpdateMinimumSize(); + (IsToolbarVisible() || browser_->toolbar_overridden()) ? + FocusBehavior::ALWAYS : FocusBehavior::NEVER); + if (frame()->GetFrameView()) + frame()->GetFrameView()->UpdateMinimumSize(); // Some of the situations when the BrowserView is laid out are: // - Enter/exit immersive fullscreen mode. @@ -3278,6 +3299,11 @@ void BrowserView::AddedToWidget() { SetThemeProfileForWindow(GetNativeWindow(), browser_->profile()); #endif + // This browser view may already have a custom button provider set (e.g the + // hosted app frame). + if (!toolbar_button_provider_) + SetToolbarButtonProvider(toolbar_); + toolbar_->Init(); // TODO(pbos): Manage this either inside SidePanel or the corresponding button @@ -3330,13 +3356,9 @@ void BrowserView::AddedToWidget() { EnsureFocusOrder(); - // This browser view may already have a custom button provider set (e.g the - // hosted app frame). - if (!toolbar_button_provider_) - SetToolbarButtonProvider(toolbar_); - frame_->OnBrowserViewInitViewsComplete(); - frame_->GetFrameView()->UpdateMinimumSize(); + if (frame_->GetFrameView()) + frame_->GetFrameView()->UpdateMinimumSize(); using_native_frame_ = frame_->ShouldUseNativeFrame(); MaybeInitializeWebUITabStrip(); @@ -3755,7 +3777,8 @@ void BrowserView::ProcessFullscreen(bool fullscreen, // Undo our anti-jankiness hacks and force a re-layout. in_process_fullscreen_ = false; ToolbarSizeChanged(false); - frame_->GetFrameView()->OnFullscreenStateChanged(); + if (frame_->GetFrameView()) + frame_->GetFrameView()->OnFullscreenStateChanged(); } bool BrowserView::ShouldUseImmersiveFullscreenForUrl(const GURL& url) const { @@ -4046,6 +4069,8 @@ Profile* BrowserView::GetProfile() { } void BrowserView::UpdateUIForTabFullscreen() { + if (!frame_->GetFrameView()) + return; frame()->GetFrameView()->UpdateFullscreenTopUI(); } @@ -4068,6 +4093,8 @@ void BrowserView::HideDownloadShelf() { } bool BrowserView::CanUserExitFullscreen() const { + if (!frame_->GetFrameView()) + return true; return frame_->GetFrameView()->CanUserExitFullscreen(); } diff --git chrome/browser/ui/views/frame/browser_view.h chrome/browser/ui/views/frame/browser_view.h index 6eea8b4b899e2..4dc56c94baa3f 100644 --- chrome/browser/ui/views/frame/browser_view.h +++ chrome/browser/ui/views/frame/browser_view.h @@ -125,11 +125,16 @@ class BrowserView : public BrowserWindow, public webapps::AppBannerManager::Observer { public: METADATA_HEADER(BrowserView); + BrowserView(); explicit BrowserView(std::unique_ptr browser); + void InitBrowser(std::unique_ptr browser); BrowserView(const BrowserView&) = delete; BrowserView& operator=(const BrowserView&) = delete; ~BrowserView() override; + // Key used to bind BrowserView to the Widget with which it is associated. + static const char kBrowserViewKey[]; + void set_frame(BrowserFrame* frame) { frame_ = frame; } BrowserFrame* frame() const { return frame_; } @@ -705,6 +710,12 @@ class BrowserView : public BrowserWindow, const std::map& extra_data) override; #endif + protected: + virtual ToolbarView* OverrideCreateToolbar(Browser* browser, + BrowserView* browser_view) { + return nullptr; + } + private: // Do not friend BrowserViewLayout. Use the BrowserViewLayoutDelegate // interface to keep these two classes decoupled and testable. diff --git chrome/browser/ui/views/frame/browser_view_layout.cc chrome/browser/ui/views/frame/browser_view_layout.cc index 1d22e4b057c6c..d73b547f09e0b 100644 --- chrome/browser/ui/views/frame/browser_view_layout.cc +++ chrome/browser/ui/views/frame/browser_view_layout.cc @@ -40,6 +40,10 @@ #include "ui/views/widget/widget.h" #include "ui/views/window/client_view.h" +#if BUILDFLAG(ENABLE_CEF) +#include "cef/libcef/browser/chrome/views/chrome_views_util.h" +#endif + using views::View; using web_modal::WebContentsModalDialogHost; using web_modal::ModalDialogHostObserver; @@ -458,6 +462,11 @@ int BrowserViewLayout::LayoutWebUITabStrip(int top) { int BrowserViewLayout::LayoutToolbar(int top) { TRACE_EVENT0("ui", "BrowserViewLayout::LayoutToolbar"); + if (cef::IsCefView(toolbar_)) { + // CEF may take ownership of the toolbar. Early exit to avoid the DCHECK + // in LayoutManager::SetViewVisibility(). + return top; + } int browser_view_width = vertical_layout_rect_.width(); bool toolbar_visible = delegate_->IsToolbarVisible(); int height = toolbar_visible ? toolbar_->GetPreferredSize().height() : 0; diff --git chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc index 504c0b746006d..f0952bad35e91 100644 --- chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc +++ chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc @@ -559,37 +559,53 @@ gfx::Range BrowserTabStripController::ListTabsInGroup( } bool BrowserTabStripController::IsFrameCondensed() const { + if (!GetFrameView()) + return false; return GetFrameView()->IsFrameCondensed(); } bool BrowserTabStripController::HasVisibleBackgroundTabShapes() const { + if (!GetFrameView()) + return false; return GetFrameView()->HasVisibleBackgroundTabShapes( BrowserFrameActiveState::kUseCurrent); } bool BrowserTabStripController::EverHasVisibleBackgroundTabShapes() const { + if (!GetFrameView()) + return false; return GetFrameView()->EverHasVisibleBackgroundTabShapes(); } bool BrowserTabStripController::ShouldPaintAsActiveFrame() const { + if (!GetFrameView()) + return false; return GetFrameView()->ShouldPaintAsActive(); } bool BrowserTabStripController::CanDrawStrokes() const { + if (!GetFrameView()) + return false; return GetFrameView()->CanDrawStrokes(); } SkColor BrowserTabStripController::GetFrameColor( BrowserFrameActiveState active_state) const { + if (!GetFrameView()) + return SK_ColorWHITE; return GetFrameView()->GetFrameColor(active_state); } SkColor BrowserTabStripController::GetToolbarTopSeparatorColor() const { + if (!GetFrameView()) + return SK_ColorWHITE; return GetFrameView()->GetToolbarTopSeparatorColor(); } absl::optional BrowserTabStripController::GetCustomBackgroundId( BrowserFrameActiveState active_state) const { + if (!GetFrameView()) + return absl::nullopt; return GetFrameView()->GetCustomBackgroundId(active_state); } diff --git chrome/browser/ui/views/toolbar/toolbar_view.cc chrome/browser/ui/views/toolbar/toolbar_view.cc index d11554470129d..e854e476c297b 100644 --- chrome/browser/ui/views/toolbar/toolbar_view.cc +++ chrome/browser/ui/views/toolbar/toolbar_view.cc @@ -167,12 +167,13 @@ auto& GetViewCommandMap() { //////////////////////////////////////////////////////////////////////////////// // ToolbarView, public: -ToolbarView::ToolbarView(Browser* browser, BrowserView* browser_view) +ToolbarView::ToolbarView(Browser* browser, BrowserView* browser_view, + absl::optional display_mode) : AnimationDelegateViews(this), browser_(browser), browser_view_(browser_view), app_menu_icon_controller_(browser->profile(), this), - display_mode_(GetDisplayMode(browser)) { + display_mode_(display_mode ? *display_mode : GetDisplayMode(browser)) { SetID(VIEW_ID_TOOLBAR); UpgradeDetector::GetInstance()->AddObserver(this); @@ -207,7 +208,7 @@ void ToolbarView::Init() { #endif auto location_bar = std::make_unique( browser_, browser_->profile(), browser_->command_controller(), this, - display_mode_ != DisplayMode::NORMAL); + display_mode_ != DisplayMode::NORMAL && !browser_->toolbar_overridden()); // Make sure the toolbar shows by default. size_animation_.Reset(1); diff --git chrome/browser/ui/views/toolbar/toolbar_view.h chrome/browser/ui/views/toolbar/toolbar_view.h index 8b929587548ec..835a665380277 100644 --- chrome/browser/ui/views/toolbar/toolbar_view.h +++ chrome/browser/ui/views/toolbar/toolbar_view.h @@ -92,7 +92,8 @@ class ToolbarView : public views::AccessiblePaneView, // needs to be displayed. }; - ToolbarView(Browser* browser, BrowserView* browser_view); + ToolbarView(Browser* browser, BrowserView* browser_view, + absl::optional display_mode); ToolbarView(const ToolbarView&) = delete; ToolbarView& operator=(const ToolbarView&) = delete; ~ToolbarView() override;