1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef UI_NATIVE_THEME_NATIVE_THEME_H_ 6 #define UI_NATIVE_THEME_NATIVE_THEME_H_ 7 8 #include <map> 9 10 #include "base/containers/flat_map.h" 11 #include "base/macros.h" 12 #include "base/observer_list.h" 13 #include "build/build_config.h" 14 #include "cc/paint/paint_canvas.h" 15 #include "third_party/skia/include/core/SkColor.h" 16 #include "ui/base/models/menu_separator_types.h" 17 #include "ui/gfx/geometry/rect.h" 18 #include "ui/gfx/geometry/size.h" 19 #include "ui/gfx/native_widget_types.h" 20 #include "ui/native_theme/caption_style.h" 21 #include "ui/native_theme/native_theme_color_id.h" 22 #include "ui/native_theme/native_theme_export.h" 23 #include "ui/native_theme/native_theme_observer.h" 24 25 namespace gfx { 26 class Rect; 27 class Size; 28 } 29 30 namespace ui { 31 32 // This class supports drawing UI controls (like buttons, text fields, lists, 33 // comboboxes, etc) that look like the native UI controls of the underlying 34 // platform, such as Windows or Linux. It also supplies default colors for 35 // dialog box backgrounds, etc., which are obtained from the system theme where 36 // possible. 37 // 38 // The supported control types are listed in the Part enum. These parts can be 39 // in any state given by the State enum, where the actual definition of the 40 // state is part-specific. The supported colors are listed in the ColorId enum. 41 // 42 // Some parts require more information than simply the state in order to be 43 // drawn correctly, and this information is given to the Paint() method via the 44 // ExtraParams union. Each part that requires more information has its own 45 // field in the union. 46 // 47 // NativeTheme also supports getting the default size of a given part with 48 // the GetPartSize() method. 49 class NATIVE_THEME_EXPORT NativeTheme { 50 public: 51 // The part to be painted / sized. 52 enum Part { 53 kCheckbox, 54 #if (defined(OS_LINUX) || defined(OS_BSD)) && !defined(OS_CHROMEOS) 55 kFrameTopArea, 56 #endif 57 kInnerSpinButton, 58 kMenuList, 59 kMenuPopupBackground, 60 #if defined(OS_WIN) 61 kMenuCheck, 62 kMenuCheckBackground, 63 kMenuPopupArrow, 64 kMenuPopupGutter, 65 #endif 66 kMenuPopupSeparator, 67 kMenuItemBackground, 68 kProgressBar, 69 kPushButton, 70 kRadio, 71 72 // The order of the arrow enums is important, do not change without also 73 // changing the code in platform implementations. 74 kScrollbarDownArrow, 75 kScrollbarLeftArrow, 76 kScrollbarRightArrow, 77 kScrollbarUpArrow, 78 79 kScrollbarHorizontalThumb, 80 kScrollbarVerticalThumb, 81 kScrollbarHorizontalTrack, 82 kScrollbarVerticalTrack, 83 kScrollbarHorizontalGripper, 84 kScrollbarVerticalGripper, 85 // The corner is drawn when there is both a horizontal and vertical 86 // scrollbar. 87 kScrollbarCorner, 88 kSliderTrack, 89 kSliderThumb, 90 kTabPanelBackground, 91 kTextField, 92 kTrackbarThumb, 93 kTrackbarTrack, 94 kWindowResizeGripper, 95 kMaxPart, 96 }; 97 98 // The state of the part. 99 enum State { 100 // IDs defined as specific values for use in arrays. 101 kDisabled = 0, 102 kHovered = 1, 103 kNormal = 2, 104 kPressed = 3, 105 kNumStates = kPressed + 1, 106 }; 107 108 // OS-level preferred color scheme. (Ex. high contrast or dark mode color 109 // preference.) 110 enum class PreferredColorScheme { 111 kDark = 0, 112 kLight = 1, 113 kMaxValue = kLight, 114 }; 115 116 // OS-level preferred contrast. (Ex. high contrast or increased contrast.) 117 enum class PreferredContrast { 118 kNoPreference = 0, 119 kMore = 1, 120 kLess = 2, 121 kMaxValue = kLess, 122 }; 123 124 // IMPORTANT! 125 // This enum is reporting in metrics. Do not reorder; add additional values at 126 // the end. 127 // 128 // This represents the OS-level high contrast theme. kNone unless the default 129 // system color scheme is kPlatformHighContrast. 130 enum class PlatformHighContrastColorScheme { 131 kNone = 0, 132 kDark = 1, 133 kLight = 2, 134 kMaxValue = kLight, 135 }; 136 137 // The color scheme used for painting the native controls. 138 enum class ColorScheme { 139 kDefault, 140 kLight, 141 kDark, 142 kPlatformHighContrast, // When the platform is providing HC colors (eg. 143 // Win) 144 }; 145 146 // This enum represents the available unique security chip color states. 147 enum class SecurityChipColorId { 148 DEFAULT, 149 SECURE, 150 SECURE_WITH_CERT, 151 DANGEROUS, 152 }; 153 154 // Each structure below holds extra information needed when painting a given 155 // part. 156 157 struct ButtonExtraParams { 158 bool checked; 159 bool indeterminate; // Whether the button state is indeterminate. 160 bool is_default; // Whether the button is default button. 161 bool is_focused; 162 bool has_border; 163 int classic_state; // Used on Windows when uxtheme is not available. 164 SkColor background_color; 165 float zoom; 166 }; 167 168 struct FrameTopAreaExtraParams { 169 // Distinguishes between active (foreground) and inactive 170 // (background) window frame styles. 171 bool is_active; 172 bool incognito; 173 // True when Chromium renders the titlebar. False when the window 174 // manager renders the titlebar. 175 bool use_custom_frame; 176 // If the NativeTheme will paint a solid color, it should use 177 // |default_background_color|. 178 SkColor default_background_color; 179 }; 180 181 struct InnerSpinButtonExtraParams { 182 bool spin_up; 183 bool read_only; 184 int classic_state; // Used on Windows when uxtheme is not available. 185 }; 186 187 struct MenuArrowExtraParams { 188 bool pointing_right; 189 // Used for the disabled state to indicate if the item is both disabled and 190 // selected. 191 bool is_selected; 192 }; 193 194 struct MenuCheckExtraParams { 195 bool is_radio; 196 // Used for the disabled state to indicate if the item is both disabled and 197 // selected. 198 bool is_selected; 199 }; 200 201 struct MenuSeparatorExtraParams { 202 const gfx::Rect* paint_rect; 203 MenuSeparatorType type; 204 }; 205 206 struct MenuItemExtraParams { 207 bool is_selected; 208 int corner_radius; 209 }; 210 211 struct MenuListExtraParams { 212 bool has_border; 213 bool has_border_radius; 214 int arrow_x; 215 int arrow_y; 216 int arrow_size; 217 SkColor arrow_color; 218 SkColor background_color; 219 int classic_state; // Used on Windows when uxtheme is not available. 220 }; 221 222 struct MenuBackgroundExtraParams { 223 int corner_radius; 224 }; 225 226 struct ProgressBarExtraParams { 227 double animated_seconds; 228 bool determinate; 229 int value_rect_x; 230 int value_rect_y; 231 int value_rect_width; 232 int value_rect_height; 233 }; 234 235 struct ScrollbarArrowExtraParams { 236 bool is_hovering; 237 float zoom; 238 bool right_to_left; 239 }; 240 241 struct ScrollbarTrackExtraParams { 242 bool is_upper; 243 int track_x; 244 int track_y; 245 int track_width; 246 int track_height; 247 int classic_state; // Used on Windows when uxtheme is not available. 248 }; 249 250 enum ScrollbarOverlayColorTheme { 251 ScrollbarOverlayColorThemeDark, 252 ScrollbarOverlayColorThemeLight 253 }; 254 255 struct ScrollbarThumbExtraParams { 256 bool is_hovering; 257 ScrollbarOverlayColorTheme scrollbar_theme; 258 }; 259 260 #if defined(OS_APPLE) 261 enum ScrollbarOrientation { 262 // Vertical scrollbar on the right side of content. 263 kVerticalOnRight, 264 // Vertical scrollbar on the left side of content. 265 kVerticalOnLeft, 266 // Horizontal scrollbar (on the bottom of content). 267 kHorizontal, 268 }; 269 270 // A unique set of scrollbar params. Currently needed for Mac. 271 struct ScrollbarExtraParams { 272 bool is_hovering; 273 bool is_overlay; 274 ScrollbarOverlayColorTheme scrollbar_theme; 275 ScrollbarOrientation orientation; // Used on Mac for drawing gradients. 276 }; 277 #endif 278 279 struct SliderExtraParams { 280 bool vertical; 281 bool in_drag; 282 int thumb_x; 283 int thumb_y; 284 float zoom; 285 bool right_to_left; 286 }; 287 288 struct TextFieldExtraParams { 289 bool is_text_area; 290 bool is_listbox; 291 SkColor background_color; 292 bool is_read_only; 293 bool is_focused; 294 bool fill_content_area; 295 bool draw_edges; 296 int classic_state; // Used on Windows when uxtheme is not available. 297 bool has_border; 298 bool auto_complete_active; 299 }; 300 301 struct TrackbarExtraParams { 302 bool vertical; 303 int classic_state; // Used on Windows when uxtheme is not available. 304 }; 305 306 union NATIVE_THEME_EXPORT ExtraParams { 307 ExtraParams(); 308 ExtraParams(const ExtraParams& other); 309 310 ButtonExtraParams button; 311 FrameTopAreaExtraParams frame_top_area; 312 InnerSpinButtonExtraParams inner_spin; 313 MenuArrowExtraParams menu_arrow; 314 MenuCheckExtraParams menu_check; 315 MenuItemExtraParams menu_item; 316 MenuSeparatorExtraParams menu_separator; 317 MenuListExtraParams menu_list; 318 MenuBackgroundExtraParams menu_background; 319 ProgressBarExtraParams progress_bar; 320 ScrollbarArrowExtraParams scrollbar_arrow; 321 #if defined(OS_APPLE) 322 ScrollbarExtraParams scrollbar_extra; 323 #endif 324 ScrollbarTrackExtraParams scrollbar_track; 325 ScrollbarThumbExtraParams scrollbar_thumb; 326 SliderExtraParams slider; 327 TextFieldExtraParams text_field; 328 TrackbarExtraParams trackbar; 329 }; 330 331 // Return the size of the part. 332 virtual gfx::Size GetPartSize(Part part, 333 State state, 334 const ExtraParams& extra) const = 0; 335 336 virtual float GetBorderRadiusForPart(Part part, 337 float width, 338 float height, 339 float zoom) const; 340 341 // Paint the part to the canvas. 342 virtual void Paint( 343 cc::PaintCanvas* canvas, 344 Part part, 345 State state, 346 const gfx::Rect& rect, 347 const ExtraParams& extra, 348 ColorScheme color_scheme = ColorScheme::kDefault) const = 0; 349 350 // Paint part during state transition, used for overlay scrollbar state 351 // transition animation. PaintStateTransition(cc::PaintCanvas * canvas,Part part,State startState,State endState,double progress,const gfx::Rect & rect,ScrollbarOverlayColorTheme theme)352 virtual void PaintStateTransition(cc::PaintCanvas* canvas, 353 Part part, 354 State startState, 355 State endState, 356 double progress, 357 const gfx::Rect& rect, 358 ScrollbarOverlayColorTheme theme) const {} 359 360 // Returns whether the theme uses a nine-patch resource for the given part. 361 // If true, calling code should always paint into a canvas the size of which 362 // can be gotten from GetNinePatchCanvasSize. 363 virtual bool SupportsNinePatch(Part part) const = 0; 364 365 // If the part paints into a nine-patch resource, the size of the canvas 366 // which should be painted into. 367 virtual gfx::Size GetNinePatchCanvasSize(Part part) const = 0; 368 369 // If the part paints into a nine-patch resource, the rect in the canvas 370 // which defines the center tile. This is the tile that should be resized out 371 // when the part is resized. 372 virtual gfx::Rect GetNinePatchAperture(Part part) const = 0; 373 374 // Colors for GetSystemColor(). 375 enum ColorId { 376 #define OP(enum_name) enum_name 377 NATIVE_THEME_COLOR_IDS, 378 #undef OP 379 380 kColorId_NumColors, 381 }; 382 383 enum class SystemThemeColor { 384 kNotSupported, 385 kButtonFace, 386 kButtonText, 387 kGrayText, 388 kHighlight, 389 kHighlightText, 390 kHotlight, 391 kMenuHighlight, 392 kScrollbar, 393 kWindow, 394 kWindowText, 395 kMaxValue = kWindowText, 396 }; 397 398 // Return a color from the system theme. 399 virtual SkColor GetSystemColor( 400 ColorId color_id, 401 ColorScheme color_scheme = ColorScheme::kDefault) const; 402 403 // Returns a shared instance of the native theme that should be used for web 404 // rendering. Do not use it in a normal application context (i.e. browser). 405 // The returned object should not be deleted by the caller. This function is 406 // not thread safe and should only be called from the UI thread. Each port of 407 // NativeTheme should provide its own implementation of this function, 408 // returning the port's subclass. 409 static NativeTheme* GetInstanceForWeb(); 410 411 // Returns a shared instance of the default native theme for native UI. 412 static NativeTheme* GetInstanceForNativeUi(); 413 414 // Returns a shared instance of the native theme for incognito UI. 415 static NativeTheme* GetInstanceForDarkUI(); 416 417 // Whether OS-level dark mode is available in the current OS. 418 static bool SystemDarkModeSupported(); 419 420 // Add or remove observers to be notified when the native theme changes. 421 void AddObserver(NativeThemeObserver* observer); 422 void RemoveObserver(NativeThemeObserver* observer); 423 424 // Notify observers of native theme changes. 425 void NotifyObservers(); 426 427 // Returns whether this NativeTheme uses higher-contrast colors, controlled by 428 // system accessibility settings and the system theme. 429 virtual bool UsesHighContrastColors() const; 430 431 // Returns the PlatformHighContrastColorScheme used by the OS. Returns a value 432 // other than kNone only if the default system color scheme is 433 // kPlatformHighContrast. 434 PlatformHighContrastColorScheme GetPlatformHighContrastColorScheme() const; 435 436 // Returns true when the NativeTheme uses a light-on-dark color scheme. If 437 // you're considering using this function to choose between two hard-coded 438 // colors, you probably shouldn't. Instead, use GetSystemColor(). 439 virtual bool ShouldUseDarkColors() const; 440 441 // Returns the OS-level user preferred color scheme. See the comment for 442 // CalculatePreferredColorScheme() for details on how preferred color scheme 443 // is calculated. 444 virtual PreferredColorScheme GetPreferredColorScheme() const; 445 446 // Returns the OS-level user preferred contrast. 447 virtual PreferredContrast GetPreferredContrast() const; 448 449 // Returns the system's caption style. 450 virtual base::Optional<CaptionStyle> GetSystemCaptionStyle() const; 451 452 virtual ColorScheme GetDefaultSystemColorScheme() const; 453 454 virtual const std::map<SystemThemeColor, SkColor>& GetSystemColors() const; 455 456 base::Optional<SkColor> GetSystemThemeColor( 457 SystemThemeColor theme_color) const; 458 459 bool HasDifferentSystemColors( 460 const std::map<SystemThemeColor, SkColor>& colors) const; 461 set_use_dark_colors(bool should_use_dark_colors)462 void set_use_dark_colors(bool should_use_dark_colors) { 463 should_use_dark_colors_ = should_use_dark_colors; 464 } set_high_contrast(bool is_high_contrast)465 void set_high_contrast(bool is_high_contrast) { 466 is_high_contrast_ = is_high_contrast; 467 } set_preferred_color_scheme(PreferredColorScheme preferred_color_scheme)468 void set_preferred_color_scheme(PreferredColorScheme preferred_color_scheme) { 469 preferred_color_scheme_ = preferred_color_scheme; 470 } set_preferred_contrast(PreferredContrast preferred_contrast)471 void set_preferred_contrast(PreferredContrast preferred_contrast) { 472 preferred_contrast_ = preferred_contrast; 473 } 474 void set_system_colors(const std::map<SystemThemeColor, SkColor>& colors); 475 476 // Updates the state of dark mode, high contrast, and the map of system 477 // colors. Returns true if NativeTheme was updated as a result, or false if 478 // the state of NativeTheme was untouched. 479 bool UpdateSystemColorInfo( 480 bool is_dark_mode, 481 bool is_high_contrast, 482 const base::flat_map<SystemThemeColor, uint32_t>& colors); 483 484 // On certain platforms, currently only Mac, there is a unique visual for 485 // pressed states. 486 virtual SkColor GetSystemButtonPressedColor(SkColor base_color) const; 487 488 // Assign the focus-ring-appropriate alpha value to the provided base_color. 489 virtual SkColor FocusRingColorForBaseColor(SkColor base_color) const; 490 491 protected: 492 explicit NativeTheme(bool should_only_use_dark_colors); 493 virtual ~NativeTheme(); 494 495 // Whether high contrast is forced via command-line flag. 496 bool IsForcedHighContrast() const; 497 // Whether dark mode is forced via command-line flag. 498 bool IsForcedDarkMode() const; 499 500 // Calculates and returns the current user preferred color scheme. The 501 // base behavior is to set preferred color scheme to light or dark depending 502 // on the state of dark mode. 503 // 504 // Some platforms override this behavior. On Windows, for example, we also 505 // look at the high contrast setting. If high contrast is enabled, the 506 // preferred color scheme calculation will ignore the state of dark mode. 507 // Instead, preferred color scheme will be light, or dark depending on the OS 508 // high contrast theme. If high contrast is off, the preferred color scheme 509 // calculation will follow the default behavior. 510 virtual PreferredColorScheme CalculatePreferredColorScheme() const; 511 512 // Calculates and returns the current user preferred contrast. 513 virtual PreferredContrast CalculatePreferredContrast() const; 514 515 // A function to be called by native theme instances that need to set state 516 // or listeners with the webinstance in order to provide correct native 517 // platform behaviors. ConfigureWebInstance()518 virtual void ConfigureWebInstance() {} 519 520 // Allows one native theme to observe changes in another. For example, the 521 // web native theme for Windows observes the corresponding ui native theme in 522 // order to receive changes regarding the state of dark mode, high contrast, 523 // preferred color scheme and preferred contrast. 524 class NATIVE_THEME_EXPORT ColorSchemeNativeThemeObserver 525 : public NativeThemeObserver { 526 public: 527 ColorSchemeNativeThemeObserver(NativeTheme* theme_to_update); 528 ~ColorSchemeNativeThemeObserver() override; 529 530 private: 531 // ui::NativeThemeObserver: 532 void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override; 533 534 // The theme that gets updated when OnNativeThemeUpdated() is called. 535 NativeTheme* const theme_to_update_; 536 537 DISALLOW_COPY_AND_ASSIGN(ColorSchemeNativeThemeObserver); 538 }; 539 540 mutable std::map<SystemThemeColor, SkColor> system_colors_; 541 542 private: 543 // Observers to notify when the native theme changes. 544 base::ObserverList<NativeThemeObserver>::Unchecked native_theme_observers_; 545 546 bool should_use_dark_colors_ = false; 547 bool is_high_contrast_ = false; 548 PreferredColorScheme preferred_color_scheme_ = PreferredColorScheme::kLight; 549 PreferredContrast preferred_contrast_ = PreferredContrast::kNoPreference; 550 551 DISALLOW_COPY_AND_ASSIGN(NativeTheme); 552 }; 553 554 } // namespace ui 555 556 #endif // UI_NATIVE_THEME_NATIVE_THEME_H_ 557