blob: b6f47d402f4dc490dfe68bef799182ec07f9ac7e [file] [log] [blame]
// 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/logging.h"
#include "build/build_config.h"
#include "ui/base/layout.h"
#include "ui/base/material_design/material_design_controller.h"
#include "ui/gfx/animation/tween.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/path.h"
#include "ui/gfx/skia_util.h"
#include "ui/native_theme/common_theme.h"
#include "ui/native_theme/native_theme_switches.h"
namespace ui {
namespace {
SkAlpha ThumbAlphaForState(NativeTheme::State state) {
bool overlay = IsOverlayScrollbarEnabled();
switch (state) {
case NativeTheme::kDisabled:
return 0x00;
case NativeTheme::kHovered:
return overlay ? 0xB2 : 0x4D;
case NativeTheme::kNormal:
return overlay ? 0x8C : 0x33;
case NativeTheme::kPressed:
return overlay ? 0xB2 : 0x80;
case NativeTheme::kNumStates:
break;
}
NOTREACHED();
return 0xFF;
}
SkAlpha ThumbStrokeAlphaForState(NativeTheme::State state) {
DCHECK(IsOverlayScrollbarEnabled());
switch (state) {
case NativeTheme::kDisabled:
return 0x00;
case NativeTheme::kHovered:
case NativeTheme::kPressed:
return 0x33;
case NativeTheme::kNormal:
return 0x26;
case NativeTheme::kNumStates:
break;
}
NOTREACHED();
return 0xFF;
}
const SkColor kTrackColor = SkColorSetRGB(0xF1, 0xF1, 0xF1);
} // namespace
// static
NativeTheme* NativeTheme::GetInstanceForWeb() {
return NativeThemeAura::instance();
}
// static
NativeThemeAura* NativeThemeAura::instance() {
CR_DEFINE_STATIC_LOCAL(NativeThemeAura, s_native_theme, ());
return &s_native_theme;
}
NativeThemeAura::NativeThemeAura() {
// We don't draw scrollbar buttons.
#if defined(OS_CHROMEOS)
set_scrollbar_button_length(0);
#endif
// 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() {
}
// This implementation returns hardcoded colors.
SkColor NativeThemeAura::GetSystemColor(ColorId color_id) const {
return GetAuraColor(color_id, this);
}
void NativeThemeAura::PaintMenuPopupBackground(
SkCanvas* canvas,
const gfx::Size& size,
const MenuBackgroundExtraParams& menu_background) const {
SkColor color = GetSystemColor(NativeTheme::kColorId_MenuBackgroundColor);
if (menu_background.corner_radius > 0) {
SkPaint paint;
paint.setStyle(SkPaint::kFill_Style);
paint.setFlags(SkPaint::kAntiAlias_Flag);
paint.setColor(color);
gfx::Path 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, paint);
} else {
canvas->drawColor(color, SkXfermode::kSrc_Mode);
}
}
void NativeThemeAura::PaintMenuItemBackground(
SkCanvas* canvas,
State state,
const gfx::Rect& rect,
const MenuItemExtraParams& menu_item) const {
CommonThemePaintMenuItemBackground(this, canvas, state, rect, menu_item);
}
void NativeThemeAura::PaintArrowButton(SkCanvas* canvas,
const gfx::Rect& rect,
Part direction,
State state) const {
SkColor bg_color = kTrackColor;
// Aura-win uses slightly different arrow colors.
SkColor arrow_color = gfx::kPlaceholderColor;
switch (state) {
case kDisabled:
arrow_color = GetArrowColor(state);
break;
case kHovered:
bg_color = SkColorSetRGB(0xD2, 0xD2, 0xD2);
// Fall through.
case kNormal:
arrow_color = SkColorSetRGB(0x50, 0x50, 0x50);
break;
case kPressed:
bg_color = SkColorSetRGB(0x78, 0x78, 0x78);
arrow_color = SK_ColorWHITE;
break;
case kNumStates:
break;
}
DCHECK_NE(arrow_color, gfx::kPlaceholderColor);
SkPaint paint;
paint.setColor(bg_color);
canvas->drawIRect(gfx::RectToSkIRect(rect), paint);
PaintArrow(canvas, rect, direction, arrow_color);
}
void NativeThemeAura::PaintScrollbarTrack(
SkCanvas* canvas,
Part part,
State state,
const ScrollbarTrackExtraParams& extra_params,
const gfx::Rect& rect) const {
// Overlay Scrollbar should never paint a scrollbar track.
DCHECK(!IsOverlayScrollbarEnabled());
SkPaint paint;
paint.setColor(kTrackColor);
canvas->drawIRect(gfx::RectToSkIRect(rect), paint);
}
void NativeThemeAura::PaintScrollbarThumb(SkCanvas* canvas,
Part part,
State state,
const gfx::Rect& rect) const {
// Do not paint if state is disabled.
if (state == kDisabled)
return;
PaintScrollbarThumbStateTransition(canvas, part, state, state, 1.0, rect);
}
void NativeThemeAura::PaintScrollbarThumbStateTransition(
SkCanvas* canvas,
Part part,
State start_state,
State end_state,
double progress,
const gfx::Rect& rect) const {
gfx::Rect thumb_rect(rect);
if (IsOverlayScrollbarEnabled()) {
// In overlay mode, draw a stroke (border).
const int kStrokeWidth = 1;
SkAlpha stroke_alpha = gfx::Tween::IntValueBetween(
progress, ThumbStrokeAlphaForState(start_state),
ThumbStrokeAlphaForState(end_state));
SkPaint paint;
paint.setColor(SkColorSetA(SK_ColorWHITE, stroke_alpha));
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(kStrokeWidth);
canvas->drawIRect(gfx::RectToSkIRect(thumb_rect), paint);
thumb_rect.Inset(kStrokeWidth, kStrokeWidth, kStrokeWidth, kStrokeWidth);
} else {
// 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(kThumbPadding, extra_padding);
else
thumb_rect.Inset(extra_padding, kThumbPadding);
}
SkPaint paint;
SkAlpha alpha = gfx::Tween::IntValueBetween(
progress, ThumbAlphaForState(start_state), ThumbAlphaForState(end_state));
paint.setColor(SkColorSetA(SK_ColorBLACK, alpha));
canvas->drawIRect(gfx::RectToSkIRect(thumb_rect), paint);
}
void NativeThemeAura::PaintScrollbarCorner(SkCanvas* canvas,
State state,
const gfx::Rect& rect) const {
// Overlay Scrollbar should never paint a scrollbar corner.
DCHECK(!IsOverlayScrollbarEnabled());
SkPaint paint;
paint.setColor(SkColorSetRGB(0xDC, 0xDC, 0xDC));
canvas->drawIRect(RectToSkIRect(rect), paint);
}
} // namespace ui