blob: 66e8e35bf6e51672ba04bb956b17a8bebba6933a [file] [log] [blame]
// 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_FRAME_VIEW_H_
#define CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_FRAME_VIEW_H_
#include <ostream>
#include <utility>
#include "base/memory/raw_ptr.h"
#include "build/build_config.h"
#include "chrome/browser/ui/views/frame/browser_widget.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/gfx/geometry/outsets_f.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/views/window/frame_view.h"
class BrowserView;
namespace views {
class Label;
}
// This enum is used for functions who rely on the state of the browser to alter
// the appearance of the window frame.
enum class BrowserFrameActiveState {
// Use the window's actual current active/inactive state.
kUseCurrent,
// Force the frame to be treated as active, regardless of the current state.
// Note: Only used on ChromeOS.
kActive,
// Force the frame to be treated as inactive, regardless of the current sate.
// Note: Only used on ChromeOS.
kInactive,
};
// Represents an area in the upper left or right of the browser window that
// browser UI should be careful when rendering in. This might include caption
// buttons, control box, or app icon.
//
// This is an example of the leading exclusion area in LTR:
//
// ┏━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━┯━━━━━
// ┃ content │ horizontal │
// ┠────────────────┘ ↔ │
// ┃ vertical ↕ padding ┊
// ┠─────────────────┄┄┄┄┄┄┄┄┄┄┄┄┘
// ┃
//
struct BrowserLayoutExclusionArea {
// This is the area which has visual elements managed by the frame. No drawing
// should occur here.
gfx::SizeF content;
// Any additional area next to the content that should remain empty for visual
// balance. It's okay for edges and borders to be drawn in this space.
float horizontal_padding = 0.f;
// Any additional area below the content that should remain empty for visual
// balance. It's okay for edges and borders to be drawn in this space.
float vertical_padding = 0.f;
// Returns the content area plus the padding, if any.
gfx::SizeF ContentWithPadding() const {
return gfx::SizeF(content.width() + horizontal_padding,
content.height() + vertical_padding);
}
// Returns true if there is no exclusion area.
bool IsEmpty() const { return ContentWithPadding().IsEmpty(); }
};
// Represents the parameters that the browser's layout requires in order to lay
// out the window contents.
//
// This is how the exclusion areas look in LTR:
// ┏━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━┓
// ┃ leading_exclusion │ │ trailing_exclusion ┃
// ┠───────────────────┘ └────────────────────┨
// ┃ ┃
//
// Note that in RTL UI, coordinates are reversed, so the leading exclusion is
// still at the lower X coordinate and the trailing exclusion at the higher.
//
// Also note that one or both exclusions may be empty, in which case there is
// no exclusion.
//
struct BrowserLayoutParams {
// A rectangle in which it is generally safe to lay out browser view elements.
// This is in window coordinates and may not align with the actual content
// view. It is okay for the content view to paint outside this rectangle, but
// that may overlap OS or frame elements.
gfx::Rect visual_client_area;
// The area in the leading (lowest X values; i.e. top-left in LTR and top-
// right in RTL) corner occupied by frame-owned controls, from the edge of the
// visual client area.
//
// It is sometimes okay for the content to draw through the edge of this area,
// e.g. to draw the leading curve of the first tab. Use the difference between
// `content` and `content_with_padding` to determine the area it is safe to
// draw in.
BrowserLayoutExclusionArea leading_exclusion;
// The area in the trailing (highest X values; i.e. top-right in LTR and top-
// left in RTL) corner occupied by frame-owned controls, from the edge of the
// visual client area.
//
// It is sometimes okay for the content to draw through the edge of this area,
// e.g. to draw the leading curve of the first tab. Use the difference between
// `content` and `content_with_padding` to determine the area it is safe to
// draw in.
BrowserLayoutExclusionArea trailing_exclusion;
};
// BrowserFrameView is an abstract base class that defines the
// interface for the part of a browser window that is not the "client area"
// (where the web content is displayed). This includes the title bar, window
// borders, and caption buttons (minimize, maximize, close).
//
// This class is responsible for:
// - Laying out major UI components like the tab strip.
// - Painting the window frame, taking into account the browser theme.
// - Responding to window state changes (fullscreen, activation, maximization).
//
// Concrete implementations are provided for each platform (e.g., Windows, Mac,
// Linux) and are created by the factory function
// `chrome::CreateBrowserFrameView`.
class BrowserFrameView : public views::FrameView {
METADATA_HEADER(BrowserFrameView, views::FrameView)
public:
BrowserFrameView(BrowserWidget* browser_widget, BrowserView* browser_view);
BrowserFrameView(const BrowserFrameView&) = delete;
BrowserFrameView& operator=(const BrowserFrameView&) = delete;
~BrowserFrameView() override;
BrowserView* browser_view() const { return browser_view_; }
BrowserWidget* browser_widget() const { return browser_widget_; }
// Called after BrowserView has initialized its child views. This is a useful
// hook for performing final setup that depends on other child views, like
// the tabstrip or toolbar, being present.
virtual void OnBrowserViewInitViewsComplete();
// Called when the browser window's fullscreen state changes.
virtual void OnFullscreenStateChanged();
// Returns whether the caption buttons are drawn at the leading edge (e.g. on
// the left for LTR languages, such as on macOS).
virtual bool CaptionButtonsOnLeadingEdge() const;
// Default implementation for getting browser layout parameters.
virtual BrowserLayoutParams GetBrowserLayoutParams() const;
// Returns the bounds, in this view's coordinates, that the tab
// strip should occupy.
virtual gfx::Rect GetBoundsForTabStripRegion(
const gfx::Size& tabstrip_minimum_size) const = 0;
// Returns the maximum bounds, in this view's coordinates, for
// the WebAppFrameToolbarView, which contains controls for a web app.
virtual gfx::Rect GetBoundsForWebAppFrameToolbar(
const gfx::Size& toolbar_preferred_size) const = 0;
// Lays out the window title for a web app within the given available space.
// Unlike the above GetBounds methods this is not just a method to return the
// bounds the title should occupy, since different implementations might also
// want to change other attributes of the title, such as alignment.
virtual void LayoutWebAppWindowTitle(const gfx::Rect& available_space,
views::Label& window_title_label) const;
// Returns the inset from the top of the window to the top of the client
// view. For a tabbed browser, this is the space occupied by the tab strip.
// For popup windows, this is the toolbar. For app windows, this is the
// WebContents. Varies on fullscreen. If |restored| is true, this is
// calculated for the window's restored state, regardless of its current state
// (e.g., maximized or fullscreen).
virtual int GetTopInset(bool restored) const = 0;
// Updates the top UI state to be hidden or shown in fullscreen according to
// the preference's state. Currently only used on Mac.
virtual void UpdateFullscreenTopUI();
// Returns true if the top UI (tabstrip, toolbar) should be hidden because the
// browser is in fullscreen mode.
virtual bool ShouldHideTopUIInFullscreen() const;
// Returns true if a toolbar should be shown in the current browser, false if
// not. If this returns false, there is no reason to call e.g.
// `GetBoundsForWebAppFrameToolbar()`.
virtual bool ShouldShowWebAppFrameToolbar() const;
// Determines whether the top of the frame is "condensed" (i.e., has less
// vertical space). This is typically true when the window is maximized or
// fullscreen. If true, the top frame is just the height of a tab,
// rather than having extra vertical space above the tabs.
virtual bool IsFrameCondensed() const;
// Determines if background tab shapes have a distinct appearance from the
// frame background. This is true if the theme uses a custom tab background
// image or if the calculated color for background tabs differs from the frame
// color.
bool HasVisibleBackgroundTabShapes(
BrowserFrameActiveState active_state) const;
// Returns the color that should be used for text and icons in the title bar
// (e.g., the window title and caption button icons).
virtual SkColor GetCaptionColor(BrowserFrameActiveState active_state) const;
// Returns the primary background color of the browser frame. This is also the
// color used for the tab strip background unless overridden by a theme.
virtual SkColor GetFrameColor(BrowserFrameActiveState active_state) const;
// Returns the resource ID for a custom background image if the active theme
// provides one for the frame. This checks for images for the given active
// state and also considers theme-related fallbacks (e.g., an inactive image
// falling back to an active one).
std::optional<int> GetCustomBackgroundId(
BrowserFrameActiveState active_state) const;
// Updates the the loading animation (throbber) for the window icon in the
// frame. Mainly used by special browsers such as PWAs.
virtual void UpdateThrobber(bool running) = 0;
// Signals that the frame's minimum size may have changed. This prompts the
// widget to update its size constraints by re-querying `GetMinimumSize()`.
// This is typically called when child views (e.g. tab strip, toolbar,
// bookmarks bar) change visibility.The window manager is notified of this
// change via GetWidget()->OnSizeConstraintsChanged().
virtual void UpdateMinimumSize();
// Called when the Window Controls Overlay state changes, allowing the frame
// to update the state of the caption buttons accordingly.
virtual void WindowControlsOverlayEnabledChanged() {}
// Returns the insets from the edge of the native window to the client view in
// DIPs. The value is left-to-right even on RTL locales. That is,
// insets.left() will be on the left in screen coordinates. Subclasses must
// implement this.
virtual gfx::Insets RestoredMirroredFrameBorderInsets() const;
// Returns the insets from the client view to the input region. The returned
// insets will be negative, such that view_rect.Inset(GetInputInsets()) will
// be the input region. Subclasses must implement this.
virtual gfx::Insets GetInputInsets() const;
// Gets the rounded-rect clipping region for the window frame when it is
// in its restored (non-maximized) state. Subclasses must implement this.
virtual SkRRect GetRestoredClipRegion() const;
// Returns the height of the translucent area at the top of the frame. Returns
// 0 if the frame is opaque (not transparent) or in fullscreen.
virtual int GetTranslucentTopAreaHeight() const;
// Sets the bounds of `frame_`.
virtual void SetFrameBounds(const gfx::Rect& bounds);
// views::FrameView:
void Layout(PassKey) override;
Views GetChildrenInZOrder() override;
protected:
// Called when `frame_`'s "paint as active" state has changed.
virtual void PaintAsActiveChanged();
// Used by GetCaptionButtonBounds() below.
struct BoundsAndMargins {
// The bounds of a view or collection of views.
gfx::RectF bounds;
// The preferred margins around `bounds`.
gfx::OutsetsF margins;
// Returns the rectangle that contains `bounds` with `margins`.
gfx::Rect ToEnclosingRect() const;
};
// Gets the bounds of the caption buttons, and their required margins if any.
// The bounds are the combined rectangle containing all caption buttons; the
// margins are the preferred visual padding area around that rectangle.
//
// Mac (small buttons; padding around):
//
// ┏━━━━━━━━━━━━━┯━━━━━━
// ┃ ┌───────┐ │
// ┃ │O O O│ │
// ┃ └───────┘ │
// ┠─────────────┘
//
// Windows (larger buttons, no additional padding):
//
// ━━━━━┯━━━━━━━━━━━━━┓
// │ _ □ X ┃
// └─────────────┨
// ┃
//
virtual BoundsAndMargins GetCaptionButtonBounds() const;
// Helper function to determine if we should treat the frame as the active
// state.
bool ShouldPaintAsActiveForState(BrowserFrameActiveState active_state) const;
// Returns a themed image for the frame background, if one exists.
gfx::ImageSkia GetFrameImage(BrowserFrameActiveState active_state =
BrowserFrameActiveState::kUseCurrent) const;
// Returns a themed image for the frame overlay, if one exists.
gfx::ImageSkia GetFrameOverlayImage(
BrowserFrameActiveState active_state =
BrowserFrameActiveState::kUseCurrent) const;
private:
#if BUILDFLAG(IS_WIN)
// ui::EventHandler:
void OnGestureEvent(ui::GestureEvent* event) override;
// views::FrameView:
int GetSystemMenuY() const override;
#endif // BUILDFLAG(IS_WIN)
// The BrowserWidget that owns this view.
const raw_ptr<BrowserWidget, DanglingUntriaged> browser_widget_;
// The BrowserView hosted within `frame_`.
const raw_ptr<BrowserView, DanglingUntriaged> browser_view_;
// Subscription to receive notifications when the frame's PaintAsActive state
// changes.
base::CallbackListSubscription paint_as_active_subscription_ =
browser_widget_->RegisterPaintAsActiveChangedCallback(
base::BindRepeating(&BrowserFrameView::PaintAsActiveChanged,
base::Unretained(this)));
};
namespace chrome {
// Factory function for creating a BrowserFrameView. Platform specific
// implementations should define this in their respective
// browser_view_factor_*.cc files.
std::unique_ptr<BrowserFrameView> CreateBrowserFrameView(
BrowserWidget* browser_widget,
BrowserView* browser_view);
} // namespace chrome
// For debugging and testing.
std::ostream& operator<<(std::ostream&, const BrowserLayoutExclusionArea&);
std::ostream& operator<<(std::ostream&, const BrowserLayoutParams&);
#endif // CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_FRAME_VIEW_H_