native_theme_aura.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  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. #include "ui/native_theme/native_theme_aura.h"
  5. #include <limits>
  6. #include <utility>
  7. #include "base/check_op.h"
  8. #include "base/containers/fixed_flat_map.h"
  9. #include "base/no_destructor.h"
  10. #include "base/notreached.h"
  11. #include "base/trace_event/trace_event.h"
  12. #include "build/build_config.h"
  13. #include "cc/paint/paint_canvas.h"
  14. #include "cc/paint/paint_flags.h"
  15. #include "third_party/skia/include/core/SkPath.h"
  16. #include "ui/base/layout.h"
  17. #include "ui/base/ui_base_features.h"
  18. #include "ui/color/color_provider.h"
  19. #include "ui/gfx/animation/tween.h"
  20. #include "ui/gfx/canvas.h"
  21. #include "ui/gfx/color_palette.h"
  22. #include "ui/gfx/geometry/insets.h"
  23. #include "ui/gfx/geometry/rect.h"
  24. #include "ui/gfx/geometry/rrect_f.h"
  25. #include "ui/gfx/geometry/size.h"
  26. #include "ui/gfx/geometry/skia_conversions.h"
  27. #include "ui/gfx/image/image_skia.h"
  28. #include "ui/native_theme/common_theme.h"
  29. #include "ui/native_theme/native_theme_features.h"
  30. #include "ui/native_theme/overlay_scrollbar_constants_aura.h"
  31. namespace ui {
  32. namespace {
  33. // Constants for painting overlay scrollbars. Other properties needed outside
  34. // this painting code are defined in overlay_scrollbar_constants_aura.h.
  35. constexpr int kOverlayScrollbarMinimumLength = 32;
  36. // 2 pixel border with 1 pixel center patch. The border is 2 pixels despite the
  37. // stroke width being 1 so that the inner pixel can match the center tile
  38. // color. This prevents color interpolation between the patches.
  39. constexpr int kOverlayScrollbarBorderPatchWidth = 2;
  40. constexpr int kOverlayScrollbarCenterPatchSize = 1;
  41. const SkScalar kScrollRadius =
  42. 1; // select[multiple] radius+width are set in css
  43. } // namespace
  44. ////////////////////////////////////////////////////////////////////////////////
  45. // NativeTheme:
  46. #if !BUILDFLAG(IS_APPLE)
  47. // static
  48. NativeTheme* NativeTheme::GetInstanceForWeb() {
  49. return NativeThemeAura::web_instance();
  50. }
  51. #if !BUILDFLAG(IS_WIN)
  52. // static
  53. NativeTheme* NativeTheme::GetInstanceForNativeUi() {
  54. static base::NoDestructor<NativeThemeAura> s_native_theme(false, false);
  55. return s_native_theme.get();
  56. }
  57. NativeTheme* NativeTheme::GetInstanceForDarkUI() {
  58. static base::NoDestructor<NativeThemeAura> s_native_theme(false, true);
  59. return s_native_theme.get();
  60. }
  61. #endif // !BUILDFLAG(IS_WIN)
  62. #endif // !BUILDFLAG(IS_APPLE)
  63. ////////////////////////////////////////////////////////////////////////////////
  64. // NativeThemeAura:
  65. NativeThemeAura::NativeThemeAura(bool use_overlay_scrollbars,
  66. bool should_only_use_dark_colors,
  67. bool is_custom_system_theme)
  68. : NativeThemeBase(should_only_use_dark_colors, is_custom_system_theme),
  69. use_overlay_scrollbars_(use_overlay_scrollbars) {
  70. // We don't draw scrollbar buttons.
  71. #if BUILDFLAG(IS_CHROMEOS)
  72. set_scrollbar_button_length(0);
  73. #endif
  74. if (use_overlay_scrollbars_) {
  75. scrollbar_width_ =
  76. kOverlayScrollbarThumbWidthPressed + kOverlayScrollbarStrokeWidth;
  77. }
  78. // Images and alphas declarations assume the following order.
  79. static_assert(kDisabled == 0, "states unexpectedly changed");
  80. static_assert(kHovered == 1, "states unexpectedly changed");
  81. static_assert(kNormal == 2, "states unexpectedly changed");
  82. static_assert(kPressed == 3, "states unexpectedly changed");
  83. }
  84. NativeThemeAura::~NativeThemeAura() {}
  85. // static
  86. NativeThemeAura* NativeThemeAura::web_instance() {
  87. static base::NoDestructor<NativeThemeAura> s_native_theme_for_web(
  88. IsOverlayScrollbarEnabled(), false);
  89. return s_native_theme_for_web.get();
  90. }
  91. SkColor NativeThemeAura::FocusRingColorForBaseColor(SkColor base_color) const {
  92. #if BUILDFLAG(IS_APPLE)
  93. // On Mac OSX, the system Accent Color setting is darkened a bit
  94. // for better contrast.
  95. return SkColorSetA(base_color, 166);
  96. #else
  97. return base_color;
  98. #endif // BUILDFLAG(IS_APPLE)
  99. }
  100. void NativeThemeAura::PaintMenuPopupBackground(
  101. cc::PaintCanvas* canvas,
  102. const ColorProvider* color_provider,
  103. const gfx::Size& size,
  104. const MenuBackgroundExtraParams& menu_background,
  105. ColorScheme color_scheme) const {
  106. DCHECK(color_provider);
  107. // TODO(crbug/1308932): Remove FromColor and make all SkColor4f.
  108. SkColor4f color =
  109. SkColor4f::FromColor(color_provider->GetColor(kColorMenuBackground));
  110. if (menu_background.corner_radius > 0) {
  111. cc::PaintFlags flags;
  112. flags.setStyle(cc::PaintFlags::kFill_Style);
  113. flags.setAntiAlias(true);
  114. flags.setColor(color);
  115. SkPath path;
  116. SkRect rect = SkRect::MakeWH(SkIntToScalar(size.width()),
  117. SkIntToScalar(size.height()));
  118. SkScalar radius = SkIntToScalar(menu_background.corner_radius);
  119. SkScalar radii[8] = {radius, radius, radius, radius,
  120. radius, radius, radius, radius};
  121. path.addRoundRect(rect, radii);
  122. canvas->drawPath(path, flags);
  123. } else {
  124. canvas->drawColor(color, SkBlendMode::kSrc);
  125. }
  126. }
  127. void NativeThemeAura::PaintMenuItemBackground(
  128. cc::PaintCanvas* canvas,
  129. const ColorProvider* color_provider,
  130. State state,
  131. const gfx::Rect& rect,
  132. const MenuItemExtraParams& menu_item,
  133. ColorScheme color_scheme) const {
  134. CommonThemePaintMenuItemBackground(this, color_provider, canvas, state, rect,
  135. menu_item);
  136. }
  137. void NativeThemeAura::PaintArrowButton(
  138. cc::PaintCanvas* canvas,
  139. const gfx::Rect& rect,
  140. Part direction,
  141. State state,
  142. ColorScheme color_scheme,
  143. const ScrollbarArrowExtraParams& arrow) const {
  144. SkColor bg_color = GetControlColor(kScrollbarArrowBackground, color_scheme);
  145. // Aura-win uses slightly different arrow colors.
  146. SkColor arrow_color = gfx::kPlaceholderColor;
  147. switch (state) {
  148. case kDisabled:
  149. arrow_color = GetArrowColor(state, color_scheme);
  150. break;
  151. case kHovered:
  152. bg_color =
  153. GetControlColor(kScrollbarArrowBackgroundHovered, color_scheme);
  154. arrow_color = GetControlColor(kScrollbarArrowHovered, color_scheme);
  155. break;
  156. case kNormal:
  157. arrow_color = GetControlColor(kScrollbarArrow, color_scheme);
  158. break;
  159. case kPressed:
  160. bg_color =
  161. GetControlColor(kScrollbarArrowBackgroundPressed, color_scheme);
  162. arrow_color = GetControlColor(kScrollbarArrowPressed, color_scheme);
  163. break;
  164. case kNumStates:
  165. break;
  166. }
  167. DCHECK_NE(arrow_color, gfx::kPlaceholderColor);
  168. cc::PaintFlags flags;
  169. flags.setColor(bg_color);
  170. SkScalar upper_left_radius = 0;
  171. SkScalar lower_left_radius = 0;
  172. SkScalar upper_right_radius = 0;
  173. SkScalar lower_right_radius = 0;
  174. float zoom = arrow.zoom ? arrow.zoom : 1.0;
  175. if (direction == kScrollbarUpArrow) {
  176. if (arrow.right_to_left) {
  177. upper_left_radius = kScrollRadius * zoom;
  178. } else {
  179. upper_right_radius = kScrollRadius * zoom;
  180. }
  181. } else if (direction == kScrollbarDownArrow) {
  182. if (arrow.right_to_left) {
  183. lower_left_radius = kScrollRadius * zoom;
  184. } else {
  185. lower_right_radius = kScrollRadius * zoom;
  186. }
  187. }
  188. DrawPartiallyRoundRect(canvas, rect, upper_left_radius, upper_right_radius,
  189. lower_right_radius, lower_left_radius, flags);
  190. PaintArrow(canvas, rect, direction, arrow_color);
  191. }
  192. void NativeThemeAura::PaintScrollbarTrack(
  193. cc::PaintCanvas* canvas,
  194. Part part,
  195. State state,
  196. const ScrollbarTrackExtraParams& extra_params,
  197. const gfx::Rect& rect,
  198. ColorScheme color_scheme) const {
  199. // Overlay Scrollbar should never paint a scrollbar track.
  200. DCHECK(!use_overlay_scrollbars_);
  201. cc::PaintFlags flags;
  202. SkColor track_color = GetControlColor(kScrollbarTrack, color_scheme);
  203. flags.setColor(track_color);
  204. canvas->drawIRect(gfx::RectToSkIRect(rect), flags);
  205. }
  206. void NativeThemeAura::PaintScrollbarThumb(cc::PaintCanvas* canvas,
  207. const ColorProvider* color_provider,
  208. Part part,
  209. State state,
  210. const gfx::Rect& rect,
  211. ScrollbarOverlayColorTheme theme,
  212. ColorScheme color_scheme) const {
  213. // Do not paint if state is disabled.
  214. if (state == kDisabled)
  215. return;
  216. TRACE_EVENT0("blink", "NativeThemeAura::PaintScrollbarThumb");
  217. gfx::Rect thumb_rect(rect);
  218. SkColor thumb_color;
  219. if (use_overlay_scrollbars_) {
  220. if (state == NativeTheme::kDisabled)
  221. return;
  222. const bool hovered = state != kNormal;
  223. static constexpr auto kFillIdMap =
  224. base::MakeFixedFlatMap<ScrollbarOverlayColorTheme, std::array<int, 2>>({
  225. {ScrollbarOverlayColorTheme::kDefault,
  226. {kColorOverlayScrollbarFill, kColorOverlayScrollbarFillHovered}},
  227. {ScrollbarOverlayColorTheme::kLight,
  228. {kColorOverlayScrollbarFillLight,
  229. kColorOverlayScrollbarFillHoveredLight}},
  230. {ScrollbarOverlayColorTheme::kDark,
  231. {kColorOverlayScrollbarFillDark,
  232. kColorOverlayScrollbarFillHoveredDark}},
  233. });
  234. static constexpr auto kStrokeIdMap =
  235. base::MakeFixedFlatMap<ScrollbarOverlayColorTheme, std::array<int, 2>>({
  236. {ScrollbarOverlayColorTheme::kDefault,
  237. {kColorOverlayScrollbarStroke,
  238. kColorOverlayScrollbarStrokeHovered}},
  239. {ScrollbarOverlayColorTheme::kLight,
  240. {kColorOverlayScrollbarStrokeLight,
  241. kColorOverlayScrollbarStrokeHoveredLight}},
  242. {ScrollbarOverlayColorTheme::kDark,
  243. {kColorOverlayScrollbarStrokeDark,
  244. kColorOverlayScrollbarStrokeHoveredDark}},
  245. });
  246. DCHECK(color_provider);
  247. thumb_color = color_provider->GetColor(kFillIdMap.at(theme)[hovered]);
  248. const SkColor stroke_color =
  249. color_provider->GetColor(kStrokeIdMap.at(theme)[hovered]);
  250. // In overlay mode, draw a stroke (border).
  251. constexpr int kStrokeWidth = kOverlayScrollbarStrokeWidth;
  252. cc::PaintFlags flags;
  253. flags.setColor(stroke_color);
  254. flags.setStyle(cc::PaintFlags::kStroke_Style);
  255. flags.setStrokeWidth(kStrokeWidth);
  256. gfx::RectF stroke_rect(thumb_rect);
  257. gfx::InsetsF stroke_insets(kStrokeWidth / 2.f);
  258. // The edge to which the scrollbar is attached shouldn't have a border.
  259. gfx::Insets edge_adjust_insets;
  260. if (part == NativeTheme::kScrollbarHorizontalThumb)
  261. edge_adjust_insets.set_bottom(-kStrokeWidth);
  262. else
  263. edge_adjust_insets.set_right(-kStrokeWidth);
  264. stroke_rect.Inset(stroke_insets + gfx::InsetsF(edge_adjust_insets));
  265. canvas->drawRect(gfx::RectFToSkRect(stroke_rect), flags);
  266. // Inset the all the edges edges so we fill-in the stroke below.
  267. // For left vertical scrollbar, we will horizontally flip the canvas in
  268. // ScrollbarThemeOverlay::paintThumb.
  269. gfx::Insets fill_insets(kStrokeWidth);
  270. thumb_rect.Inset(fill_insets + edge_adjust_insets);
  271. } else {
  272. ControlColorId color_id = kScrollbarThumb;
  273. SkAlpha thumb_alpha = SK_AlphaTRANSPARENT;
  274. switch (state) {
  275. case NativeTheme::kDisabled:
  276. break;
  277. case NativeTheme::kHovered:
  278. color_id = kScrollbarThumbHovered;
  279. thumb_alpha = 0x4D;
  280. break;
  281. case NativeTheme::kNormal:
  282. thumb_alpha = 0x33;
  283. break;
  284. case NativeTheme::kPressed:
  285. color_id = kScrollbarThumbPressed;
  286. thumb_alpha = 0x80;
  287. break;
  288. case NativeTheme::kNumStates:
  289. NOTREACHED();
  290. break;
  291. }
  292. // If there are no scrollbuttons then provide some padding so that the thumb
  293. // doesn't touch the top of the track.
  294. const int kThumbPadding = 2;
  295. const int extra_padding =
  296. (scrollbar_button_length() == 0) ? kThumbPadding : 0;
  297. if (part == NativeTheme::kScrollbarVerticalThumb)
  298. thumb_rect.Inset(gfx::Insets::VH(extra_padding, kThumbPadding));
  299. else
  300. thumb_rect.Inset(gfx::Insets::VH(kThumbPadding, extra_padding));
  301. thumb_color =
  302. (InForcedColorsMode() && features::IsForcedColorsEnabled())
  303. ? GetControlColor(color_id, color_scheme)
  304. : SkColorSetA(GetControlColor(kScrollbarThumb, color_scheme),
  305. thumb_alpha);
  306. }
  307. cc::PaintFlags flags;
  308. flags.setColor(thumb_color);
  309. canvas->drawIRect(gfx::RectToSkIRect(thumb_rect), flags);
  310. }
  311. void NativeThemeAura::PaintScrollbarCorner(cc::PaintCanvas* canvas,
  312. State state,
  313. const gfx::Rect& rect,
  314. ColorScheme color_scheme) const {
  315. // Overlay Scrollbar should never paint a scrollbar corner.
  316. DCHECK(!use_overlay_scrollbars_);
  317. cc::PaintFlags flags;
  318. SkColor bg_color = color_scheme == ui::NativeTheme::ColorScheme::kDark
  319. ? SkColorSetRGB(0x12, 0x12, 0x12)
  320. : SkColorSetRGB(0xDC, 0xDC, 0xDC);
  321. flags.setColor(bg_color);
  322. canvas->drawIRect(RectToSkIRect(rect), flags);
  323. }
  324. gfx::Size NativeThemeAura::GetPartSize(Part part,
  325. State state,
  326. const ExtraParams& extra) const {
  327. if (use_overlay_scrollbars_) {
  328. constexpr int minimum_length =
  329. kOverlayScrollbarMinimumLength + 2 * kOverlayScrollbarStrokeWidth;
  330. // Aura overlay scrollbars need a slight tweak from the base sizes.
  331. switch (part) {
  332. case kScrollbarHorizontalThumb:
  333. return gfx::Size(minimum_length, scrollbar_width_);
  334. case kScrollbarVerticalThumb:
  335. return gfx::Size(scrollbar_width_, minimum_length);
  336. default:
  337. // TODO(bokan): We should probably make sure code using overlay
  338. // scrollbars isn't asking for part sizes that don't exist.
  339. // crbug.com/657159.
  340. break;
  341. }
  342. }
  343. return NativeThemeBase::GetPartSize(part, state, extra);
  344. }
  345. void NativeThemeAura::DrawPartiallyRoundRect(cc::PaintCanvas* canvas,
  346. const gfx::Rect& rect,
  347. const SkScalar upper_left_radius,
  348. const SkScalar upper_right_radius,
  349. const SkScalar lower_right_radius,
  350. const SkScalar lower_left_radius,
  351. const cc::PaintFlags& flags) {
  352. gfx::RRectF rounded_rect(
  353. gfx::RectF(rect), upper_left_radius, upper_left_radius,
  354. upper_right_radius, upper_right_radius, lower_right_radius,
  355. lower_right_radius, lower_left_radius, lower_left_radius);
  356. canvas->drawRRect(static_cast<SkRRect>(rounded_rect), flags);
  357. }
  358. bool NativeThemeAura::SupportsNinePatch(Part part) const {
  359. if (!IsOverlayScrollbarEnabled())
  360. return false;
  361. return part == kScrollbarHorizontalThumb || part == kScrollbarVerticalThumb;
  362. }
  363. gfx::Size NativeThemeAura::GetNinePatchCanvasSize(Part part) const {
  364. DCHECK(SupportsNinePatch(part));
  365. return gfx::Size(
  366. kOverlayScrollbarBorderPatchWidth * 2 + kOverlayScrollbarCenterPatchSize,
  367. kOverlayScrollbarBorderPatchWidth * 2 + kOverlayScrollbarCenterPatchSize);
  368. }
  369. gfx::Rect NativeThemeAura::GetNinePatchAperture(Part part) const {
  370. DCHECK(SupportsNinePatch(part));
  371. return gfx::Rect(
  372. kOverlayScrollbarBorderPatchWidth, kOverlayScrollbarBorderPatchWidth,
  373. kOverlayScrollbarCenterPatchSize, kOverlayScrollbarCenterPatchSize);
  374. }
  375. } // namespace ui