mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			1159 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			1159 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| diff --git chrome/browser/ui/browser_command_controller.cc chrome/browser/ui/browser_command_controller.cc
 | |
| index 47e19e2f12139..be792c0b0a12a 100644
 | |
| --- chrome/browser/ui/browser_command_controller.cc
 | |
| +++ chrome/browser/ui/browser_command_controller.cc
 | |
| @@ -421,6 +421,7 @@ bool BrowserCommandController::ExecuteCommandWithDisposition(
 | |
|    // choose to not implement CommandUpdaterDelegate inside this class and
 | |
|    // therefore command_updater_ doesn't have the delegate set).
 | |
|    if (!SupportsCommand(id) || !IsCommandEnabled(id)) {
 | |
| +    LOG(WARNING) << "Invalid/disabled command " << id;
 | |
|      return false;
 | |
|    }
 | |
|  
 | |
| @@ -438,6 +439,13 @@ bool BrowserCommandController::ExecuteCommandWithDisposition(
 | |
|    DCHECK(command_updater_.IsCommandEnabled(id))
 | |
|        << "Invalid/disabled command " << id;
 | |
|  
 | |
| +#if BUILDFLAG(ENABLE_CEF)
 | |
| +  if (browser_->cef_delegate() &&
 | |
| +      browser_->cef_delegate()->HandleCommand(id, disposition)) {
 | |
| +    return true;
 | |
| +  }
 | |
| +#endif
 | |
| +
 | |
|    // The order of commands in this switch statement must match the function
 | |
|    // declaration order in browser.h!
 | |
|    switch (id) {
 | |
| @@ -1211,11 +1219,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/toolbar/app_menu_model.cc chrome/browser/ui/toolbar/app_menu_model.cc
 | |
| index 6130205985f73..5505b44742fde 100644
 | |
| --- chrome/browser/ui/toolbar/app_menu_model.cc
 | |
| +++ chrome/browser/ui/toolbar/app_menu_model.cc
 | |
| @@ -733,10 +733,12 @@ FindAndEditSubMenuModel::FindAndEditSubMenuModel(
 | |
|      ui::SimpleMenuModel::Delegate* delegate)
 | |
|      : SimpleMenuModel(delegate) {
 | |
|    AddItemWithStringIdAndVectorIcon(this, IDC_FIND, IDS_FIND, kSearchMenuIcon);
 | |
| +  if (delegate->IsCommandIdVisible(IDC_EDIT_MENU)) {
 | |
|    AddSeparator(ui::NORMAL_SEPARATOR);
 | |
|    AddItemWithStringIdAndVectorIcon(this, IDC_CUT, IDS_CUT, kCutMenuIcon);
 | |
|    AddItemWithStringIdAndVectorIcon(this, IDC_COPY, IDS_COPY, kCopyMenuIcon);
 | |
|    AddItemWithStringIdAndVectorIcon(this, IDC_PASTE, IDS_PASTE, kPasteMenuIcon);
 | |
| +  }
 | |
|  }
 | |
|  
 | |
|  class SaveAndShareSubMenuModel : public ui::SimpleMenuModel {
 | |
| @@ -801,6 +803,57 @@ SaveAndShareSubMenuModel::SaveAndShareSubMenuModel(
 | |
|    }
 | |
|  }
 | |
|  
 | |
| +#if BUILDFLAG(ENABLE_CEF)
 | |
| +using IsVisibleCallback = base::RepeatingCallback<bool(int)>;
 | |
| +
 | |
| +void FilterMenuModel(ui::SimpleMenuModel* model,
 | |
| +                     const IsVisibleCallback& is_visible) {
 | |
| +  std::optional<size_t> last_separator;
 | |
| +  size_t visible_ct = 0;
 | |
| +  for (size_t i = 0; i < model->GetItemCount(); ++i) {
 | |
| +    const auto type = model->GetTypeAt(i);
 | |
| +    if (type == ui::MenuModel::TYPE_SEPARATOR) {
 | |
| +      if (last_separator) {
 | |
| +        // Remove multiple separators in a row. Prefer to remove a NORMAL
 | |
| +        // separator if possible (as compared to zoom/edit controls which use
 | |
| +        // UPPER/LOWER separators).
 | |
| +        if (model->GetSeparatorTypeAt(*last_separator) ==
 | |
| +            ui::NORMAL_SEPARATOR) {
 | |
| +          model->RemoveItemAt(*last_separator);
 | |
| +          i--;
 | |
| +          last_separator = i;
 | |
| +        } else {
 | |
| +          model->RemoveItemAt(i);
 | |
| +          i--;
 | |
| +        }
 | |
| +      } else if (visible_ct == 0) {
 | |
| +        // Remove leading separator.
 | |
| +        model->RemoveItemAt(i);
 | |
| +        i--;
 | |
| +      } else {
 | |
| +        last_separator = i;
 | |
| +      }
 | |
| +      visible_ct = 0;
 | |
| +    } else if (is_visible.Run(model->GetCommandIdAt(i))) {
 | |
| +      last_separator = std::nullopt;
 | |
| +      visible_ct++;
 | |
| +
 | |
| +      if (type == ui::MenuModel::TYPE_SUBMENU) {
 | |
| +        // Filter sub-menu.
 | |
| +        auto sub_model =
 | |
| +            static_cast<ui::SimpleMenuModel*>(model->GetSubmenuModelAt(i));
 | |
| +        FilterMenuModel(sub_model, is_visible);
 | |
| +      }
 | |
| +    }
 | |
| +  }
 | |
| +
 | |
| +  if (last_separator) {
 | |
| +    // Remove trailing separator.
 | |
| +    model->RemoveItemAt(*last_separator);
 | |
| +  }
 | |
| +}
 | |
| +#endif  // BUILDFLAG(ENABLE_CEF)
 | |
| +
 | |
|  }  // namespace
 | |
|  
 | |
|  ////////////////////////////////////////////////////////////////////////////////
 | |
| @@ -1730,7 +1783,7 @@ bool AppMenuModel::IsCommandIdChecked(int command_id) const {
 | |
|    return false;
 | |
|  }
 | |
|  
 | |
| -bool AppMenuModel::IsCommandIdEnabled(int command_id) const {
 | |
| +bool AppMenuModel::IsCommandIdEnabledInternal(int command_id) const {
 | |
|    GlobalError* error =
 | |
|        GlobalErrorServiceFactory::GetForProfile(browser_->profile())
 | |
|            ->GetGlobalErrorByMenuItemCommandID(command_id);
 | |
| @@ -1746,6 +1799,30 @@ bool AppMenuModel::IsCommandIdEnabled(int command_id) const {
 | |
|    }
 | |
|  }
 | |
|  
 | |
| +bool AppMenuModel::IsCommandIdEnabled(int command_id) const {
 | |
| +  if (!IsCommandIdEnabledInternal(command_id)) {
 | |
| +    return false;
 | |
| +  }
 | |
| +
 | |
| +#if BUILDFLAG(ENABLE_CEF)
 | |
| +  if (browser_->cef_delegate()) {
 | |
| +    return browser_->cef_delegate()->IsAppMenuItemEnabled(command_id);
 | |
| +  }
 | |
| +#endif
 | |
| +
 | |
| +  return true;
 | |
| +}
 | |
| +
 | |
| +bool AppMenuModel::IsCommandIdVisible(int command_id) const {
 | |
| +#if BUILDFLAG(ENABLE_CEF)
 | |
| +  if (browser_->cef_delegate()) {
 | |
| +    return browser_->cef_delegate()->IsAppMenuItemVisible(command_id);
 | |
| +  }
 | |
| +#endif
 | |
| +
 | |
| +  return true;
 | |
| +}
 | |
| +
 | |
|  bool AppMenuModel::IsCommandIdAlerted(int command_id) const {
 | |
|    if (command_id == IDC_VIEW_PASSWORDS ||
 | |
|        command_id == IDC_SHOW_PASSWORD_MANAGER) {
 | |
| @@ -1901,8 +1978,10 @@ void AppMenuModel::Build() {
 | |
|                                     IDS_CLEAR_BROWSING_DATA,
 | |
|                                     kTrashCanRefreshIcon);
 | |
|  
 | |
| +  if (IsCommandIdVisible(IDC_ZOOM_MENU)) {
 | |
|    AddSeparator(ui::NORMAL_SEPARATOR);
 | |
|    CreateZoomMenu();
 | |
| +  }
 | |
|    AddSeparator(ui::NORMAL_SEPARATOR);
 | |
|  
 | |
|    AddItemWithStringIdAndVectorIcon(this, IDC_PRINT, IDS_PRINT, kPrintMenuIcon);
 | |
| @@ -1997,6 +2076,11 @@ void AppMenuModel::Build() {
 | |
|    }
 | |
|  #endif  // !BUILDFLAG(IS_CHROMEOS)
 | |
|  
 | |
| +#if BUILDFLAG(ENABLE_CEF)
 | |
| +  FilterMenuModel(this, base::BindRepeating(&AppMenuModel::IsCommandIdVisible,
 | |
| +                                            base::Unretained(this)));
 | |
| +#endif
 | |
| +
 | |
|    uma_action_recorded_ = false;
 | |
|  }
 | |
|  
 | |
| diff --git chrome/browser/ui/toolbar/app_menu_model.h chrome/browser/ui/toolbar/app_menu_model.h
 | |
| index f5f5d8c1a8918..bebb784115c87 100644
 | |
| --- chrome/browser/ui/toolbar/app_menu_model.h
 | |
| +++ chrome/browser/ui/toolbar/app_menu_model.h
 | |
| @@ -232,6 +232,7 @@ class AppMenuModel : public ui::SimpleMenuModel,
 | |
|    void ExecuteCommand(int command_id, int event_flags) override;
 | |
|    bool IsCommandIdChecked(int command_id) const override;
 | |
|    bool IsCommandIdEnabled(int command_id) const override;
 | |
| +  bool IsCommandIdVisible(int command_id) const override;
 | |
|    bool IsCommandIdAlerted(int command_id) const override;
 | |
|    bool IsElementIdAlerted(ui::ElementIdentifier element_id) const override;
 | |
|    bool GetAcceleratorForCommandId(int command_id,
 | |
| @@ -272,6 +273,8 @@ class AppMenuModel : public ui::SimpleMenuModel,
 | |
|    void LogSafetyHubInteractionMetrics(safety_hub::SafetyHubModuleType sh_module,
 | |
|                                        int event_flags);
 | |
|  
 | |
| +  bool IsCommandIdEnabledInternal(int command_id) const;
 | |
| +
 | |
|   private:
 | |
|    // Adds actionable global error menu items to the menu.
 | |
|    // Examples: Extension permissions and sign in errors.
 | |
| diff --git chrome/browser/ui/views/find_bar_host.cc chrome/browser/ui/views/find_bar_host.cc
 | |
| index 38fe5a02de21d..2bd4508d5c024 100644
 | |
| --- chrome/browser/ui/views/find_bar_host.cc
 | |
| +++ chrome/browser/ui/views/find_bar_host.cc
 | |
| @@ -604,6 +604,14 @@ gfx::Rect FindBarHost::GetDialogPosition(gfx::Rect avoid_overlapping_rect) {
 | |
|    // The BrowserView does Layout for the components that we care about
 | |
|    // positioning relative to, so we ask it to tell us where we should go.
 | |
|    gfx::Rect find_bar_bounds = browser_view_->GetFindBarBoundingBox();
 | |
| +
 | |
| +#if BUILDFLAG(ENABLE_CEF)
 | |
| +  if (browser_view_->browser() && browser_view_->browser()->cef_delegate()) {
 | |
| +    browser_view_->browser()->cef_delegate()->UpdateFindBarBoundingBox(
 | |
| +        &find_bar_bounds);
 | |
| +  }
 | |
| +#endif
 | |
| +
 | |
|    if (find_bar_bounds.IsEmpty()) {
 | |
|      return gfx::Rect();
 | |
|    }
 | |
| diff --git chrome/browser/ui/views/frame/browser_frame.cc chrome/browser/ui/views/frame/browser_frame.cc
 | |
| index 806679c846f15..5c685e93631c8 100644
 | |
| --- chrome/browser/ui/views/frame/browser_frame.cc
 | |
| +++ chrome/browser/ui/views/frame/browser_frame.cc
 | |
| @@ -112,15 +112,25 @@ ui::ColorProviderKey::SchemeVariant GetSchemeVariant(
 | |
|  ////////////////////////////////////////////////////////////////////////////////
 | |
|  // 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)
 | |
| +    SetBrowserView(browser_view);
 | |
| +}
 | |
| +
 | |
| +void BrowserFrame::SetBrowserView(BrowserView* browser_view) {
 | |
| +  browser_view_ = browser_view;
 | |
| +  if (browser_view_) {
 | |
| +    browser_view_->set_frame(this);
 | |
| +  }
 | |
|  }
 | |
|  
 | |
|  BrowserFrame::~BrowserFrame() = default;
 | |
| @@ -226,10 +236,20 @@ void BrowserFrame::LayoutWebAppWindowTitle(
 | |
|  }
 | |
|  
 | |
|  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);
 | |
|  }
 | |
|  
 | |
|  void BrowserFrame::UpdateThrobber(bool running) {
 | |
| +  if (!browser_frame_view_) {
 | |
| +    // Not supported with CEF Views-hosted DevTools windows.
 | |
| +    return;
 | |
| +  }
 | |
|    browser_frame_view_->UpdateThrobber(running);
 | |
|  }
 | |
|  
 | |
| @@ -238,6 +258,8 @@ BrowserNonClientFrameView* BrowserFrame::GetFrameView() const {
 | |
|  }
 | |
|  
 | |
|  bool BrowserFrame::UseCustomFrame() const {
 | |
| +  if (!native_browser_frame_)
 | |
| +    return true;
 | |
|    return native_browser_frame_->UseCustomFrame();
 | |
|  }
 | |
|  
 | |
| @@ -252,20 +274,30 @@ bool BrowserFrame::ShouldDrawFrameHeader() const {
 | |
|  void BrowserFrame::GetWindowPlacement(
 | |
|      gfx::Rect* bounds,
 | |
|      ui::mojom::WindowShowState* show_state) const {
 | |
| +  if (!native_browser_frame_) {
 | |
| +    *show_state = ui::mojom::WindowShowState::kDefault;
 | |
| +    return;
 | |
| +  }
 | |
|    return native_browser_frame_->GetWindowPlacement(bounds, show_state);
 | |
|  }
 | |
|  
 | |
|  content::KeyboardEventProcessingResult BrowserFrame::PreHandleKeyboardEvent(
 | |
|      const input::NativeWebKeyboardEvent& event) {
 | |
| +  if (!native_browser_frame_)
 | |
| +    return content::KeyboardEventProcessingResult::NOT_HANDLED;
 | |
|    return native_browser_frame_->PreHandleKeyboardEvent(event);
 | |
|  }
 | |
|  
 | |
|  bool BrowserFrame::HandleKeyboardEvent(
 | |
|      const input::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();
 | |
|  }
 | |
|  
 | |
| @@ -366,6 +398,8 @@ ui::ColorProviderKey::ThemeInitializerSupplier* BrowserFrame::GetCustomTheme()
 | |
|  }
 | |
|  
 | |
|  void BrowserFrame::OnNativeWidgetWorkspaceChanged() {
 | |
| +  if (!browser_view_)
 | |
| +    return;
 | |
|    chrome::SaveWindowWorkspace(browser_view_->browser(), GetWorkspace());
 | |
|    chrome::SaveWindowVisibleOnAllWorkspaces(browser_view_->browser(),
 | |
|                                             IsVisibleOnAllWorkspaces());
 | |
| @@ -576,6 +610,13 @@ void BrowserFrame::SelectNativeTheme() {
 | |
|      return;
 | |
|    }
 | |
|  
 | |
| +  // Always use the NativeTheme for forced color modes.
 | |
| +  if (ui::NativeTheme::IsForcedDarkMode() ||
 | |
| +      ui::NativeTheme::IsForcedLightMode()) {
 | |
| +    SetNativeTheme(native_theme);
 | |
| +    return;
 | |
| +  }
 | |
| +
 | |
|    // Ignore the system theme for web apps with window-controls-overlay as the
 | |
|    // display_override so the web contents can blend with the overlay by using
 | |
|    // the developer-provided theme color for a better experience. Context:
 | |
| @@ -641,5 +682,8 @@ bool BrowserFrame::RegenerateFrameOnThemeChange(
 | |
|  }
 | |
|  
 | |
|  bool BrowserFrame::IsIncognitoBrowser() const {
 | |
| +  if (!browser_view_) {
 | |
| +    return true;
 | |
| +  }
 | |
|    return browser_view_->browser()->profile()->IsIncognitoProfile();
 | |
|  }
 | |
| diff --git chrome/browser/ui/views/frame/browser_frame.h chrome/browser/ui/views/frame/browser_frame.h
 | |
| index 3d8a15049d4d2..66c4789581fe1 100644
 | |
| --- chrome/browser/ui/views/frame/browser_frame.h
 | |
| +++ chrome/browser/ui/views/frame/browser_frame.h
 | |
| @@ -59,6 +59,7 @@ 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);
 | |
|  
 | |
|    BrowserFrame(const BrowserFrame&) = delete;
 | |
| @@ -138,7 +139,7 @@ class BrowserFrame : public views::Widget, public views::ContextMenuController {
 | |
|  
 | |
|    // ThemeService calls this when a user has changed their theme, indicating
 | |
|    // that it's time to redraw everything.
 | |
| -  void UserChangedTheme(BrowserThemeChangeType theme_change_type);
 | |
| +  virtual void UserChangedTheme(BrowserThemeChangeType theme_change_type);
 | |
|  
 | |
|    // views::Widget:
 | |
|    views::internal::RootView* CreateRootView() override;
 | |
| @@ -172,22 +173,26 @@ class BrowserFrame : public views::Widget, public views::ContextMenuController {
 | |
|    void SetTabDragKind(TabDragKind tab_drag_kind);
 | |
|    TabDragKind tab_drag_kind() const { return tab_drag_kind_; }
 | |
|  
 | |
| +  BrowserView* browser_view() const { return browser_view_.get(); }
 | |
| +
 | |
|   protected:
 | |
| +  void SetBrowserView(BrowserView* browser_view);
 | |
| +
 | |
|    // views::Widget:
 | |
|    void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override;
 | |
|    ui::ColorProviderKey GetColorProviderKey() const override;
 | |
|  
 | |
| +  // Select a native theme that is appropriate for the current context. This is
 | |
| +  // currently only needed for Linux to switch between the regular NativeTheme
 | |
| +  // and the GTK NativeTheme instance.
 | |
| +  void SelectNativeTheme();
 | |
| +
 | |
|   private:
 | |
|    void OnTouchUiChanged();
 | |
|  
 | |
|    // Callback for MenuRunner.
 | |
|    void OnMenuClosed();
 | |
|  
 | |
| -  // Select a native theme that is appropriate for the current context. This is
 | |
| -  // currently only needed for Linux to switch between the regular NativeTheme
 | |
| -  // and the GTK NativeTheme instance.
 | |
| -  void SelectNativeTheme();
 | |
| -
 | |
|    // Regenerate the frame on theme change if necessary. Returns true if
 | |
|    // regenerated.
 | |
|    bool RegenerateFrameOnThemeChange(BrowserThemeChangeType theme_change_type);
 | |
| diff --git chrome/browser/ui/views/frame/browser_view.cc chrome/browser/ui/views/frame/browser_view.cc
 | |
| index 127aa3ef3ba70..506cb33978bed 100644
 | |
| --- chrome/browser/ui/views/frame/browser_view.cc
 | |
| +++ chrome/browser/ui/views/frame/browser_view.cc
 | |
| @@ -363,10 +363,6 @@ using web_modal::WebContentsModalDialogHost;
 | |
|  
 | |
|  namespace {
 | |
|  
 | |
| -// 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__";
 | |
| -
 | |
|  #if BUILDFLAG(IS_CHROMEOS)
 | |
|  // UMA histograms that record animation smoothness for tab loading animation.
 | |
|  constexpr char kTabLoadingSmoothnessHistogramName[] =
 | |
| @@ -776,6 +772,14 @@ class BrowserViewLayoutDelegateImpl : public BrowserViewLayoutDelegate {
 | |
|      return browser_view_->frame()->GetTopInset() - browser_view_->y();
 | |
|    }
 | |
|  
 | |
| +  void UpdateDialogTopInsetInBrowserView(int* dialog_top_y) const override {
 | |
| +#if BUILDFLAG(ENABLE_CEF)
 | |
| +    if (auto cef_delegate = browser_view_->browser_->cef_delegate()) {
 | |
| +      cef_delegate->UpdateDialogTopInset(dialog_top_y);
 | |
| +    }
 | |
| +#endif
 | |
| +  }
 | |
| +
 | |
|    bool IsToolbarVisible() const override {
 | |
|      return browser_view_->IsToolbarVisible();
 | |
|    }
 | |
| @@ -927,11 +931,21 @@ class BrowserView::AccessibilityModeObserver : public ui::AXModeObserver {
 | |
|  ///////////////////////////////////////////////////////////////////////////////
 | |
|  // BrowserView, public:
 | |
|  
 | |
| +BrowserView::BrowserView() : BrowserView(nullptr) {}
 | |
| +
 | |
|  BrowserView::BrowserView(std::unique_ptr<Browser> browser)
 | |
|      : views::ClientView(nullptr, nullptr),
 | |
| -      browser_(std::move(browser)),
 | |
|        accessibility_mode_observer_(
 | |
|            std::make_unique<AccessibilityModeObserver>(this)) {
 | |
| +  if (browser) {
 | |
| +    InitBrowser(std::move(browser));
 | |
| +  }
 | |
| +}
 | |
| +
 | |
| +void BrowserView::InitBrowser(std::unique_ptr<Browser> browser) {
 | |
| +  DCHECK(!browser_);
 | |
| +  browser_ = std::move(browser);
 | |
| +
 | |
|    SetShowIcon(::ShouldShowWindowIcon(
 | |
|        browser_.get(), AppUsesWindowControlsOverlay(), AppUsesTabbed()));
 | |
|  
 | |
| @@ -1071,8 +1085,15 @@ BrowserView::BrowserView(std::unique_ptr<Browser> browser)
 | |
|        watermark_view_));
 | |
|  #endif
 | |
|  
 | |
| -  toolbar_ = top_container_->AddChildView(
 | |
| -      std::make_unique<ToolbarView>(browser_.get(), this));
 | |
| +  toolbar_ = OverrideCreateToolbar();
 | |
| +  if (!toolbar_) {
 | |
| +    toolbar_ = new ToolbarView(browser_.get(), this, std::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<ContentsSeparator>());
 | |
| @@ -1144,7 +1165,9 @@ BrowserView::BrowserView(std::unique_ptr<Browser> browser)
 | |
|  }
 | |
|  
 | |
|  BrowserView::~BrowserView() {
 | |
| +  if (browser_) {
 | |
|    browser_->GetFeatures().TearDownPreBrowserViewDestruction();
 | |
| +  }
 | |
|  
 | |
|    // Remove the layout manager to avoid dangling. This needs to be earlier than
 | |
|    // other cleanups that destroy views referenced in the layout manager.
 | |
| @@ -1156,7 +1179,9 @@ BrowserView::~BrowserView() {
 | |
|  
 | |
|    // All the tabs should have been destroyed already. If we were closed by the
 | |
|    // OS with some tabs than the NativeBrowserFrame should have destroyed them.
 | |
| +  if (browser_) {
 | |
|    DCHECK_EQ(0, browser_->tab_strip_model()->count());
 | |
| +  }
 | |
|  
 | |
|    // Stop the animation timer explicitly here to avoid running it in a nested
 | |
|    // message loop, which may run by Browser destructor.
 | |
| @@ -1165,17 +1190,18 @@ BrowserView::~BrowserView() {
 | |
|    // Immersive mode may need to reparent views before they are removed/deleted.
 | |
|    immersive_mode_controller_.reset();
 | |
|  
 | |
| -  // Reset autofill bubble handler to make sure it does not out-live toolbar,
 | |
| -  // since it is responsible for showing autofill related bubbles from toolbar's
 | |
| -  // child views and it is an observer for avatar toolbar button if any.
 | |
| -  autofill_bubble_handler_.reset();
 | |
| +  // If the Toolbar is not overloaded it will be destroyed via
 | |
| +  // RemoveAllChildViews().
 | |
| +  WillDestroyToolbar();
 | |
|  
 | |
| +  if (browser_) {
 | |
|    auto* global_registry =
 | |
|        extensions::ExtensionCommandsGlobalRegistry::Get(browser_->profile());
 | |
|    if (global_registry->registry_for_active_window() ==
 | |
|        extension_keybinding_registry_.get()) {
 | |
|      global_registry->set_registry_for_active_window(nullptr);
 | |
|    }
 | |
| +  }
 | |
|  
 | |
|    // These are raw pointers to child views, so they need to be set to null
 | |
|    // before `RemoveAllChildViews()` is called to avoid dangling.
 | |
| @@ -1800,6 +1826,28 @@ gfx::Point BrowserView::GetThemeOffsetFromBrowserView() const {
 | |
|        ThemeProperties::kFrameHeightAboveTabs - browser_view_origin.y());
 | |
|  }
 | |
|  
 | |
| +void BrowserView::WillDestroyToolbar() {
 | |
| +  // Reset autofill bubble handler to make sure it does not out-live toolbar,
 | |
| +  // since it is responsible for showing autofill related bubbles from toolbar's
 | |
| +  // child views and it is an observer for avatar toolbar button if any.
 | |
| +  autofill_bubble_handler_.reset();
 | |
| +
 | |
| +  toolbar_button_provider_ = nullptr;
 | |
| +  if (GetBrowserViewLayout()) {
 | |
| +    GetBrowserViewLayout()->reset_toolbar();
 | |
| +  }
 | |
| +
 | |
| +  if (toolbar_ && toolbar_->parent()) {
 | |
| +    // Remove now instead of waiting for RemoveAllChildViews(), as there is
 | |
| +    // otherwise no guarantee that the Toolbar will be removed before the
 | |
| +    // BrowserView is removed (and destroyed).
 | |
| +    toolbar_->parent()->RemoveChildView(toolbar_);
 | |
| +    toolbar_.ClearAndDelete();
 | |
| +  } else {
 | |
| +    toolbar_ = nullptr;
 | |
| +  }
 | |
| +}
 | |
| +
 | |
|  // static:
 | |
|  BrowserView::DevToolsDockedPlacement BrowserView::GetDevToolsDockedPlacement(
 | |
|      const gfx::Rect& contents_webview_bounds,
 | |
| @@ -2220,7 +2268,13 @@ void BrowserView::OnExclusiveAccessUserInput() {
 | |
|  
 | |
|  bool BrowserView::ShouldHideUIForFullscreen() const {
 | |
|    // Immersive mode needs UI for the slide-down top panel.
 | |
| -  if (immersive_mode_controller_->IsEnabled()) {
 | |
| +  // Avoid callback into |immersive_mode_controller_| during construction.
 | |
| +  // See CEF issue #3527.
 | |
| +  if (immersive_mode_controller_ && immersive_mode_controller_->IsEnabled()) {
 | |
| +    return false;
 | |
| +  }
 | |
| +
 | |
| +  if (!frame_->GetFrameView()) {
 | |
|      return false;
 | |
|    }
 | |
|  
 | |
| @@ -3459,7 +3513,9 @@ DownloadBubbleUIController* BrowserView::GetDownloadBubbleUIController() {
 | |
|      }
 | |
|      return nullptr;
 | |
|    }
 | |
| -  DCHECK(toolbar_button_provider_);
 | |
| +  if (!toolbar_button_provider_) {
 | |
| +    return nullptr;
 | |
| +  }
 | |
|    if (auto* download_button = toolbar_button_provider_->GetDownloadButton()) {
 | |
|      return download_button->bubble_controller();
 | |
|    }
 | |
| @@ -4089,7 +4145,8 @@ void BrowserView::ReparentTopContainerForEndOfImmersive() {
 | |
|      return;
 | |
|    }
 | |
|  
 | |
| -  overlay_view_->SetVisible(false);
 | |
| +  if (overlay_view_)
 | |
| +    overlay_view_->SetVisible(false);
 | |
|    top_container()->DestroyLayer();
 | |
|    AddChildViewAt(top_container(), 0);
 | |
|    EnsureFocusOrder();
 | |
| @@ -4607,11 +4664,38 @@ void BrowserView::GetAccessiblePanes(std::vector<views::View*>* panes) {
 | |
|  bool BrowserView::ShouldDescendIntoChildForEventHandling(
 | |
|      gfx::NativeView child,
 | |
|      const gfx::Point& location) {
 | |
| +#if BUILDFLAG(ENABLE_CEF)
 | |
| +  const bool frameless_pip =
 | |
| +      GetIsPictureInPictureType() &&
 | |
| +      !browser_->SupportsWindowFeature(Browser::FEATURE_TITLEBAR);
 | |
| +  if (frameless_pip) {
 | |
| +    if (auto frame_view = frame()->GetFrameView()) {
 | |
| +      int result = frame_view->NonClientHitTest(location);
 | |
| +      if (result == HTTOP || result == HTTOPLEFT || result == HTTOPRIGHT) {
 | |
| +        // Allow resize from the top of a frameless window.
 | |
| +        return false;
 | |
| +      }
 | |
| +    }
 | |
| +  }
 | |
| +#endif
 | |
| +
 | |
| +  std::optional<SkRegion> draggable_region;
 | |
| +
 | |
|    // Window for PWAs with window-controls-overlay display override should claim
 | |
|    // mouse events that fall within the draggable region.
 | |
|    web_app::AppBrowserController* controller = browser()->app_controller();
 | |
| -  if (AreDraggableRegionsEnabled() && controller &&
 | |
| -      controller->draggable_region().has_value()) {
 | |
| +  if (AreDraggableRegionsEnabled() && controller) {
 | |
| +    draggable_region = controller->draggable_region();
 | |
| +  }
 | |
| +
 | |
| +#if BUILDFLAG(ENABLE_CEF)
 | |
| +  // Match logic in PictureInPictureBrowserFrameView::NonClientHitTest.
 | |
| +  if (!draggable_region.has_value() && frameless_pip) {
 | |
| +    draggable_region = browser_->cef_delegate()->GetDraggableRegion();
 | |
| +  }
 | |
| +#endif
 | |
| +
 | |
| +  if (draggable_region.has_value()) {
 | |
|      // Draggable regions are defined relative to the web contents.
 | |
|      gfx::Point point_in_contents_web_view_coords(location);
 | |
|      views::View::ConvertPointToTarget(GetWidget()->GetRootView(),
 | |
| @@ -4620,7 +4704,7 @@ bool BrowserView::ShouldDescendIntoChildForEventHandling(
 | |
|  
 | |
|      // Draggable regions should be ignored for clicks into any browser view's
 | |
|      // owned widgets, for example alerts, permission prompts or find bar.
 | |
| -    return !controller->draggable_region()->contains(
 | |
| +    return !draggable_region->contains(
 | |
|                 point_in_contents_web_view_coords.x(),
 | |
|                 point_in_contents_web_view_coords.y()) ||
 | |
|             WidgetOwnedByAnchorContainsPoint(point_in_contents_web_view_coords);
 | |
| @@ -4734,8 +4818,10 @@ void BrowserView::Layout(PassKey) {
 | |
|  
 | |
|    // 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.
 | |
| @@ -4802,6 +4888,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();
 | |
|    if (download::IsDownloadBubbleEnabled() &&
 | |
|        features::IsToolbarPinningEnabled() &&
 | |
| @@ -4849,14 +4940,10 @@ 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();
 | |
| @@ -5252,7 +5339,8 @@ void BrowserView::ProcessFullscreen(bool fullscreen, const int64_t display_id) {
 | |
|    // 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();
 | |
|  }
 | |
|  
 | |
|  void BrowserView::RequestFullscreen(bool fullscreen, int64_t display_id) {
 | |
| @@ -5748,6 +5836,8 @@ Profile* BrowserView::GetProfile() {
 | |
|  }
 | |
|  
 | |
|  void BrowserView::UpdateUIForTabFullscreen() {
 | |
| +  if (!frame_->GetFrameView())
 | |
| +    return;
 | |
|    frame()->GetFrameView()->UpdateFullscreenTopUI();
 | |
|  }
 | |
|  
 | |
| @@ -5777,6 +5867,8 @@ bool BrowserView::CanUserEnterFullscreen() const {
 | |
|  }
 | |
|  
 | |
|  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 b9986c6e9097d..fc8f781e6ac66 100644
 | |
| --- chrome/browser/ui/views/frame/browser_view.h
 | |
| +++ chrome/browser/ui/views/frame/browser_view.h
 | |
| @@ -151,11 +151,16 @@ class BrowserView : public BrowserWindow,
 | |
|    METADATA_HEADER(BrowserView, views::ClientView)
 | |
|  
 | |
|   public:
 | |
| +  BrowserView();
 | |
|    explicit BrowserView(std::unique_ptr<Browser> browser);
 | |
| +  void InitBrowser(std::unique_ptr<Browser> 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 constexpr char kBrowserViewKey[] = "__BROWSER_VIEW__";
 | |
| +
 | |
|    void set_frame(BrowserFrame* frame) {
 | |
|      frame_ = frame;
 | |
|      paint_as_active_subscription_ =
 | |
| @@ -900,6 +905,10 @@ class BrowserView : public BrowserWindow,
 | |
|    void Copy();
 | |
|    void Paste();
 | |
|  
 | |
| +  // Called during Toolbar destruction to remove dependent objects that have
 | |
| +  // dangling references.
 | |
| +  virtual void WillDestroyToolbar();
 | |
| +
 | |
|   protected:
 | |
|    // Enumerates where the devtools are docked relative to the browser's main
 | |
|    // web contents.
 | |
| @@ -923,6 +932,8 @@ class BrowserView : public BrowserWindow,
 | |
|        const gfx::Rect& contents_webview_bounds,
 | |
|        const gfx::Rect& local_webview_container_bounds);
 | |
|  
 | |
| +  virtual ToolbarView* OverrideCreateToolbar() { 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 1376fdf933420..336391e29944c 100644
 | |
| --- chrome/browser/ui/views/frame/browser_view_layout.cc
 | |
| +++ chrome/browser/ui/views/frame/browser_view_layout.cc
 | |
| @@ -52,6 +52,10 @@
 | |
|  #include "ui/views/window/client_view.h"
 | |
|  #include "ui/views/window/hit_test_utils.h"
 | |
|  
 | |
| +#if BUILDFLAG(ENABLE_CEF)
 | |
| +#include "cef/libcef/browser/chrome/views/chrome_views_util.h"
 | |
| +#endif
 | |
| +
 | |
|  using views::View;
 | |
|  using web_modal::ModalDialogHostObserver;
 | |
|  using web_modal::WebContentsModalDialogHost;
 | |
| @@ -102,6 +106,10 @@ class BrowserViewLayout::WebContentsModalDialogHostViews
 | |
|      observer_list_.Notify(&ModalDialogHostObserver::OnHostDestroying);
 | |
|    }
 | |
|  
 | |
| +  bool HasObservers() const {
 | |
| +    return !observer_list_.empty();
 | |
| +  }
 | |
| +
 | |
|    void NotifyPositionRequiresUpdate() {
 | |
|      observer_list_.Notify(&ModalDialogHostObserver::OnPositionRequiresUpdate);
 | |
|    }
 | |
| @@ -111,7 +119,7 @@ class BrowserViewLayout::WebContentsModalDialogHostViews
 | |
|      views::View* view = browser_view_layout_->contents_container_;
 | |
|      gfx::Rect rect = view->ConvertRectToWidget(view->GetLocalBounds());
 | |
|      const int middle_x = rect.x() + rect.width() / 2;
 | |
| -    const int top = browser_view_layout_->dialog_top_y_;
 | |
| +    const int top = GetDialogTopY();
 | |
|      return gfx::Point(middle_x - size.width() / 2, top);
 | |
|    }
 | |
|  
 | |
| @@ -134,7 +142,7 @@ class BrowserViewLayout::WebContentsModalDialogHostViews
 | |
|      // universally.
 | |
|      views::View* view = browser_view_layout_->contents_container_;
 | |
|      gfx::Rect content_area = view->ConvertRectToWidget(view->GetLocalBounds());
 | |
| -    const int top = browser_view_layout_->dialog_top_y_;
 | |
| +    const int top = GetDialogTopY();
 | |
|      return gfx::Size(content_area.width(), content_area.bottom() - top);
 | |
|    }
 | |
|  
 | |
| @@ -163,6 +171,13 @@ class BrowserViewLayout::WebContentsModalDialogHostViews
 | |
|      return host_widget ? host_widget->GetNativeView() : nullptr;
 | |
|    }
 | |
|  
 | |
| +  int GetDialogTopY() const {
 | |
| +    int dialog_top_y = browser_view_layout_->dialog_top_y_;
 | |
| +    browser_view_layout_->delegate_->UpdateDialogTopInsetInBrowserView(
 | |
| +        &dialog_top_y);
 | |
| +    return dialog_top_y;
 | |
| +  }
 | |
| +
 | |
|    // Add/remove observer.
 | |
|    void AddObserver(ModalDialogHostObserver* observer) override {
 | |
|      observer_list_.AddObserver(observer);
 | |
| @@ -486,6 +501,8 @@ void BrowserViewLayout::Layout(views::View* browser_view) {
 | |
|      exclusive_access_bubble->RepositionIfVisible();
 | |
|    }
 | |
|  
 | |
| +  // Avoid unnecessary calls to UpdateDialogTopInsetInBrowserView().
 | |
| +  if (dialog_host_->HasObservers()) {
 | |
|    // Adjust any hosted dialogs if the browser's dialog hosting bounds changed.
 | |
|    const gfx::Rect dialog_bounds(dialog_host_->GetDialogPosition(gfx::Size()),
 | |
|                                  dialog_host_->GetMaximumDialogSize());
 | |
| @@ -499,6 +516,7 @@ void BrowserViewLayout::Layout(views::View* browser_view) {
 | |
|      latest_dialog_bounds_in_screen_ = dialog_bounds_in_screen;
 | |
|      dialog_host_->NotifyPositionRequiresUpdate();
 | |
|    }
 | |
| +  }
 | |
|  }
 | |
|  
 | |
|  gfx::Size BrowserViewLayout::GetPreferredSize(
 | |
| @@ -635,6 +653,13 @@ int BrowserViewLayout::LayoutWebUITabStrip(int top) {
 | |
|  
 | |
|  int BrowserViewLayout::LayoutToolbar(int top) {
 | |
|    TRACE_EVENT0("ui", "BrowserViewLayout::LayoutToolbar");
 | |
| +#if BUILDFLAG(ENABLE_CEF)
 | |
| +  if (cef::IsCefView(toolbar_)) {
 | |
| +    // CEF may take ownership of the toolbar. Early exit to avoid the DCHECK
 | |
| +    // in LayoutManager::SetViewVisibility().
 | |
| +    return top;
 | |
| +  }
 | |
| +#endif
 | |
|    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/frame/browser_view_layout.h chrome/browser/ui/views/frame/browser_view_layout.h
 | |
| index f5203245ab9ec..de060d33fcf16 100644
 | |
| --- chrome/browser/ui/views/frame/browser_view_layout.h
 | |
| +++ chrome/browser/ui/views/frame/browser_view_layout.h
 | |
| @@ -90,6 +90,8 @@ class BrowserViewLayout : public views::LayoutManager {
 | |
|      contents_border_widget_ = contents_border_widget;
 | |
|    }
 | |
|  
 | |
| +  void reset_toolbar() { toolbar_ = nullptr; }
 | |
| +
 | |
|    views::Widget* contents_border_widget() { return contents_border_widget_; }
 | |
|  
 | |
|    // Sets the bounds for the contents border.
 | |
| @@ -186,7 +188,7 @@ class BrowserViewLayout : public views::LayoutManager {
 | |
|    const raw_ptr<WebAppFrameToolbarView> web_app_frame_toolbar_;
 | |
|    const raw_ptr<views::Label> web_app_window_title_;
 | |
|    const raw_ptr<TabStripRegionView> tab_strip_region_view_;
 | |
| -  const raw_ptr<views::View> toolbar_;
 | |
| +  raw_ptr<views::View> toolbar_;
 | |
|    const raw_ptr<InfoBarContainerView> infobar_container_;
 | |
|    const raw_ptr<views::View> contents_container_;
 | |
|    const raw_ptr<views::View> left_aligned_side_panel_separator_;
 | |
| diff --git chrome/browser/ui/views/frame/browser_view_layout_delegate.h chrome/browser/ui/views/frame/browser_view_layout_delegate.h
 | |
| index 451c5ad63337b..66f946c95b9b4 100644
 | |
| --- chrome/browser/ui/views/frame/browser_view_layout_delegate.h
 | |
| +++ chrome/browser/ui/views/frame/browser_view_layout_delegate.h
 | |
| @@ -28,6 +28,7 @@ class BrowserViewLayoutDelegate {
 | |
|        const gfx::Rect& available_space,
 | |
|        views::Label& window_title_label) const = 0;
 | |
|    virtual int GetTopInsetInBrowserView() const = 0;
 | |
| +  virtual void UpdateDialogTopInsetInBrowserView(int* dialog_top_y) const = 0;
 | |
|    virtual bool IsToolbarVisible() const = 0;
 | |
|    virtual bool IsBookmarkBarVisible() const = 0;
 | |
|    virtual bool IsContentsSeparatorEnabled() const = 0;
 | |
| diff --git chrome/browser/ui/views/frame/contents_web_view.cc chrome/browser/ui/views/frame/contents_web_view.cc
 | |
| index 6bdd187588951..8ac385bcd0cb5 100644
 | |
| --- chrome/browser/ui/views/frame/contents_web_view.cc
 | |
| +++ chrome/browser/ui/views/frame/contents_web_view.cc
 | |
| @@ -29,6 +29,12 @@ ContentsWebView::ContentsWebView(content::BrowserContext* browser_context)
 | |
|    // Draws the ContentsWebView background.
 | |
|    SetPaintToLayer(ui::LAYER_SOLID_COLOR);
 | |
|    SetProperty(views::kElementIdentifierKey, kContentsWebViewElementId);
 | |
| +
 | |
| +  // Mouse events on draggable regions will not be handled by the WebView.
 | |
| +  // Avoid the resulting DCHECK in NativeViewHost::OnMousePressed by
 | |
| +  // configuring the NativeViewHost not to process events via the view
 | |
| +  // hierarchy.
 | |
| +  holder()->SetCanProcessEventsWithinSubtree(false);
 | |
|  }
 | |
|  
 | |
|  ContentsWebView::~ContentsWebView() = default;
 | |
| diff --git chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc
 | |
| index d69e8e49bf650..61386736a8d57 100644
 | |
| --- chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc
 | |
| +++ chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.cc
 | |
| @@ -668,6 +668,11 @@ PictureInPictureBrowserFrameView::PictureInPictureBrowserFrameView(
 | |
|      frame_background_ = std::make_unique<views::FrameBackground>();
 | |
|    }
 | |
|  #endif
 | |
| +
 | |
| +  if (!browser_view->browser()->SupportsWindowFeature(
 | |
| +          Browser::FEATURE_TITLEBAR)) {
 | |
| +    top_bar_container_view_->SetVisible(false);
 | |
| +  }
 | |
|  }
 | |
|  
 | |
|  PictureInPictureBrowserFrameView::~PictureInPictureBrowserFrameView() {
 | |
| @@ -801,18 +806,42 @@ gfx::Rect PictureInPictureBrowserFrameView::GetWindowBoundsForClientBounds(
 | |
|  
 | |
|  int PictureInPictureBrowserFrameView::NonClientHitTest(
 | |
|      const gfx::Point& point) {
 | |
| -  // Allow interacting with the buttons.
 | |
| -  if (GetLocationIconViewBounds().Contains(point) ||
 | |
| -      GetBackToTabControlsBounds().Contains(point) ||
 | |
| -      GetCloseControlsBounds().Contains(point)) {
 | |
| -    return HTCLIENT;
 | |
| +  const bool frameless = !top_bar_container_view_->GetVisible();
 | |
| +  if (!frameless) {
 | |
| +    // Allow interacting with the buttons.
 | |
| +    if (GetLocationIconViewBounds().Contains(point) ||
 | |
| +        GetBackToTabControlsBounds().Contains(point) ||
 | |
| +        GetCloseControlsBounds().Contains(point)) {
 | |
| +      return HTCLIENT;
 | |
| +    }
 | |
| +
 | |
| +    for (size_t i = 0; i < content_setting_views_.size(); i++) {
 | |
| +      if (GetContentSettingViewBounds(i).Contains(point)) {
 | |
| +        return HTCLIENT;
 | |
| +      }
 | |
| +    }
 | |
|    }
 | |
|  
 | |
| -  for (size_t i = 0; i < content_setting_views_.size(); i++) {
 | |
| -    if (GetContentSettingViewBounds(i).Contains(point)) {
 | |
| -      return HTCLIENT;
 | |
| +#if BUILDFLAG(ENABLE_CEF)
 | |
| +  if (frameless) {
 | |
| +    // Match logic in BrowserView::ShouldDescendIntoChildForEventHandling.
 | |
| +    const auto draggable_region =
 | |
| +        browser_view()->browser()->cef_delegate()->GetDraggableRegion();
 | |
| +    if (draggable_region.has_value()) {
 | |
| +      // Draggable regions are defined relative to the web contents.
 | |
| +      gfx::Point point_in_contents_web_view_coords(point);
 | |
| +      views::View::ConvertPointToTarget(GetWidget()->GetRootView(),
 | |
| +                                        browser_view()->contents_web_view(),
 | |
| +                                        &point_in_contents_web_view_coords);
 | |
| +
 | |
| +      if (draggable_region->contains(
 | |
| +              point_in_contents_web_view_coords.x(),
 | |
| +              point_in_contents_web_view_coords.y())) {
 | |
| +        return HTCAPTION;
 | |
| +      }
 | |
|      }
 | |
|    }
 | |
| +#endif  // BUILDFLAG(ENABLE_CEF)
 | |
|  
 | |
|    // Allow dragging and resizing the window.
 | |
|    int window_component = GetHTComponentForFrame(
 | |
| @@ -886,7 +915,8 @@ void PictureInPictureBrowserFrameView::Layout(PassKey) {
 | |
|    gfx::Rect content_area = GetLocalBounds();
 | |
|    content_area.Inset(FrameBorderInsets());
 | |
|    gfx::Rect top_bar = content_area;
 | |
| -  top_bar.set_height(kTopControlsHeight);
 | |
| +  top_bar.set_height(
 | |
| +      top_bar_container_view_->GetVisible() ? kTopControlsHeight : 0);
 | |
|    top_bar_container_view_->SetBoundsRect(top_bar);
 | |
|  #if !BUILDFLAG(IS_ANDROID)
 | |
|    if (auto_pip_setting_overlay_) {
 | |
| @@ -1436,7 +1466,8 @@ gfx::Insets PictureInPictureBrowserFrameView::ResizeBorderInsets() const {
 | |
|  }
 | |
|  
 | |
|  int PictureInPictureBrowserFrameView::GetTopAreaHeight() const {
 | |
| -  return FrameBorderInsets().top() + kTopControlsHeight;
 | |
| +  return FrameBorderInsets().top() +
 | |
| +         (top_bar_container_view_->GetVisible() ? kTopControlsHeight : 0);
 | |
|  }
 | |
|  
 | |
|  gfx::Size PictureInPictureBrowserFrameView::GetNonClientViewAreaSize() const {
 | |
| diff --git chrome/browser/ui/views/omnibox/omnibox_popup_closer.cc chrome/browser/ui/views/omnibox/omnibox_popup_closer.cc
 | |
| index 33c6444869375..d74818698d81a 100644
 | |
| --- chrome/browser/ui/views/omnibox/omnibox_popup_closer.cc
 | |
| +++ chrome/browser/ui/views/omnibox/omnibox_popup_closer.cc
 | |
| @@ -27,7 +27,8 @@ OmniboxPopupCloser::OmniboxPopupCloser(BrowserView* browser_view)
 | |
|  OmniboxPopupCloser::~OmniboxPopupCloser() = default;
 | |
|  
 | |
|  void OmniboxPopupCloser::OnMouseEvent(ui::MouseEvent* event) {
 | |
| -  if (!browser_view_->browser()->is_delete_scheduled() &&
 | |
| +  if (browser_view_->browser() &&
 | |
| +      !browser_view_->browser()->is_delete_scheduled() &&
 | |
|        event->type() == ui::EventType::kMousePressed) {
 | |
|      LocationBarView* location_bar_view = browser_view_->GetLocationBarView();
 | |
|      CHECK(location_bar_view);
 | |
| diff --git chrome/browser/ui/views/page_action/page_action_icon_controller.cc chrome/browser/ui/views/page_action/page_action_icon_controller.cc
 | |
| index b41c7ca3a6a01..24d3c68c34a26 100644
 | |
| --- chrome/browser/ui/views/page_action/page_action_icon_controller.cc
 | |
| +++ chrome/browser/ui/views/page_action/page_action_icon_controller.cc
 | |
| @@ -117,6 +117,14 @@ void PageActionIconController::Init(const PageActionIconParams& params,
 | |
|          continue;
 | |
|        }
 | |
|      }
 | |
| +
 | |
| +#if BUILDFLAG(ENABLE_CEF)
 | |
| +    if (params.browser && params.browser->cef_delegate() &&
 | |
| +        !params.browser->cef_delegate()->IsPageActionIconVisible(type)) {
 | |
| +      continue;
 | |
| +    }
 | |
| +#endif
 | |
| +
 | |
|      switch (type) {
 | |
|        case PageActionIconType::kPaymentsOfferNotification:
 | |
|          add_page_action_icon(
 | |
| diff --git chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
 | |
| index 99da126067283..1519dd277c73b 100644
 | |
| --- chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
 | |
| +++ chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
 | |
| @@ -669,29 +669,41 @@ 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::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);
 | |
|  }
 | |
|  
 | |
|  std::optional<int> BrowserTabStripController::GetCustomBackgroundId(
 | |
|      BrowserFrameActiveState active_state) const {
 | |
| +  if (!GetFrameView())
 | |
| +    return std::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 27efd0c4238f4..50037f13b926a 100644
 | |
| --- chrome/browser/ui/views/toolbar/toolbar_view.cc
 | |
| +++ chrome/browser/ui/views/toolbar/toolbar_view.cc
 | |
| @@ -188,7 +188,7 @@ class TabstripLikeBackground : public views::Background {
 | |
|    void Paint(gfx::Canvas* canvas, views::View* view) const override {
 | |
|      bool painted = TopContainerBackground::PaintThemeCustomImage(canvas, view,
 | |
|                                                                   browser_view_);
 | |
| -    if (!painted) {
 | |
| +    if (!painted && browser_view_->frame()->GetFrameView()) {
 | |
|        SkColor frame_color =
 | |
|            browser_view_->frame()->GetFrameView()->GetFrameColor(
 | |
|                BrowserFrameActiveState::kUseCurrent);
 | |
| @@ -222,12 +222,13 @@ END_METADATA
 | |
|  DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(ToolbarView, kToolbarElementId);
 | |
|  DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(ToolbarView, kToolbarContainerElementId);
 | |
|  
 | |
| -ToolbarView::ToolbarView(Browser* browser, BrowserView* browser_view)
 | |
| +ToolbarView::ToolbarView(Browser* browser, BrowserView* browser_view,
 | |
| +                         std::optional<DisplayMode> 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);
 | |
|    SetProperty(views::kElementIdentifierKey, kToolbarElementId);
 | |
|  
 | |
| @@ -259,9 +260,24 @@ ToolbarView::~ToolbarView() {
 | |
|    for (const auto& view_and_command : GetViewCommandMap()) {
 | |
|      chrome::RemoveCommandObserver(browser_, view_and_command.second, this);
 | |
|    }
 | |
| +
 | |
| +  browser_view_->WillDestroyToolbar();
 | |
|  }
 | |
|  
 | |
|  void ToolbarView::Init() {
 | |
| +#if BUILDFLAG(ENABLE_CEF)
 | |
| +  using ToolbarButtonType = cef::BrowserDelegate::ToolbarButtonType;
 | |
| +  auto button_visible = [this](ToolbarButtonType type) {
 | |
| +    if (this->browser_->cef_delegate()) {
 | |
| +      return this->browser_->cef_delegate()->IsToolbarButtonVisible(type);
 | |
| +    }
 | |
| +    return true;
 | |
| +  };
 | |
| +  #define BUTTON_VISIBLE(type) button_visible(ToolbarButtonType::type)
 | |
| +#else
 | |
| +  #define BUTTON_VISIBLE(type) true
 | |
| +#endif
 | |
| +
 | |
|  #if defined(USE_AURA)
 | |
|    // Avoid generating too many occlusion tracking calculation events before this
 | |
|    // function returns. The occlusion status will be computed only once once this
 | |
| @@ -284,12 +300,12 @@ void ToolbarView::Init() {
 | |
|  
 | |
|    auto location_bar = std::make_unique<LocationBarView>(
 | |
|        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);
 | |
|  
 | |
|    std::unique_ptr<DownloadToolbarButtonView> download_button;
 | |
| -  if (download::IsDownloadBubbleEnabled() &&
 | |
| +  if (download::IsDownloadBubbleEnabled() && BUTTON_VISIBLE(kDownload) &&
 | |
|        (!features::IsToolbarPinningEnabled() ||
 | |
|         !base::FeatureList::IsEnabled(features::kPinnableDownloadsButton))) {
 | |
|      download_button =
 | |
| @@ -373,7 +389,8 @@ void ToolbarView::Init() {
 | |
|    std::unique_ptr<media_router::CastToolbarButton> cast;
 | |
|    if (!(features::IsToolbarPinningEnabled() &&
 | |
|          base::FeatureList::IsEnabled(features::kPinnedCastButton))) {
 | |
| -    if (media_router::MediaRouterEnabled(browser_->profile())) {
 | |
| +    if (media_router::MediaRouterEnabled(browser_->profile()) &&
 | |
| +        BUTTON_VISIBLE(kCast)) {
 | |
|        cast = media_router::CastToolbarButton::Create(browser_);
 | |
|      }
 | |
|    }
 | |
| @@ -387,7 +404,8 @@ void ToolbarView::Init() {
 | |
|  
 | |
|    std::unique_ptr<send_tab_to_self::SendTabToSelfToolbarIconView>
 | |
|        send_tab_to_self_button;
 | |
| -  if (!browser_->profile()->IsOffTheRecord()) {
 | |
| +  if (!browser_->profile()->IsOffTheRecord() &&
 | |
| +      BUTTON_VISIBLE(kSendTabToSelf)) {
 | |
|      send_tab_to_self_button =
 | |
|          std::make_unique<send_tab_to_self::SendTabToSelfToolbarIconView>(
 | |
|              browser_view_);
 | |
| @@ -860,7 +878,8 @@ void ToolbarView::Layout(PassKey) {
 | |
|  
 | |
|    if (display_mode_ == DisplayMode::NORMAL) {
 | |
|      LayoutCommon();
 | |
| -    UpdateClipPath();
 | |
| +    if (!browser_->toolbar_overridden())
 | |
| +      UpdateClipPath();
 | |
|    }
 | |
|  
 | |
|    if (toolbar_controller_) {
 | |
| diff --git chrome/browser/ui/views/toolbar/toolbar_view.h chrome/browser/ui/views/toolbar/toolbar_view.h
 | |
| index 8562522807529..a88825e8242e3 100644
 | |
| --- chrome/browser/ui/views/toolbar/toolbar_view.h
 | |
| +++ chrome/browser/ui/views/toolbar/toolbar_view.h
 | |
| @@ -100,7 +100,8 @@ class ToolbarView : public views::AccessiblePaneView,
 | |
|    DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kToolbarElementId);
 | |
|    DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kToolbarContainerElementId);
 | |
|  
 | |
| -  ToolbarView(Browser* browser, BrowserView* browser_view);
 | |
| +  ToolbarView(Browser* browser, BrowserView* browser_view,
 | |
| +              std::optional<DisplayMode> display_mode);
 | |
|    ToolbarView(const ToolbarView&) = delete;
 | |
|    ToolbarView& operator=(const ToolbarView&) = delete;
 | |
|    ~ToolbarView() override;
 |