123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ui/native_theme/native_theme_aura.h"
- #include <limits>
- #include <utility>
- #include "base/check_op.h"
- #include "base/containers/fixed_flat_map.h"
- #include "base/no_destructor.h"
- #include "base/notreached.h"
- #include "base/trace_event/trace_event.h"
- #include "build/build_config.h"
- #include "cc/paint/paint_canvas.h"
- #include "cc/paint/paint_flags.h"
- #include "third_party/skia/include/core/SkPath.h"
- #include "ui/base/layout.h"
- #include "ui/base/ui_base_features.h"
- #include "ui/color/color_provider.h"
- #include "ui/gfx/animation/tween.h"
- #include "ui/gfx/canvas.h"
- #include "ui/gfx/color_palette.h"
- #include "ui/gfx/geometry/insets.h"
- #include "ui/gfx/geometry/rect.h"
- #include "ui/gfx/geometry/rrect_f.h"
- #include "ui/gfx/geometry/size.h"
- #include "ui/gfx/geometry/skia_conversions.h"
- #include "ui/gfx/image/image_skia.h"
- #include "ui/native_theme/common_theme.h"
- #include "ui/native_theme/native_theme_features.h"
- #include "ui/native_theme/overlay_scrollbar_constants_aura.h"
- namespace ui {
- namespace {
- // Constants for painting overlay scrollbars. Other properties needed outside
- // this painting code are defined in overlay_scrollbar_constants_aura.h.
- constexpr int kOverlayScrollbarMinimumLength = 32;
- // 2 pixel border with 1 pixel center patch. The border is 2 pixels despite the
- // stroke width being 1 so that the inner pixel can match the center tile
- // color. This prevents color interpolation between the patches.
- constexpr int kOverlayScrollbarBorderPatchWidth = 2;
- constexpr int kOverlayScrollbarCenterPatchSize = 1;
- const SkScalar kScrollRadius =
- 1; // select[multiple] radius+width are set in css
- } // namespace
- ////////////////////////////////////////////////////////////////////////////////
- // NativeTheme:
- #if !BUILDFLAG(IS_APPLE)
- // static
- NativeTheme* NativeTheme::GetInstanceForWeb() {
- return NativeThemeAura::web_instance();
- }
- #if !BUILDFLAG(IS_WIN)
- // static
- NativeTheme* NativeTheme::GetInstanceForNativeUi() {
- static base::NoDestructor<NativeThemeAura> s_native_theme(false, false);
- return s_native_theme.get();
- }
- NativeTheme* NativeTheme::GetInstanceForDarkUI() {
- static base::NoDestructor<NativeThemeAura> s_native_theme(false, true);
- return s_native_theme.get();
- }
- #endif // !BUILDFLAG(IS_WIN)
- #endif // !BUILDFLAG(IS_APPLE)
- ////////////////////////////////////////////////////////////////////////////////
- // NativeThemeAura:
- NativeThemeAura::NativeThemeAura(bool use_overlay_scrollbars,
- bool should_only_use_dark_colors,
- bool is_custom_system_theme)
- : NativeThemeBase(should_only_use_dark_colors, is_custom_system_theme),
- use_overlay_scrollbars_(use_overlay_scrollbars) {
- // We don't draw scrollbar buttons.
- #if BUILDFLAG(IS_CHROMEOS)
- set_scrollbar_button_length(0);
- #endif
- if (use_overlay_scrollbars_) {
- scrollbar_width_ =
- kOverlayScrollbarThumbWidthPressed + kOverlayScrollbarStrokeWidth;
- }
- // Images and alphas declarations assume the following order.
- static_assert(kDisabled == 0, "states unexpectedly changed");
- static_assert(kHovered == 1, "states unexpectedly changed");
- static_assert(kNormal == 2, "states unexpectedly changed");
- static_assert(kPressed == 3, "states unexpectedly changed");
- }
- NativeThemeAura::~NativeThemeAura() {}
- // static
- NativeThemeAura* NativeThemeAura::web_instance() {
- static base::NoDestructor<NativeThemeAura> s_native_theme_for_web(
- IsOverlayScrollbarEnabled(), false);
- return s_native_theme_for_web.get();
- }
- SkColor NativeThemeAura::FocusRingColorForBaseColor(SkColor base_color) const {
- #if BUILDFLAG(IS_APPLE)
- // On Mac OSX, the system Accent Color setting is darkened a bit
- // for better contrast.
- return SkColorSetA(base_color, 166);
- #else
- return base_color;
- #endif // BUILDFLAG(IS_APPLE)
- }
- void NativeThemeAura::PaintMenuPopupBackground(
- cc::PaintCanvas* canvas,
- const ColorProvider* color_provider,
- const gfx::Size& size,
- const MenuBackgroundExtraParams& menu_background,
- ColorScheme color_scheme) const {
- DCHECK(color_provider);
- // TODO(crbug/1308932): Remove FromColor and make all SkColor4f.
- SkColor4f color =
- SkColor4f::FromColor(color_provider->GetColor(kColorMenuBackground));
- if (menu_background.corner_radius > 0) {
- cc::PaintFlags flags;
- flags.setStyle(cc::PaintFlags::kFill_Style);
- flags.setAntiAlias(true);
- flags.setColor(color);
- SkPath path;
- SkRect rect = SkRect::MakeWH(SkIntToScalar(size.width()),
- SkIntToScalar(size.height()));
- SkScalar radius = SkIntToScalar(menu_background.corner_radius);
- SkScalar radii[8] = {radius, radius, radius, radius,
- radius, radius, radius, radius};
- path.addRoundRect(rect, radii);
- canvas->drawPath(path, flags);
- } else {
- canvas->drawColor(color, SkBlendMode::kSrc);
- }
- }
- void NativeThemeAura::PaintMenuItemBackground(
- cc::PaintCanvas* canvas,
- const ColorProvider* color_provider,
- State state,
- const gfx::Rect& rect,
- const MenuItemExtraParams& menu_item,
- ColorScheme color_scheme) const {
- CommonThemePaintMenuItemBackground(this, color_provider, canvas, state, rect,
- menu_item);
- }
- void NativeThemeAura::PaintArrowButton(
- cc::PaintCanvas* canvas,
- const gfx::Rect& rect,
- Part direction,
- State state,
- ColorScheme color_scheme,
- const ScrollbarArrowExtraParams& arrow) const {
- SkColor bg_color = GetControlColor(kScrollbarArrowBackground, color_scheme);
- // Aura-win uses slightly different arrow colors.
- SkColor arrow_color = gfx::kPlaceholderColor;
- switch (state) {
- case kDisabled:
- arrow_color = GetArrowColor(state, color_scheme);
- break;
- case kHovered:
- bg_color =
- GetControlColor(kScrollbarArrowBackgroundHovered, color_scheme);
- arrow_color = GetControlColor(kScrollbarArrowHovered, color_scheme);
- break;
- case kNormal:
- arrow_color = GetControlColor(kScrollbarArrow, color_scheme);
- break;
- case kPressed:
- bg_color =
- GetControlColor(kScrollbarArrowBackgroundPressed, color_scheme);
- arrow_color = GetControlColor(kScrollbarArrowPressed, color_scheme);
- break;
- case kNumStates:
- break;
- }
- DCHECK_NE(arrow_color, gfx::kPlaceholderColor);
- cc::PaintFlags flags;
- flags.setColor(bg_color);
- SkScalar upper_left_radius = 0;
- SkScalar lower_left_radius = 0;
- SkScalar upper_right_radius = 0;
- SkScalar lower_right_radius = 0;
- float zoom = arrow.zoom ? arrow.zoom : 1.0;
- if (direction == kScrollbarUpArrow) {
- if (arrow.right_to_left) {
- upper_left_radius = kScrollRadius * zoom;
- } else {
- upper_right_radius = kScrollRadius * zoom;
- }
- } else if (direction == kScrollbarDownArrow) {
- if (arrow.right_to_left) {
- lower_left_radius = kScrollRadius * zoom;
- } else {
- lower_right_radius = kScrollRadius * zoom;
- }
- }
- DrawPartiallyRoundRect(canvas, rect, upper_left_radius, upper_right_radius,
- lower_right_radius, lower_left_radius, flags);
- PaintArrow(canvas, rect, direction, arrow_color);
- }
- void NativeThemeAura::PaintScrollbarTrack(
- cc::PaintCanvas* canvas,
- Part part,
- State state,
- const ScrollbarTrackExtraParams& extra_params,
- const gfx::Rect& rect,
- ColorScheme color_scheme) const {
- // Overlay Scrollbar should never paint a scrollbar track.
- DCHECK(!use_overlay_scrollbars_);
- cc::PaintFlags flags;
- SkColor track_color = GetControlColor(kScrollbarTrack, color_scheme);
- flags.setColor(track_color);
- canvas->drawIRect(gfx::RectToSkIRect(rect), flags);
- }
- void NativeThemeAura::PaintScrollbarThumb(cc::PaintCanvas* canvas,
- const ColorProvider* color_provider,
- Part part,
- State state,
- const gfx::Rect& rect,
- ScrollbarOverlayColorTheme theme,
- ColorScheme color_scheme) const {
- // Do not paint if state is disabled.
- if (state == kDisabled)
- return;
- TRACE_EVENT0("blink", "NativeThemeAura::PaintScrollbarThumb");
- gfx::Rect thumb_rect(rect);
- SkColor thumb_color;
- if (use_overlay_scrollbars_) {
- if (state == NativeTheme::kDisabled)
- return;
- const bool hovered = state != kNormal;
- static constexpr auto kFillIdMap =
- base::MakeFixedFlatMap<ScrollbarOverlayColorTheme, std::array<int, 2>>({
- {ScrollbarOverlayColorTheme::kDefault,
- {kColorOverlayScrollbarFill, kColorOverlayScrollbarFillHovered}},
- {ScrollbarOverlayColorTheme::kLight,
- {kColorOverlayScrollbarFillLight,
- kColorOverlayScrollbarFillHoveredLight}},
- {ScrollbarOverlayColorTheme::kDark,
- {kColorOverlayScrollbarFillDark,
- kColorOverlayScrollbarFillHoveredDark}},
- });
- static constexpr auto kStrokeIdMap =
- base::MakeFixedFlatMap<ScrollbarOverlayColorTheme, std::array<int, 2>>({
- {ScrollbarOverlayColorTheme::kDefault,
- {kColorOverlayScrollbarStroke,
- kColorOverlayScrollbarStrokeHovered}},
- {ScrollbarOverlayColorTheme::kLight,
- {kColorOverlayScrollbarStrokeLight,
- kColorOverlayScrollbarStrokeHoveredLight}},
- {ScrollbarOverlayColorTheme::kDark,
- {kColorOverlayScrollbarStrokeDark,
- kColorOverlayScrollbarStrokeHoveredDark}},
- });
- DCHECK(color_provider);
- thumb_color = color_provider->GetColor(kFillIdMap.at(theme)[hovered]);
- const SkColor stroke_color =
- color_provider->GetColor(kStrokeIdMap.at(theme)[hovered]);
- // In overlay mode, draw a stroke (border).
- constexpr int kStrokeWidth = kOverlayScrollbarStrokeWidth;
- cc::PaintFlags flags;
- flags.setColor(stroke_color);
- flags.setStyle(cc::PaintFlags::kStroke_Style);
- flags.setStrokeWidth(kStrokeWidth);
- gfx::RectF stroke_rect(thumb_rect);
- gfx::InsetsF stroke_insets(kStrokeWidth / 2.f);
- // The edge to which the scrollbar is attached shouldn't have a border.
- gfx::Insets edge_adjust_insets;
- if (part == NativeTheme::kScrollbarHorizontalThumb)
- edge_adjust_insets.set_bottom(-kStrokeWidth);
- else
- edge_adjust_insets.set_right(-kStrokeWidth);
- stroke_rect.Inset(stroke_insets + gfx::InsetsF(edge_adjust_insets));
- canvas->drawRect(gfx::RectFToSkRect(stroke_rect), flags);
- // Inset the all the edges edges so we fill-in the stroke below.
- // For left vertical scrollbar, we will horizontally flip the canvas in
- // ScrollbarThemeOverlay::paintThumb.
- gfx::Insets fill_insets(kStrokeWidth);
- thumb_rect.Inset(fill_insets + edge_adjust_insets);
- } else {
- ControlColorId color_id = kScrollbarThumb;
- SkAlpha thumb_alpha = SK_AlphaTRANSPARENT;
- switch (state) {
- case NativeTheme::kDisabled:
- break;
- case NativeTheme::kHovered:
- color_id = kScrollbarThumbHovered;
- thumb_alpha = 0x4D;
- break;
- case NativeTheme::kNormal:
- thumb_alpha = 0x33;
- break;
- case NativeTheme::kPressed:
- color_id = kScrollbarThumbPressed;
- thumb_alpha = 0x80;
- break;
- case NativeTheme::kNumStates:
- NOTREACHED();
- break;
- }
- // If there are no scrollbuttons then provide some padding so that the thumb
- // doesn't touch the top of the track.
- const int kThumbPadding = 2;
- const int extra_padding =
- (scrollbar_button_length() == 0) ? kThumbPadding : 0;
- if (part == NativeTheme::kScrollbarVerticalThumb)
- thumb_rect.Inset(gfx::Insets::VH(extra_padding, kThumbPadding));
- else
- thumb_rect.Inset(gfx::Insets::VH(kThumbPadding, extra_padding));
- thumb_color =
- (InForcedColorsMode() && features::IsForcedColorsEnabled())
- ? GetControlColor(color_id, color_scheme)
- : SkColorSetA(GetControlColor(kScrollbarThumb, color_scheme),
- thumb_alpha);
- }
- cc::PaintFlags flags;
- flags.setColor(thumb_color);
- canvas->drawIRect(gfx::RectToSkIRect(thumb_rect), flags);
- }
- void NativeThemeAura::PaintScrollbarCorner(cc::PaintCanvas* canvas,
- State state,
- const gfx::Rect& rect,
- ColorScheme color_scheme) const {
- // Overlay Scrollbar should never paint a scrollbar corner.
- DCHECK(!use_overlay_scrollbars_);
- cc::PaintFlags flags;
- SkColor bg_color = color_scheme == ui::NativeTheme::ColorScheme::kDark
- ? SkColorSetRGB(0x12, 0x12, 0x12)
- : SkColorSetRGB(0xDC, 0xDC, 0xDC);
- flags.setColor(bg_color);
- canvas->drawIRect(RectToSkIRect(rect), flags);
- }
- gfx::Size NativeThemeAura::GetPartSize(Part part,
- State state,
- const ExtraParams& extra) const {
- if (use_overlay_scrollbars_) {
- constexpr int minimum_length =
- kOverlayScrollbarMinimumLength + 2 * kOverlayScrollbarStrokeWidth;
- // Aura overlay scrollbars need a slight tweak from the base sizes.
- switch (part) {
- case kScrollbarHorizontalThumb:
- return gfx::Size(minimum_length, scrollbar_width_);
- case kScrollbarVerticalThumb:
- return gfx::Size(scrollbar_width_, minimum_length);
- default:
- // TODO(bokan): We should probably make sure code using overlay
- // scrollbars isn't asking for part sizes that don't exist.
- // crbug.com/657159.
- break;
- }
- }
- return NativeThemeBase::GetPartSize(part, state, extra);
- }
- void NativeThemeAura::DrawPartiallyRoundRect(cc::PaintCanvas* canvas,
- const gfx::Rect& rect,
- const SkScalar upper_left_radius,
- const SkScalar upper_right_radius,
- const SkScalar lower_right_radius,
- const SkScalar lower_left_radius,
- const cc::PaintFlags& flags) {
- gfx::RRectF rounded_rect(
- gfx::RectF(rect), upper_left_radius, upper_left_radius,
- upper_right_radius, upper_right_radius, lower_right_radius,
- lower_right_radius, lower_left_radius, lower_left_radius);
- canvas->drawRRect(static_cast<SkRRect>(rounded_rect), flags);
- }
- bool NativeThemeAura::SupportsNinePatch(Part part) const {
- if (!IsOverlayScrollbarEnabled())
- return false;
- return part == kScrollbarHorizontalThumb || part == kScrollbarVerticalThumb;
- }
- gfx::Size NativeThemeAura::GetNinePatchCanvasSize(Part part) const {
- DCHECK(SupportsNinePatch(part));
- return gfx::Size(
- kOverlayScrollbarBorderPatchWidth * 2 + kOverlayScrollbarCenterPatchSize,
- kOverlayScrollbarBorderPatchWidth * 2 + kOverlayScrollbarCenterPatchSize);
- }
- gfx::Rect NativeThemeAura::GetNinePatchAperture(Part part) const {
- DCHECK(SupportsNinePatch(part));
- return gfx::Rect(
- kOverlayScrollbarBorderPatchWidth, kOverlayScrollbarBorderPatchWidth,
- kOverlayScrollbarCenterPatchSize, kOverlayScrollbarCenterPatchSize);
- }
- } // namespace ui
|