chromium/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.h

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_NON_CLIENT_FRAME_VIEW_CHROMEOS_H_
#define CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_NON_CLIENT_FRAME_VIEW_CHROMEOS_H_

#include <memory>

#include "base/cancelable_callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "chrome/browser/ui/views/frame/browser_frame_header_chromeos.h"
#include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
#include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
#include "chrome/browser/ui/views/tab_icon_view_model.h"
#include "chromeos/ui/frame/highlight_border_overlay.h"
#include "components/services/app_service/public/cpp/app_registry_cache.h"
#include "components/services/app_service/public/cpp/app_update.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/display/display_observer.h"
#include "ui/display/tablet_state.h"

class ProfileIndicatorIcon;
class TabIconView;

namespace chromeos {
class FrameCaptionButtonContainerView;
class HighlightBorderOverlay;
}  // namespace chromeos

// Provides the BrowserNonClientFrameView for Chrome OS.
class BrowserNonClientFrameViewChromeOS
    : public BrowserNonClientFrameView,
      public BrowserFrameHeaderChromeOS::AppearanceProvider,
      public display::DisplayObserver,
      public TabIconViewModel,
      public aura::WindowObserver,
      public ImmersiveModeController::Observer,
      public apps::AppRegistryCache::Observer {
  METADATA_HEADER(BrowserNonClientFrameViewChromeOS, BrowserNonClientFrameView)

 public:
  BrowserNonClientFrameViewChromeOS(BrowserFrame* frame,
                                    BrowserView* browser_view);
  BrowserNonClientFrameViewChromeOS(const BrowserNonClientFrameViewChromeOS&) =
      delete;
  BrowserNonClientFrameViewChromeOS& operator=(
      const BrowserNonClientFrameViewChromeOS&) = delete;
  ~BrowserNonClientFrameViewChromeOS() override;

  static BrowserNonClientFrameViewChromeOS* Get(aura::Window* window);

  void Init();

  // BrowserNonClientFrameView:
  gfx::Rect GetBoundsForTabStripRegion(
      const gfx::Size& tabstrip_minimum_size) const override;
  gfx::Rect GetBoundsForWebAppFrameToolbar(
      const gfx::Size& toolbar_preferred_size) const override;
  void LayoutWebAppWindowTitle(const gfx::Rect& available_space,
                               views::Label& window_title_label) const override;
  int GetTopInset(bool restored) const override;
  void UpdateThrobber(bool running) override;
  bool CanUserExitFullscreen() const override;
  SkColor GetCaptionColor(BrowserFrameActiveState active_state) const override;
  SkColor GetFrameColor(BrowserFrameActiveState active_state) const override;
  void UpdateMinimumSize() override;

  // views::NonClientFrameView:
  gfx::Rect GetBoundsForClientView() const override;
  gfx::Rect GetWindowBoundsForClientBounds(
      const gfx::Rect& client_bounds) const override;
  int NonClientHitTest(const gfx::Point& point) override;
  void GetWindowMask(const gfx::Size& size, SkPath* window_mask) override;
  void ResetWindowControls() override;
  void WindowControlsOverlayEnabledChanged() override;
  void UpdateWindowIcon() override;
  void UpdateWindowTitle() override;
  void SizeConstraintsChanged() override;
  void UpdateWindowRoundedCorners() override;

  // views::View:
  void OnPaint(gfx::Canvas* canvas) override;
  void Layout(PassKey) override;
  gfx::Size GetMinimumSize() const override;
  void OnThemeChanged() override;
  void ChildPreferredSizeChanged(views::View* child) override;
  bool DoesIntersectRect(const views::View* target,
                         const gfx::Rect& rect) const override;
  views::View::Views GetChildrenInZOrder() override;

  // BrowserFrameHeaderChromeOS::AppearanceProvider:
  SkColor GetTitleColor() override;
  SkColor GetFrameHeaderColor(bool active) override;
  gfx::ImageSkia GetFrameHeaderImage(bool active) override;
  int GetFrameHeaderImageYInset() override;
  gfx::ImageSkia GetFrameHeaderOverlayImage(bool active) override;

  // display::DisplayObserver:
  void OnDisplayTabletStateChanged(display::TabletState state) override;
  void OnDisplayMetricsChanged(const display::Display& display,
                               uint32_t changed_metrics) override;

  void OnTabletModeToggled(bool enabled);

  // TabIconViewModel:
  bool ShouldTabIconViewAnimate() const override;
  ui::ImageModel GetFaviconForTabIconView() override;

  // aura::WindowObserver:
  void OnWindowDestroying(aura::Window* window) override;
  void OnWindowPropertyChanged(aura::Window* window,
                               const void* key,
                               intptr_t old) override;

  // ImmersiveModeController::Observer:
  void OnImmersiveRevealStarted() override;
  void OnImmersiveRevealEnded() override;
  void OnImmersiveFullscreenExited() override;

  // apps::AppRegistryCache::Observer:
  void OnAppUpdate(const apps::AppUpdate& update) override;
  void OnAppRegistryCacheWillBeDestroyed(
      apps::AppRegistryCache* cache) override;

  chromeos::FrameCaptionButtonContainerView* caption_button_container() {
    return caption_button_container_;
  }

 protected:
  // BrowserNonClientFrameView:
  void PaintAsActiveChanged() override;
  void OnProfileAvatarChanged(const base::FilePath& profile_path) override;
  void AddedToWidget() override;

 private:
  friend class BrowserNonClientFrameViewChromeOSTestApi;
  FRIEND_TEST_ALL_PREFIXES(ImmersiveModeBrowserViewTestNoWebUiTabStrip,
                           ImmersiveFullscreen);

  // App is a PWA and has borderless in its manifest. This doesn't yet mean
  // that the `window-management` permission has been granted and borderless
  // mode would be activated.
  bool AppIsPwaWithBorderlessDisplayMode() const;

  // Returns true if `GetShowCaptionButtonsWhenNotInOverview()` returns true
  // and this browser window is not showing in overview.
  bool GetShowCaptionButtons() const;

  // Returns whether we should show caption buttons. False for fullscreen,
  // tablet mode and webUI tab strip in most cases. The exceptions are if this
  // is a packaged app, as they have immersive mode enabled, and floated windows
  // in tablet mode.
  bool GetShowCaptionButtonsWhenNotInOverview() const;

  // Distance between the edge of the NonClientFrameView and the web app frame
  // toolbar.
  int GetToolbarLeftInset() const;

  // Distance between the edges of the NonClientFrameView and the tab strip.
  int GetTabStripLeftInset() const;
  int GetTabStripRightInset() const;

  // Returns true if there is anything to paint. Some fullscreen windows do
  // not need their frames painted.
  bool GetShouldPaint() const;

  // Helps to hide or show the header as needed when the window is added to or
  // removed from overview.
  void OnAddedToOrRemovedFromOverview();

  // Creates the frame header for the browser window.
  std::unique_ptr<chromeos::FrameHeader> CreateFrameHeader();

  // Triggers the web-app origin and icon animations, assumes the web-app UI
  // elements exist.
  void StartWebAppAnimation();

  // Updates the kTopViewInset window property after a layout.
  void UpdateTopViewInset();

  // Returns true if |profile_indicator_icon_| should be shown.
  bool GetShowProfileIndicatorIcon() const;

  // Updates the icon that indicates a teleported window.
  void UpdateProfileIcons();

  void LayoutProfileIndicator();

  void UpdateBorderlessModeEnabled();

  // Returns whether this window is currently in the overview list.
  bool GetOverviewMode() const;

  // Returns whether this window is currently in, or is about to be in, tab
  // fullscreen (not immersive fullscreen). Returns false for immersive
  // fullscreen.
  bool GetHideCaptionButtonsForFullscreen() const;

  // Called any time the frame color may have changed.
  void OnUpdateFrameColor();

  // Called any time the theme has changed and may need to be animated.
  void MaybeAnimateThemeChanged();

  // Returns whether the associated window is currently floated or not.
  bool IsFloated() const;

  // Helper to check whether we should enable immersive mode.`on_tablet_enabled`
  // is set to true only when it is called when tablet mode is just toggled on
  // notified from OnTabletModeToggled.
  bool ShouldEnableImmersiveModeController(bool on_tablet_enabled) const;

  // Helper to check whether we should enable fullscreen mode.
  // `on_tablet_enabled` is set to true only when tablet mode is just toggled
  // on notified from OnTabletModeToggled.
  bool ShouldEnableFullscreenMode(bool on_tablet_enabled) const;

  // True if the the associated browser window should be using the WebUI tab
  // strip.
  bool UseWebUITabStrip() const;

  // Returns the top level aura::Window for this browser window.
  const aura::Window* GetFrameWindow() const;
  aura::Window* GetFrameWindow();

  // Generates a nine patch layer painted with a highlight border.
  std::unique_ptr<HighlightBorderOverlay> highlight_border_overlay_;

  // View which contains the window controls.
  raw_ptr<chromeos::FrameCaptionButtonContainerView> caption_button_container_ =
      nullptr;

  // For popups, the window icon.
  raw_ptr<TabIconView> window_icon_ = nullptr;

  // This is used for teleported windows (in multi-profile mode).
  raw_ptr<ProfileIndicatorIcon> profile_indicator_icon_ = nullptr;

  // Helper class for painting the header.
  std::unique_ptr<chromeos::FrameHeader> frame_header_;

  base::ScopedObservation<aura::Window, aura::WindowObserver>
      window_observation_{this};

  base::ScopedObservation<apps::AppRegistryCache,
                          apps::AppRegistryCache::Observer>
      app_registry_cache_observation_{this};

  std::optional<display::ScopedDisplayObserver> display_observer_;

  gfx::Size last_minimum_size_;

  // Callback to invoke to animate back in the layer associated with the
  // `contents_web_view()` native view following a theme changed event.
  base::CancelableOnceCallback<void(bool)> theme_changed_animation_callback_;

  base::WeakPtrFactory<BrowserNonClientFrameViewChromeOS> weak_ptr_factory_{
      this};
};

#endif  // CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_NON_CLIENT_FRAME_VIEW_CHROMEOS_H_