#ifndef UI_NATIVE_THEME_NATIVE_THEME_H_
#define UI_NATIVE_THEME_NATIVE_THEME_H_
#include <stddef.h>
#include <optional>
#include <variant>
#include "base/callback_list.h"
#include "base/component_export.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/observer_list.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "base/types/pass_key.h"
#include "build/build_config.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/models/menu_separator_types.h"
#include "ui/color/color_id.h"
#include "ui/color/color_provider_key.h"
#include "ui/color/system_theme.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/size.h"
namespace cc {
class PaintCanvas;
}
namespace gfx {
class Rect;
}
namespace ui {
class ColorProvider;
class NativeThemeObserver;
class COMPONENT_EXPORT(NATIVE_THEME) NativeTheme {
public:
enum Part {
kCheckbox,
#if BUILDFLAG(IS_LINUX)
kFrameTopArea,
#endif
kInnerSpinButton,
kMenuList,
kMenuPopupBackground,
#if BUILDFLAG(IS_WIN)
kMenuCheck,
kMenuCheckBackground,
kMenuPopupArrow,
kMenuPopupGutter,
#endif
kMenuPopupSeparator,
kMenuItemBackground,
kProgressBar,
kPushButton,
kRadio,
kScrollbarDownArrow,
kScrollbarLeftArrow,
kScrollbarRightArrow,
kScrollbarUpArrow,
kScrollbarHorizontalThumb,
kScrollbarVerticalThumb,
kScrollbarHorizontalTrack,
kScrollbarVerticalTrack,
kScrollbarHorizontalGripper,
kScrollbarVerticalGripper,
kScrollbarCorner,
kSliderTrack,
kSliderThumb,
kTabPanelBackground,
kTextField,
kTrackbarThumb,
kTrackbarTrack,
kWindowResizeGripper,
kMaxPart,
};
enum State {
kDisabled = 0,
kHovered = 1,
kNormal = 2,
kPressed = 3,
kNumStates = kPressed + 1,
};
enum class PreferredColorScheme {
kNoPreference = 0,
kLight = 1,
kDark = 2,
kMaxValue = kDark,
};
enum class PreferredContrast {
kNoPreference = 0,
kMore = 1,
kLess = 2,
kCustom = 3,
kMaxValue = kCustom,
};
struct ButtonExtraParams {
bool checked = false;
bool indeterminate = false;
bool is_default = false;
bool is_focused = false;
bool has_border = false;
int classic_state = 0;
SkColor background_color = gfx::kPlaceholderColor;
float zoom = 0;
};
struct FrameTopAreaExtraParams {
bool is_active = false;
bool use_custom_frame = false;
SkColor default_background_color = gfx::kPlaceholderColor;
};
enum class SpinArrowsDirection : int {
kLeftRight,
kUpDown,
};
struct InnerSpinButtonExtraParams {
bool spin_up = false;
bool read_only = false;
SpinArrowsDirection spin_arrows_direction = SpinArrowsDirection::kUpDown;
int classic_state = 0;
};
struct MenuArrowExtraParams {
bool pointing_right = false;
bool is_selected = false;
};
struct MenuCheckExtraParams {
bool is_radio = false;
bool is_selected = false;
};
struct MenuSeparatorExtraParams {
raw_ptr<const gfx::Rect> paint_rect = nullptr;
ColorId color_id = kColorMenuSeparator;
MenuSeparatorType type = MenuSeparatorType::NORMAL_SEPARATOR;
};
struct MenuItemExtraParams {
bool is_selected = false;
int corner_radius = 0;
};
enum class ArrowDirection : int {
kDown,
kLeft,
kRight,
};
struct COMPONENT_EXPORT(NATIVE_THEME) MenuListExtraParams {
bool has_border = false;
bool has_border_radius = false;
int arrow_x = 0;
int arrow_y = 0;
int arrow_size = 0;
ArrowDirection arrow_direction = ArrowDirection::kDown;
SkColor arrow_color = gfx::kPlaceholderColor;
SkColor background_color = gfx::kPlaceholderColor;
int classic_state = 0;
float zoom = 0;
MenuListExtraParams();
MenuListExtraParams(const MenuListExtraParams&);
MenuListExtraParams& operator=(const MenuListExtraParams&);
};
struct MenuBackgroundExtraParams {
int corner_radius = 0;
};
struct ProgressBarExtraParams {
double animated_seconds = 0;
bool determinate = false;
int value_rect_x = 0;
int value_rect_y = 0;
int value_rect_width = 0;
int value_rect_height = 0;
float zoom = 0;
bool is_horizontal = false;
};
struct ScrollbarArrowExtraParams {
bool is_hovering = false;
float zoom = 0;
bool needs_rounded_corner = false;
bool right_to_left = false;
std::optional<SkColor> thumb_color;
std::optional<SkColor> track_color;
};
struct ScrollbarTrackExtraParams {
bool is_upper = false;
int track_x = 0;
int track_y = 0;
int track_width = 0;
int track_height = 0;
int classic_state = 0;
std::optional<SkColor> track_color;
};
struct ScrollbarThumbExtraParams {
bool is_hovering = false;
std::optional<SkColor> thumb_color;
std::optional<SkColor> track_color;
bool is_thumb_minimal_mode = false;
bool is_web_test = false;
#if BUILDFLAG(ARKWEB_SCROLLBAR)
SkColor scrollbar_color;
#endif
};
#if BUILDFLAG(IS_APPLE)
enum ScrollbarOrientation {
kVerticalOnRight,
kVerticalOnLeft,
kHorizontal,
};
struct ScrollbarExtraParams {
bool is_hovering = false;
bool is_overlay = false;
ScrollbarOrientation orientation =
ScrollbarOrientation::kVerticalOnRight;
float scale_from_dip = 0;
std::optional<SkColor> thumb_color;
std::optional<SkColor> track_color;
};
#endif
struct SliderExtraParams {
bool vertical = false;
bool in_drag = false;
int thumb_x = 0;
int thumb_y = 0;
float zoom = 0;
bool right_to_left = false;
};
struct COMPONENT_EXPORT(NATIVE_THEME) TextFieldExtraParams {
bool is_text_area = false;
bool is_listbox = false;
SkColor background_color = gfx::kPlaceholderColor;
bool is_read_only = false;
bool is_focused = false;
bool fill_content_area = false;
bool draw_edges = false;
int classic_state = 0;
bool has_border = false;
bool auto_complete_active = false;
float zoom = 0;
TextFieldExtraParams();
TextFieldExtraParams(const TextFieldExtraParams&);
TextFieldExtraParams& operator=(const TextFieldExtraParams&);
};
struct TrackbarExtraParams {
bool vertical = false;
int classic_state = 0;
};
using ExtraParams = std::variant<ButtonExtraParams,
FrameTopAreaExtraParams,
InnerSpinButtonExtraParams,
MenuArrowExtraParams,
MenuCheckExtraParams,
MenuItemExtraParams,
MenuSeparatorExtraParams,
MenuListExtraParams,
MenuBackgroundExtraParams,
ProgressBarExtraParams,
ScrollbarArrowExtraParams,
#if BUILDFLAG(IS_APPLE)
ScrollbarExtraParams,
#endif
ScrollbarTrackExtraParams,
ScrollbarThumbExtraParams,
SliderExtraParams,
TextFieldExtraParams,
TrackbarExtraParams>;
class [[maybe_unused, nodiscard]] COMPONENT_EXPORT(NATIVE_THEME)
UpdateNotificationDelayScoper {
public:
UpdateNotificationDelayScoper();
UpdateNotificationDelayScoper(const UpdateNotificationDelayScoper&);
UpdateNotificationDelayScoper(UpdateNotificationDelayScoper&&);
UpdateNotificationDelayScoper& operator=(
const UpdateNotificationDelayScoper&) = default;
UpdateNotificationDelayScoper& operator=(UpdateNotificationDelayScoper&&) =
default;
~UpdateNotificationDelayScoper();
static bool exists(base::PassKey<NativeTheme>) { return !!num_instances_; }
static base::CallbackListSubscription RegisterCallback(
base::PassKey<NativeTheme>,
base::OnceClosure cb);
private:
static base::OnceClosureList& GetDelayedNotifications();
static size_t num_instances_;
};
NativeTheme(const NativeTheme&) = delete;
NativeTheme& operator=(const NativeTheme&) = delete;
static NativeTheme* GetInstanceForNativeUi();
static NativeTheme* GetInstanceForWeb();
static float AdjustBorderWidthByZoom(float border_width, float zoom_level);
static float AdjustBorderRadiusByZoom(Part part,
float border_radius,
float zoom_level);
virtual gfx::Size GetPartSize(Part part,
State state,
const ExtraParams& extra_params) const;
virtual int GetPaintedScrollbarTrackInset() const;
virtual gfx::Insets GetScrollbarSolidColorThumbInsets(Part part) const;
virtual float GetBorderRadiusForPart(Part part,
float width,
float height) const;
virtual bool SupportsNinePatch(Part part) const;
virtual gfx::Size GetNinePatchCanvasSize(Part part) const;
virtual gfx::Rect GetNinePatchAperture(Part part) const;
virtual SkColor GetScrollbarThumbColor(
const ColorProvider* color_provider,
State state,
const ScrollbarThumbExtraParams& extra_params) const;
virtual SkColor GetSystemButtonPressedColor(SkColor base_color) const;
void BeginObservingOsSettingChanges();
void AddObserver(NativeThemeObserver* observer);
void RemoveObserver(NativeThemeObserver* observer);
void NotifyOnNativeThemeUpdated();
void NotifyOnCaptionStyleUpdated();
void Paint(
cc::PaintCanvas* canvas,
const ColorProvider* color_provider,
Part part,
State state,
const gfx::Rect& rect,
const ExtraParams& extra_params,
bool forced_colors = false,
PreferredColorScheme color_scheme = PreferredColorScheme::kNoPreference,
PreferredContrast contrast = PreferredContrast::kNoPreference,
std::optional<SkColor> accent_color = std::nullopt) const;
ColorProviderKey GetColorProviderKey(
scoped_refptr<ColorProviderKey::ThemeInitializerSupplier> custom_theme,
bool use_custom_frame = true) const;
SystemTheme system_theme() const { return system_theme_; }
bool use_overlay_scrollbar() const { return use_overlay_scrollbar_; }
void set_use_overlay_scrollbar(bool use_overlay_scrollbar) {
use_overlay_scrollbar_ = use_overlay_scrollbar;
}
ColorProviderKey::ForcedColors forced_colors() const {
return forced_colors_;
}
void set_forced_colors(ColorProviderKey::ForcedColors forced_colors) {
forced_colors_ = forced_colors;
}
PreferredColorScheme preferred_color_scheme() const {
return preferred_color_scheme_;
}
void set_preferred_color_scheme(PreferredColorScheme preferred_color_scheme) {
preferred_color_scheme_ = preferred_color_scheme;
}
PreferredContrast preferred_contrast() const { return preferred_contrast_; }
void set_preferred_contrast(PreferredContrast preferred_contrast) {
preferred_contrast_ = preferred_contrast;
}
bool prefers_reduced_transparency() const {
return prefers_reduced_transparency_;
}
bool inverted_colors() const { return inverted_colors_; }
std::optional<SkColor> user_color() const { return user_color_; }
void set_user_color(std::optional<SkColor> user_color) {
user_color_ = user_color;
}
std::optional<ColorProviderKey::SchemeVariant> scheme_variant() const {
return scheme_variant_;
}
base::TimeDelta caret_blink_interval() const { return caret_blink_interval_; }
void set_caret_blink_interval(base::TimeDelta caret_blink_interval) {
caret_blink_interval_ = caret_blink_interval;
}
static bool IsForcedLightMode();
static bool IsForcedDarkMode();
protected:
explicit NativeTheme(SystemTheme system_theme = SystemTheme::kDefault);
virtual ~NativeTheme();
static bool IsForcedHighContrast();
virtual void PaintImpl(cc::PaintCanvas* canvas,
const ColorProvider* color_provider,
Part part,
State state,
const gfx::Rect& rect,
const ExtraParams& extra_params,
bool forced_colors,
bool dark_mode,
PreferredContrast contrast,
std::optional<SkColor> accent_color) const {}
virtual void PaintMenuItemBackground(
cc::PaintCanvas* canvas,
const ColorProvider* color_provider,
State state,
const gfx::Rect& rect,
const MenuItemExtraParams& extra_params) const;
virtual void OnToolkitSettingsChanged(bool force_notify);
void SetAssociatedWebInstance(NativeTheme* associated_web_instance);
bool UpdateWebInstance() const;
private:
void NotifyOnNativeThemeUpdatedImpl();
bool UpdateVariablesForToolkitSettings();
ColorProviderKey::ForcedColors CalculateForcedColors() const;
PreferredColorScheme CalculatePreferredColorScheme() const;
PreferredContrast CalculatePreferredContrast() const;
base::CallbackListSubscription os_settings_changed_subscription_;
base::CallbackListSubscription update_delay_subscription_;
base::ObserverList<NativeThemeObserver> native_theme_observers_;
SystemTheme system_theme_;
bool use_overlay_scrollbar_ = false;
ColorProviderKey::ForcedColors forced_colors_ =
ColorProviderKey::ForcedColors::kNone;
PreferredColorScheme preferred_color_scheme_ =
PreferredColorScheme::kNoPreference;
PreferredContrast preferred_contrast_ = PreferredContrast::kNoPreference;
bool prefers_reduced_transparency_ = false;
bool inverted_colors_ = false;
std::optional<SkColor> user_color_;
std::optional<ColorProviderKey::SchemeVariant> scheme_variant_;
ColorProviderKey::UserColorSource preferred_color_source_ =
ColorProviderKey::UserColorSource::kAccent;
base::TimeDelta caret_blink_interval_;
raw_ptr<NativeTheme> associated_web_instance_ = nullptr;
SEQUENCE_CHECKER(sequence_checker_);
};
}
#endif