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.
5 #include "ui/native_theme/native_theme_aura.h"
9 #include "base/logging.h"
10 #include "grit/ui_resources.h"
11 #include "ui/base/layout.h"
12 #include "ui/base/nine_image_painter_factory.h"
13 #include "ui/gfx/canvas.h"
14 #include "ui/gfx/image/image_skia.h"
15 #include "ui/gfx/nine_image_painter.h"
16 #include "ui/gfx/path.h"
17 #include "ui/gfx/rect.h"
18 #include "ui/gfx/size.h"
19 #include "ui/gfx/skbitmap_operations.h"
20 #include "ui/gfx/skia_util.h"
21 #include "ui/native_theme/common_theme.h"
22 #include "ui/native_theme/native_theme_switches.h"
24 using gfx::NineImagePainter
;
26 #define EMPTY_IMAGE_GRID { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
32 const int kScrollbarThumbImages
[NativeTheme::kMaxState
][9] = {
34 IMAGE_GRID(IDR_SCROLLBAR_THUMB_BASE_HOVER
),
35 IMAGE_GRID(IDR_SCROLLBAR_THUMB_BASE_NORMAL
),
36 IMAGE_GRID(IDR_SCROLLBAR_THUMB_BASE_PRESSED
)
39 const int kScrollbarArrowButtonImages
[NativeTheme::kMaxState
][9] = {
41 IMAGE_GRID(IDR_SCROLLBAR_ARROW_BUTTON_BASE_HOVER
),
42 IMAGE_GRID(IDR_SCROLLBAR_ARROW_BUTTON_BASE_NORMAL
),
43 IMAGE_GRID(IDR_SCROLLBAR_ARROW_BUTTON_BASE_PRESSED
)
46 const uint8 kScrollbarOverlayThumbFillAlphas
[NativeTheme::kMaxState
] = {
47 0, // Does not matter, will not paint for disabled state.
48 178, // Hover state, opacity 70%, alpha would be 0.7 * 255.
49 140, // Normal state, opacity 55%, alpha would be 0.55 * 255.
50 178 // Pressed state, opacity 70%, alpha would be 0.7 * 255.
53 const uint8 kScrollbarOverlayThumbStrokeAlphas
[NativeTheme::kMaxState
] = {
54 0, // Does not matter, will not paint for disabled state.
55 51, // Hover state, opacity 20%, alpha would be 0.2 * 255.
56 38, // Normal state, opacity 15%, alpha would be 0.15 * 255.
57 51 // Pressed state, opacity 20%, alpha would be 0.2 * 255.
60 const int kScrollbarOverlayThumbStrokeImages
[9] =
61 IMAGE_GRID_NO_CENTER(IDR_SCROLLBAR_OVERLAY_THUMB_STROKE
);
63 const int kScrollbarOverlayThumbFillImages
[9] =
64 IMAGE_GRID(IDR_SCROLLBAR_OVERLAY_THUMB_FILL
);
66 const int kScrollbarTrackImages
[9] = IMAGE_GRID(IDR_SCROLLBAR_BASE
);
72 NativeTheme
* NativeTheme::instance() {
73 return NativeThemeAura::instance();
77 NativeThemeAura
* NativeThemeAura::instance() {
78 CR_DEFINE_STATIC_LOCAL(NativeThemeAura
, s_native_theme
, ());
79 return &s_native_theme
;
83 NativeThemeAura::NativeThemeAura() {
84 // We don't draw scrollbar buttons.
85 #if defined(OS_CHROMEOS)
86 set_scrollbar_button_length(0);
89 // Images and alphas declarations assume the following order.
90 COMPILE_ASSERT(kDisabled
== 0, states_unexepctedly_changed
);
91 COMPILE_ASSERT(kHovered
== 1, states_unexepctedly_changed
);
92 COMPILE_ASSERT(kNormal
== 2, states_unexepctedly_changed
);
93 COMPILE_ASSERT(kPressed
== 3, states_unexepctedly_changed
);
94 COMPILE_ASSERT(kMaxState
== 4, states_unexepctedly_changed
);
97 NativeThemeAura::~NativeThemeAura() {
100 void NativeThemeAura::PaintMenuPopupBackground(
102 const gfx::Size
& size
,
103 const MenuBackgroundExtraParams
& menu_background
) const {
104 SkColor color
= GetSystemColor(NativeTheme::kColorId_MenuBackgroundColor
);
105 if (menu_background
.corner_radius
> 0) {
107 paint
.setStyle(SkPaint::kFill_Style
);
108 paint
.setFlags(SkPaint::kAntiAlias_Flag
);
109 paint
.setColor(color
);
112 SkRect rect
= SkRect::MakeWH(SkIntToScalar(size
.width()),
113 SkIntToScalar(size
.height()));
114 SkScalar radius
= SkIntToScalar(menu_background
.corner_radius
);
115 SkScalar radii
[8] = {radius
, radius
, radius
, radius
,
116 radius
, radius
, radius
, radius
};
117 path
.addRoundRect(rect
, radii
);
119 canvas
->drawPath(path
, paint
);
121 canvas
->drawColor(color
, SkXfermode::kSrc_Mode
);
125 void NativeThemeAura::PaintMenuItemBackground(
128 const gfx::Rect
& rect
,
129 const MenuListExtraParams
& menu_list
) const {
130 CommonThemePaintMenuItemBackground(canvas
, state
, rect
);
133 void NativeThemeAura::PaintArrowButton(
135 const gfx::Rect
& rect
,
138 if (direction
== kInnerSpinButton
) {
139 FallbackTheme::PaintArrowButton(gc
, rect
, direction
, state
);
142 PaintPainter(GetOrCreatePainter(
143 kScrollbarArrowButtonImages
, state
,
144 scrollbar_arrow_button_painters_
),
147 // Aura-win uses slightly different arrow colors.
148 SkColor arrow_color
= GetArrowColor(state
);
152 arrow_color
= SkColorSetRGB(0x50, 0x50, 0x50);
155 arrow_color
= SK_ColorWHITE
;
159 PaintArrow(gc
, rect
, direction
, arrow_color
);
162 void NativeThemeAura::PaintScrollbarTrack(
166 const ScrollbarTrackExtraParams
& extra_params
,
167 const gfx::Rect
& rect
) const {
168 // Overlay Scrollbar should never paint a scrollbar track.
169 DCHECK(!IsOverlayScrollbarEnabled());
170 if (!scrollbar_track_painter_
)
171 scrollbar_track_painter_
= CreateNineImagePainter(kScrollbarTrackImages
);
172 PaintPainter(scrollbar_track_painter_
.get(), sk_canvas
, rect
);
175 void NativeThemeAura::PaintScrollbarThumb(SkCanvas
* sk_canvas
,
178 const gfx::Rect
& rect
) const {
179 gfx::Rect
thumb_rect(rect
);
180 if (IsOverlayScrollbarEnabled()) {
181 // Overlay scrollbar has no track, just paint thumb directly.
182 // Do not paint if state is disabled.
183 if (state
== kDisabled
)
186 if (!scrollbar_overlay_thumb_painter_
) {
187 scrollbar_overlay_thumb_painter_
=
188 CreateDualPainter(kScrollbarOverlayThumbFillImages
,
189 kScrollbarOverlayThumbFillAlphas
,
190 kScrollbarOverlayThumbStrokeImages
,
191 kScrollbarOverlayThumbStrokeAlphas
);
195 scrollbar_overlay_thumb_painter_
.get(), sk_canvas
, thumb_rect
, state
);
198 // If there are no scrollbuttons then provide some padding so that thumb
199 // doesn't touch the top of the track.
200 const int extra_padding
= (scrollbar_button_length() == 0) ? 2 : 0;
201 if (part
== NativeTheme::kScrollbarVerticalThumb
)
202 thumb_rect
.Inset(2, extra_padding
, 2, extra_padding
);
204 thumb_rect
.Inset(extra_padding
, 2, extra_padding
, 2);
205 PaintPainter(GetOrCreatePainter(
206 kScrollbarThumbImages
, state
, scrollbar_thumb_painters_
),
211 void NativeThemeAura::PaintScrollbarThumbStateTransition(
216 const gfx::Rect
& rect
) const {
217 // Only Overlay scrollbars should have state transition animation.
218 DCHECK(IsOverlayScrollbarEnabled());
219 if (!scrollbar_overlay_thumb_painter_
) {
220 scrollbar_overlay_thumb_painter_
=
221 CreateDualPainter(kScrollbarOverlayThumbFillImages
,
222 kScrollbarOverlayThumbFillAlphas
,
223 kScrollbarOverlayThumbStrokeImages
,
224 kScrollbarOverlayThumbStrokeAlphas
);
227 PaintDualPainterTransition(scrollbar_overlay_thumb_painter_
.get(),
235 void NativeThemeAura::PaintScrollbarCorner(SkCanvas
* canvas
,
237 const gfx::Rect
& rect
) const {
238 // Overlay Scrollbar should never paint a scrollbar corner.
239 DCHECK(!IsOverlayScrollbarEnabled());
241 paint
.setColor(SkColorSetRGB(0xF1, 0xF1, 0xF1));
242 paint
.setStyle(SkPaint::kFill_Style
);
243 paint
.setXfermodeMode(SkXfermode::kSrc_Mode
);
244 canvas
->drawIRect(RectToSkIRect(rect
), paint
);
247 NineImagePainter
* NativeThemeAura::GetOrCreatePainter(
248 const int images
[kMaxState
][9],
250 scoped_ptr
<NineImagePainter
> painters
[kMaxState
]) const {
252 return painters
[state
].get();
253 if (images
[state
][0] == 0) {
254 // Must always provide normal state images.
255 DCHECK_NE(kNormal
, state
);
256 return GetOrCreatePainter(images
, kNormal
, painters
);
258 painters
[state
] = CreateNineImagePainter(images
[state
]);
259 return painters
[state
].get();
262 void NativeThemeAura::PaintPainter(NineImagePainter
* painter
,
264 const gfx::Rect
& rect
) const {
266 scoped_ptr
<gfx::Canvas
> canvas(CommonThemeCreateCanvas(sk_canvas
));
267 painter
->Paint(canvas
.get(), rect
);
270 scoped_ptr
<NativeThemeAura::DualPainter
> NativeThemeAura::CreateDualPainter(
271 const int fill_image_ids
[9],
272 const uint8 fill_alphas
[kMaxState
],
273 const int stroke_image_ids
[9],
274 const uint8 stroke_alphas
[kMaxState
]) const {
275 scoped_ptr
<NativeThemeAura::DualPainter
> dual_painter(
276 new NativeThemeAura::DualPainter(CreateNineImagePainter(fill_image_ids
),
278 CreateNineImagePainter(stroke_image_ids
),
280 return dual_painter
.Pass();
283 void NativeThemeAura::PaintDualPainter(
284 NativeThemeAura::DualPainter
* dual_painter
,
286 const gfx::Rect
& rect
,
288 DCHECK(dual_painter
);
289 scoped_ptr
<gfx::Canvas
> canvas(CommonThemeCreateCanvas(sk_canvas
));
290 dual_painter
->fill_painter
->Paint(
291 canvas
.get(), rect
, dual_painter
->fill_alphas
[state
]);
292 dual_painter
->stroke_painter
->Paint(
293 canvas
.get(), rect
, dual_painter
->stroke_alphas
[state
]);
296 void NativeThemeAura::PaintDualPainterTransition(
297 NativeThemeAura::DualPainter
* dual_painter
,
299 const gfx::Rect
& rect
,
302 double progress
) const {
303 DCHECK(dual_painter
);
304 scoped_ptr
<gfx::Canvas
> canvas(CommonThemeCreateCanvas(sk_canvas
));
305 uint8 fill_alpha
= dual_painter
->fill_alphas
[startState
] +
306 (dual_painter
->fill_alphas
[endState
] -
307 dual_painter
->fill_alphas
[startState
]) *
309 uint8 stroke_alpha
= dual_painter
->stroke_alphas
[startState
] +
310 (dual_painter
->stroke_alphas
[endState
] -
311 dual_painter
->stroke_alphas
[startState
]) *
314 dual_painter
->fill_painter
->Paint(canvas
.get(), rect
, fill_alpha
);
315 dual_painter
->stroke_painter
->Paint(canvas
.get(), rect
, stroke_alpha
);
318 NativeThemeAura::DualPainter::DualPainter(
319 scoped_ptr
<NineImagePainter
> fill_painter
,
320 const uint8 fill_alphas
[kMaxState
],
321 scoped_ptr
<NineImagePainter
> stroke_painter
,
322 const uint8 stroke_alphas
[kMaxState
])
323 : fill_painter(fill_painter
.Pass()),
324 fill_alphas(fill_alphas
),
325 stroke_painter(stroke_painter
.Pass()),
326 stroke_alphas(stroke_alphas
) {}
328 NativeThemeAura::DualPainter::~DualPainter() {}