1diff --git chrome/browser/ui/browser_command_controller.cc chrome/browser/ui/browser_command_controller.cc 2index b0bde494f7b6..19b11ac5766d 100644 3--- chrome/browser/ui/browser_command_controller.cc 4+++ chrome/browser/ui/browser_command_controller.cc 5@@ -354,8 +354,10 @@ bool BrowserCommandController::ExecuteCommandWithDisposition( 6 // CommandUpdaterDelegate and CommandUpdater declare this function so we 7 // choose to not implement CommandUpdaterDelegate inside this class and 8 // therefore command_updater_ doesn't have the delegate set). 9- if (!SupportsCommand(id) || !IsCommandEnabled(id)) 10+ if (!SupportsCommand(id) || !IsCommandEnabled(id)) { 11+ LOG(WARNING) << "Invalid/disabled command " << id; 12 return false; 13+ } 14 15 // No commands are enabled if there is not yet any selected tab. 16 // TODO(pkasting): It seems like we should not need this, because either 17@@ -952,11 +954,13 @@ void BrowserCommandController::TabRestoreServiceLoaded( 18 // BrowserCommandController, private: 19 20 bool BrowserCommandController::IsShowingMainUI() { 21- return browser_->SupportsWindowFeature(Browser::FEATURE_TABSTRIP); 22+ return browser_->SupportsWindowFeature(Browser::FEATURE_TABSTRIP) || 23+ browser_->toolbar_overridden(); 24 } 25 26 bool BrowserCommandController::IsShowingLocationBar() { 27- return browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR); 28+ return browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR) || 29+ browser_->toolbar_overridden(); 30 } 31 32 void BrowserCommandController::InitCommandState() { 33diff --git chrome/browser/ui/views/frame/browser_frame.cc chrome/browser/ui/views/frame/browser_frame.cc 34index 5aff6e51d218..55a95564fb82 100644 35--- chrome/browser/ui/views/frame/browser_frame.cc 36+++ chrome/browser/ui/views/frame/browser_frame.cc 37@@ -65,15 +65,23 @@ bool IsUsingGtkTheme(Profile* profile) { 38 //////////////////////////////////////////////////////////////////////////////// 39 // BrowserFrame, public: 40 41+BrowserFrame::BrowserFrame() : BrowserFrame(nullptr) {} 42+ 43 BrowserFrame::BrowserFrame(BrowserView* browser_view) 44 : native_browser_frame_(nullptr), 45 root_view_(nullptr), 46 browser_frame_view_(nullptr), 47- browser_view_(browser_view) { 48- browser_view_->set_frame(this); 49+ browser_view_(nullptr) { 50 set_is_secondary_widget(false); 51 // Don't focus anything on creation, selecting a tab will set the focus. 52 set_focus_on_creation(false); 53+ if (browser_view) 54+ InitBrowserView(browser_view); 55+} 56+ 57+void BrowserFrame::InitBrowserView(BrowserView* browser_view) { 58+ browser_view_ = browser_view; 59+ browser_view_->set_frame(this); 60 } 61 62 BrowserFrame::~BrowserFrame() {} 63@@ -132,6 +140,12 @@ gfx::Rect BrowserFrame::GetBoundsForTabStripRegion( 64 } 65 66 int BrowserFrame::GetTopInset() const { 67+ if (!browser_frame_view_) { 68+ // With CEF the browser may already be part of a larger Views layout. Zero 69+ // out the adjustment in BrowserView::GetTopInsetInBrowserView() so that 70+ // the browser isn't shifted to the top of the window. 71+ return browser_view_->y(); 72+ } 73 return browser_frame_view_->GetTopInset(false); 74 } 75 76@@ -166,15 +180,21 @@ void BrowserFrame::GetWindowPlacement(gfx::Rect* bounds, 77 78 content::KeyboardEventProcessingResult BrowserFrame::PreHandleKeyboardEvent( 79 const content::NativeWebKeyboardEvent& event) { 80+ if (!native_browser_frame_) 81+ return content::KeyboardEventProcessingResult::NOT_HANDLED; 82 return native_browser_frame_->PreHandleKeyboardEvent(event); 83 } 84 85 bool BrowserFrame::HandleKeyboardEvent( 86 const content::NativeWebKeyboardEvent& event) { 87+ if (!native_browser_frame_) 88+ return false; 89 return native_browser_frame_->HandleKeyboardEvent(event); 90 } 91 92 void BrowserFrame::OnBrowserViewInitViewsComplete() { 93+ if (!browser_frame_view_) 94+ return; 95 browser_frame_view_->OnBrowserViewInitViewsComplete(); 96 } 97 98@@ -207,7 +227,8 @@ const ui::ThemeProvider* BrowserFrame::GetThemeProvider() const { 99 } 100 101 const ui::NativeTheme* BrowserFrame::GetNativeTheme() const { 102- if (browser_view_->browser()->profile()->IsIncognitoProfile() && 103+ if (browser_view_ && 104+ browser_view_->browser()->profile()->IsIncognitoProfile() && 105 ThemeServiceFactory::GetForProfile(browser_view_->browser()->profile()) 106 ->UsingDefaultTheme()) { 107 return ui::NativeTheme::GetInstanceForDarkUI(); 108diff --git chrome/browser/ui/views/frame/browser_frame.h chrome/browser/ui/views/frame/browser_frame.h 109index 050c0e05e4e3..0bbcf4af9a92 100644 110--- chrome/browser/ui/views/frame/browser_frame.h 111+++ chrome/browser/ui/views/frame/browser_frame.h 112@@ -53,7 +53,9 @@ enum class TabDragKind { 113 // This is a virtual interface that allows system specific browser frames. 114 class BrowserFrame : public views::Widget, public views::ContextMenuController { 115 public: 116+ BrowserFrame(); 117 explicit BrowserFrame(BrowserView* browser_view); 118+ void InitBrowserView(BrowserView* browser_view); 119 ~BrowserFrame() override; 120 121 // Initialize the frame (creates the underlying native window). 122diff --git chrome/browser/ui/views/frame/browser_view.cc chrome/browser/ui/views/frame/browser_view.cc 123index c33c4327974e..fe470132a090 100644 124--- chrome/browser/ui/views/frame/browser_view.cc 125+++ chrome/browser/ui/views/frame/browser_view.cc 126@@ -576,11 +576,22 @@ class BrowserView::AccessibilityModeObserver : public ui::AXModeObserver { 127 /////////////////////////////////////////////////////////////////////////////// 128 // BrowserView, public: 129 130+BrowserView::BrowserView() : BrowserView(nullptr) {} 131+ 132 BrowserView::BrowserView(std::unique_ptr<Browser> browser) 133 : views::ClientView(nullptr, nullptr), 134- browser_(std::move(browser)), 135 accessibility_mode_observer_( 136 std::make_unique<AccessibilityModeObserver>(this)) { 137+ if (browser) 138+ InitBrowser(std::move(browser)); 139+} 140+ 141+void BrowserView::InitBrowser(std::unique_ptr<Browser> browser) { 142+ DCHECK(!browser_); 143+ browser_ = std::move(browser); 144+ 145+ immersive_mode_controller_ = chrome::CreateImmersiveModeController(); 146+ 147 SetShowIcon(::ShouldShowWindowIcon(browser_.get())); 148 149 // In forced app mode, all size controls are always disabled. Otherwise, use 150@@ -594,7 +605,6 @@ BrowserView::BrowserView(std::unique_ptr<Browser> browser) 151 } 152 153 browser_->tab_strip_model()->AddObserver(this); 154- immersive_mode_controller_ = chrome::CreateImmersiveModeController(); 155 156 // Top container holds tab strip region and toolbar and lives at the front of 157 // the view hierarchy. 158@@ -638,8 +648,15 @@ BrowserView::BrowserView(std::unique_ptr<Browser> browser) 159 contents_container->SetLayoutManager(std::make_unique<ContentsLayoutManager>( 160 devtools_web_view_, contents_web_view_)); 161 162- toolbar_ = top_container_->AddChildView( 163- std::make_unique<ToolbarView>(browser_.get(), this)); 164+ toolbar_ = OverrideCreateToolbar(browser_.get(), this); 165+ if (!toolbar_) { 166+ toolbar_ = new ToolbarView(browser_.get(), this, base::nullopt); 167+ } else { 168+ browser_->set_toolbar_overridden(true); 169+ // Update state that depends on the above flag. 170+ browser_->command_controller()->FullscreenStateChanged(); 171+ } 172+ top_container_->AddChildView(base::WrapUnique(toolbar_)); 173 174 contents_separator_ = 175 top_container_->AddChildView(std::make_unique<ContentsSeparator>()); 176@@ -1407,6 +1424,8 @@ bool BrowserView::ShouldHideUIForFullscreen() const { 177 if (immersive_mode_controller_->IsEnabled()) 178 return false; 179 180+ if (!frame_->GetFrameView()) 181+ return false; 182 return frame_->GetFrameView()->ShouldHideTopUIForFullscreen(); 183 } 184 185@@ -2427,7 +2446,8 @@ BrowserView::GetNativeViewHostsForTopControlsSlide() const { 186 } 187 188 void BrowserView::ReparentTopContainerForEndOfImmersive() { 189- overlay_view_->SetVisible(false); 190+ if (overlay_view_) 191+ overlay_view_->SetVisible(false); 192 top_container()->DestroyLayer(); 193 AddChildViewAt(top_container(), 0); 194 EnsureFocusOrder(); 195@@ -2889,8 +2909,10 @@ void BrowserView::Layout() { 196 197 // TODO(jamescook): Why was this in the middle of layout code? 198 toolbar_->location_bar()->omnibox_view()->SetFocusBehavior( 199- IsToolbarVisible() ? FocusBehavior::ALWAYS : FocusBehavior::NEVER); 200- frame()->GetFrameView()->UpdateMinimumSize(); 201+ (IsToolbarVisible() || browser_->toolbar_overridden()) ? 202+ FocusBehavior::ALWAYS : FocusBehavior::NEVER); 203+ if (frame()->GetFrameView()) 204+ frame()->GetFrameView()->UpdateMinimumSize(); 205 206 // Some of the situations when the BrowserView is laid out are: 207 // - Enter/exit immersive fullscreen mode. 208@@ -2947,6 +2969,11 @@ void BrowserView::AddedToWidget() { 209 SetThemeProfileForWindow(GetNativeWindow(), browser_->profile()); 210 #endif 211 212+ // This browser view may already have a custom button provider set (e.g the 213+ // hosted app frame). 214+ if (!toolbar_button_provider_) 215+ SetToolbarButtonProvider(toolbar_); 216+ 217 toolbar_->Init(); 218 219 #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) 220@@ -2987,13 +3014,9 @@ void BrowserView::AddedToWidget() { 221 222 EnsureFocusOrder(); 223 224- // This browser view may already have a custom button provider set (e.g the 225- // hosted app frame). 226- if (!toolbar_button_provider_) 227- SetToolbarButtonProvider(toolbar_); 228- 229 frame_->OnBrowserViewInitViewsComplete(); 230- frame_->GetFrameView()->UpdateMinimumSize(); 231+ if (frame_->GetFrameView()) 232+ frame_->GetFrameView()->UpdateMinimumSize(); 233 using_native_frame_ = frame_->ShouldUseNativeFrame(); 234 235 MaybeInitializeWebUITabStrip(); 236diff --git chrome/browser/ui/views/frame/browser_view.h chrome/browser/ui/views/frame/browser_view.h 237index 59ddc0ac10f9..d5f04bfd7ca5 100644 238--- chrome/browser/ui/views/frame/browser_view.h 239+++ chrome/browser/ui/views/frame/browser_view.h 240@@ -112,7 +112,9 @@ class BrowserView : public BrowserWindow, 241 public webapps::AppBannerManager::Observer { 242 public: 243 METADATA_HEADER(BrowserView); 244+ BrowserView(); 245 explicit BrowserView(std::unique_ptr<Browser> browser); 246+ void InitBrowser(std::unique_ptr<Browser> browser); 247 BrowserView(const BrowserView&) = delete; 248 BrowserView& operator=(const BrowserView&) = delete; 249 ~BrowserView() override; 250@@ -624,6 +626,12 @@ class BrowserView : public BrowserWindow, 251 return accessibility_focus_highlight_.get(); 252 } 253 254+ protected: 255+ virtual ToolbarView* OverrideCreateToolbar(Browser* browser, 256+ BrowserView* browser_view) { 257+ return nullptr; 258+ } 259+ 260 private: 261 // Do not friend BrowserViewLayout. Use the BrowserViewLayoutDelegate 262 // interface to keep these two classes decoupled and testable. 263diff --git chrome/browser/ui/views/frame/browser_view_layout.cc chrome/browser/ui/views/frame/browser_view_layout.cc 264index 56ef53cf379d..f0f1057896bd 100644 265--- chrome/browser/ui/views/frame/browser_view_layout.cc 266+++ chrome/browser/ui/views/frame/browser_view_layout.cc 267@@ -415,6 +415,12 @@ int BrowserViewLayout::LayoutWebUITabStrip(int top) { 268 269 int BrowserViewLayout::LayoutToolbar(int top) { 270 TRACE_EVENT0("ui", "BrowserViewLayout::LayoutToolbar"); 271+ if (toolbar_->parent() && toolbar_->parent()->GetLayoutManager() != this && 272+ toolbar_->parent()->GetLayoutManager() != nullptr) { 273+ // CEF may take ownership of the toolbar. Early exit to avoid the DCHECK 274+ // in LayoutManager::SetViewVisibility(). 275+ return top; 276+ } 277 int browser_view_width = vertical_layout_rect_.width(); 278 bool toolbar_visible = delegate_->IsToolbarVisible(); 279 int height = toolbar_visible ? toolbar_->GetPreferredSize().height() : 0; 280diff --git chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc 281index 8f35534df18f..c29ebc024aa2 100644 282--- chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc 283+++ chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc 284@@ -580,37 +580,53 @@ gfx::Range BrowserTabStripController::ListTabsInGroup( 285 } 286 287 bool BrowserTabStripController::IsFrameCondensed() const { 288+ if (!GetFrameView()) 289+ return false; 290 return GetFrameView()->IsFrameCondensed(); 291 } 292 293 bool BrowserTabStripController::HasVisibleBackgroundTabShapes() const { 294+ if (!GetFrameView()) 295+ return false; 296 return GetFrameView()->HasVisibleBackgroundTabShapes( 297 BrowserFrameActiveState::kUseCurrent); 298 } 299 300 bool BrowserTabStripController::EverHasVisibleBackgroundTabShapes() const { 301+ if (!GetFrameView()) 302+ return false; 303 return GetFrameView()->EverHasVisibleBackgroundTabShapes(); 304 } 305 306 bool BrowserTabStripController::ShouldPaintAsActiveFrame() const { 307+ if (!GetFrameView()) 308+ return false; 309 return GetFrameView()->ShouldPaintAsActive(); 310 } 311 312 bool BrowserTabStripController::CanDrawStrokes() const { 313+ if (!GetFrameView()) 314+ return false; 315 return GetFrameView()->CanDrawStrokes(); 316 } 317 318 SkColor BrowserTabStripController::GetFrameColor( 319 BrowserFrameActiveState active_state) const { 320+ if (!GetFrameView()) 321+ return SK_ColorWHITE; 322 return GetFrameView()->GetFrameColor(active_state); 323 } 324 325 SkColor BrowserTabStripController::GetToolbarTopSeparatorColor() const { 326+ if (!GetFrameView()) 327+ return SK_ColorWHITE; 328 return GetFrameView()->GetToolbarTopSeparatorColor(); 329 } 330 331 base::Optional<int> BrowserTabStripController::GetCustomBackgroundId( 332 BrowserFrameActiveState active_state) const { 333+ if (!GetFrameView()) 334+ return base::nullopt; 335 return GetFrameView()->GetCustomBackgroundId(active_state); 336 } 337 338diff --git chrome/browser/ui/views/toolbar/toolbar_view.cc chrome/browser/ui/views/toolbar/toolbar_view.cc 339index 5f6e182d017d..be85e6df707d 100644 340--- chrome/browser/ui/views/toolbar/toolbar_view.cc 341+++ chrome/browser/ui/views/toolbar/toolbar_view.cc 342@@ -156,12 +156,13 @@ auto& GetViewCommandMap() { 343 //////////////////////////////////////////////////////////////////////////////// 344 // ToolbarView, public: 345 346-ToolbarView::ToolbarView(Browser* browser, BrowserView* browser_view) 347+ToolbarView::ToolbarView(Browser* browser, BrowserView* browser_view, 348+ base::Optional<DisplayMode> display_mode) 349 : AnimationDelegateViews(this), 350 browser_(browser), 351 browser_view_(browser_view), 352 app_menu_icon_controller_(browser->profile(), this), 353- display_mode_(GetDisplayMode(browser)) { 354+ display_mode_(display_mode ? *display_mode : GetDisplayMode(browser)) { 355 SetID(VIEW_ID_TOOLBAR); 356 357 UpgradeDetector::GetInstance()->AddObserver(this); 358@@ -194,7 +195,7 @@ void ToolbarView::Init() { 359 #endif 360 auto location_bar = std::make_unique<LocationBarView>( 361 browser_, browser_->profile(), browser_->command_controller(), this, 362- display_mode_ != DisplayMode::NORMAL); 363+ display_mode_ != DisplayMode::NORMAL && !browser_->toolbar_overridden()); 364 // Make sure the toolbar shows by default. 365 size_animation_.Reset(1); 366 367diff --git chrome/browser/ui/views/toolbar/toolbar_view.h chrome/browser/ui/views/toolbar/toolbar_view.h 368index 99358217419a..425a0741b55a 100644 369--- chrome/browser/ui/views/toolbar/toolbar_view.h 370+++ chrome/browser/ui/views/toolbar/toolbar_view.h 371@@ -87,7 +87,8 @@ class ToolbarView : public views::AccessiblePaneView, 372 // needs to be displayed. 373 }; 374 375- ToolbarView(Browser* browser, BrowserView* browser_view); 376+ ToolbarView(Browser* browser, BrowserView* browser_view, 377+ base::Optional<DisplayMode> display_mode); 378 ToolbarView(const ToolbarView&) = delete; 379 ToolbarView& operator=(const ToolbarView&) = delete; 380 ~ToolbarView() override; 381