Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / ui / native_theme / native_theme_aura.cc
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 #include "ui/native_theme/native_theme_aura.h"
6
7 #include <limits>
8
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"
23
24 using gfx::NineImagePainter;
25
26 #define EMPTY_IMAGE_GRID { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
27
28 namespace ui {
29
30 namespace {
31
32 const int kScrollbarThumbImages[NativeTheme::kNumStates][9] = {
33   EMPTY_IMAGE_GRID,
34   IMAGE_GRID(IDR_SCROLLBAR_THUMB_BASE_HOVER),
35   IMAGE_GRID(IDR_SCROLLBAR_THUMB_BASE_NORMAL),
36   IMAGE_GRID(IDR_SCROLLBAR_THUMB_BASE_PRESSED)
37 };
38
39 const int kScrollbarArrowButtonImages[NativeTheme::kNumStates][9] = {
40   EMPTY_IMAGE_GRID,
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)
44 };
45
46 const uint8 kScrollbarOverlayThumbFillAlphas[NativeTheme::kNumStates] = {
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.
51 };
52
53 const uint8 kScrollbarOverlayThumbStrokeAlphas[NativeTheme::kNumStates] = {
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.
58 };
59
60 const int kScrollbarOverlayThumbStrokeImages[9] =
61     IMAGE_GRID_NO_CENTER(IDR_SCROLLBAR_OVERLAY_THUMB_STROKE);
62
63 const int kScrollbarOverlayThumbFillImages[9] =
64     IMAGE_GRID(IDR_SCROLLBAR_OVERLAY_THUMB_FILL);
65
66 const int kScrollbarTrackImages[9] = IMAGE_GRID(IDR_SCROLLBAR_BASE);
67
68 }  // namespace
69
70 #if !defined(OS_WIN)
71 // static
72 NativeTheme* NativeTheme::instance() {
73   return NativeThemeAura::instance();
74 }
75
76 // static
77 NativeThemeAura* NativeThemeAura::instance() {
78   CR_DEFINE_STATIC_LOCAL(NativeThemeAura, s_native_theme, ());
79   return &s_native_theme;
80 }
81 #endif
82
83 NativeThemeAura::NativeThemeAura() {
84   // We don't draw scrollbar buttons.
85 #if defined(OS_CHROMEOS)
86   set_scrollbar_button_length(0);
87 #endif
88
89   // Images and alphas declarations assume the following order.
90   COMPILE_ASSERT(kDisabled == 0, states_unexpectedly_changed);
91   COMPILE_ASSERT(kHovered == 1, states_unexpectedly_changed);
92   COMPILE_ASSERT(kNormal == 2, states_unexpectedly_changed);
93   COMPILE_ASSERT(kPressed == 3, states_unexpectedly_changed);
94 }
95
96 NativeThemeAura::~NativeThemeAura() {
97 }
98
99 void NativeThemeAura::PaintMenuPopupBackground(
100     SkCanvas* canvas,
101     const gfx::Size& size,
102     const MenuBackgroundExtraParams& menu_background) const {
103   SkColor color = GetSystemColor(NativeTheme::kColorId_MenuBackgroundColor);
104   if (menu_background.corner_radius > 0) {
105     SkPaint paint;
106     paint.setStyle(SkPaint::kFill_Style);
107     paint.setFlags(SkPaint::kAntiAlias_Flag);
108     paint.setColor(color);
109
110     gfx::Path path;
111     SkRect rect = SkRect::MakeWH(SkIntToScalar(size.width()),
112                                  SkIntToScalar(size.height()));
113     SkScalar radius = SkIntToScalar(menu_background.corner_radius);
114     SkScalar radii[8] = {radius, radius, radius, radius,
115                          radius, radius, radius, radius};
116     path.addRoundRect(rect, radii);
117
118     canvas->drawPath(path, paint);
119   } else {
120     canvas->drawColor(color, SkXfermode::kSrc_Mode);
121   }
122 }
123
124 void NativeThemeAura::PaintMenuItemBackground(
125     SkCanvas* canvas,
126     State state,
127     const gfx::Rect& rect,
128     const MenuListExtraParams& menu_list) const {
129   CommonThemePaintMenuItemBackground(canvas, state, rect);
130 }
131
132 void NativeThemeAura::PaintArrowButton(
133       SkCanvas* gc,
134       const gfx::Rect& rect,
135       Part direction,
136       State state) const {
137   if (direction == kInnerSpinButton) {
138     FallbackTheme::PaintArrowButton(gc, rect, direction, state);
139     return;
140   }
141   PaintPainter(GetOrCreatePainter(
142                    kScrollbarArrowButtonImages, state,
143                    scrollbar_arrow_button_painters_),
144                gc, rect);
145
146   // Aura-win uses slightly different arrow colors.
147   SkColor arrow_color = GetArrowColor(state);
148   switch (state) {
149     case kHovered:
150     case kNormal:
151       arrow_color = SkColorSetRGB(0x50, 0x50, 0x50);
152       break;
153     case kPressed:
154       arrow_color = SK_ColorWHITE;
155     default:
156       break;
157   }
158   PaintArrow(gc, rect, direction, arrow_color);
159 }
160
161 void NativeThemeAura::PaintScrollbarTrack(
162     SkCanvas* sk_canvas,
163     Part part,
164     State state,
165     const ScrollbarTrackExtraParams& extra_params,
166     const gfx::Rect& rect) const {
167   // Overlay Scrollbar should never paint a scrollbar track.
168   DCHECK(!IsOverlayScrollbarEnabled());
169   if (!scrollbar_track_painter_)
170     scrollbar_track_painter_ = CreateNineImagePainter(kScrollbarTrackImages);
171   PaintPainter(scrollbar_track_painter_.get(), sk_canvas, rect);
172 }
173
174 void NativeThemeAura::PaintScrollbarThumb(SkCanvas* sk_canvas,
175                                           Part part,
176                                           State state,
177                                           const gfx::Rect& rect) const {
178   gfx::Rect thumb_rect(rect);
179   if (IsOverlayScrollbarEnabled()) {
180     // Overlay scrollbar has no track, just paint thumb directly.
181     // Do not paint if state is disabled.
182     if (state == kDisabled)
183       return;
184
185     if (!scrollbar_overlay_thumb_painter_) {
186       scrollbar_overlay_thumb_painter_ =
187           CreateDualPainter(kScrollbarOverlayThumbFillImages,
188                             kScrollbarOverlayThumbFillAlphas,
189                             kScrollbarOverlayThumbStrokeImages,
190                             kScrollbarOverlayThumbStrokeAlphas);
191     }
192
193     PaintDualPainter(
194         scrollbar_overlay_thumb_painter_.get(), sk_canvas, thumb_rect, state);
195     return;
196   }
197   // If there are no scrollbuttons then provide some padding so that thumb
198   // doesn't touch the top of the track.
199   const int extra_padding = (scrollbar_button_length() == 0) ? 2 : 0;
200   if (part == NativeTheme::kScrollbarVerticalThumb)
201     thumb_rect.Inset(2, extra_padding, 2, extra_padding);
202   else
203     thumb_rect.Inset(extra_padding, 2, extra_padding, 2);
204   PaintPainter(GetOrCreatePainter(
205                    kScrollbarThumbImages, state, scrollbar_thumb_painters_),
206                sk_canvas,
207                thumb_rect);
208 }
209
210 void NativeThemeAura::PaintScrollbarThumbStateTransition(
211     SkCanvas* canvas,
212     State startState,
213     State endState,
214     double progress,
215     const gfx::Rect& rect) const {
216   // Only Overlay scrollbars should have state transition animation.
217   DCHECK(IsOverlayScrollbarEnabled());
218   if (!scrollbar_overlay_thumb_painter_) {
219     scrollbar_overlay_thumb_painter_ =
220         CreateDualPainter(kScrollbarOverlayThumbFillImages,
221                           kScrollbarOverlayThumbFillAlphas,
222                           kScrollbarOverlayThumbStrokeImages,
223                           kScrollbarOverlayThumbStrokeAlphas);
224   }
225
226   PaintDualPainterTransition(scrollbar_overlay_thumb_painter_.get(),
227                              canvas,
228                              rect,
229                              startState,
230                              endState,
231                              progress);
232 }
233
234 void NativeThemeAura::PaintScrollbarCorner(SkCanvas* canvas,
235                                            State state,
236                                            const gfx::Rect& rect) const {
237   // Overlay Scrollbar should never paint a scrollbar corner.
238   DCHECK(!IsOverlayScrollbarEnabled());
239   SkPaint paint;
240   paint.setColor(SkColorSetRGB(0xF1, 0xF1, 0xF1));
241   paint.setStyle(SkPaint::kFill_Style);
242   paint.setXfermodeMode(SkXfermode::kSrc_Mode);
243   canvas->drawIRect(RectToSkIRect(rect), paint);
244 }
245
246 NineImagePainter* NativeThemeAura::GetOrCreatePainter(
247     const int images[kNumStates][9],
248     State state,
249     scoped_ptr<NineImagePainter> painters[kNumStates]) const {
250   if (painters[state])
251     return painters[state].get();
252   if (images[state][0] == 0) {
253     // Must always provide normal state images.
254     DCHECK_NE(kNormal, state);
255     return GetOrCreatePainter(images, kNormal, painters);
256   }
257   painters[state] = CreateNineImagePainter(images[state]);
258   return painters[state].get();
259 }
260
261 void NativeThemeAura::PaintPainter(NineImagePainter* painter,
262                                    SkCanvas* sk_canvas,
263                                    const gfx::Rect& rect) const {
264   DCHECK(painter);
265   scoped_ptr<gfx::Canvas> canvas(CommonThemeCreateCanvas(sk_canvas));
266   painter->Paint(canvas.get(), rect);
267 }
268
269 scoped_ptr<NativeThemeAura::DualPainter> NativeThemeAura::CreateDualPainter(
270     const int fill_image_ids[9],
271     const uint8 fill_alphas[kNumStates],
272     const int stroke_image_ids[9],
273     const uint8 stroke_alphas[kNumStates]) const {
274   scoped_ptr<NativeThemeAura::DualPainter> dual_painter(
275       new NativeThemeAura::DualPainter(CreateNineImagePainter(fill_image_ids),
276                                        fill_alphas,
277                                        CreateNineImagePainter(stroke_image_ids),
278                                        stroke_alphas));
279   return dual_painter.Pass();
280 }
281
282 void NativeThemeAura::PaintDualPainter(
283     NativeThemeAura::DualPainter* dual_painter,
284     SkCanvas* sk_canvas,
285     const gfx::Rect& rect,
286     State state) const {
287   DCHECK(dual_painter);
288   scoped_ptr<gfx::Canvas> canvas(CommonThemeCreateCanvas(sk_canvas));
289   dual_painter->fill_painter->Paint(
290       canvas.get(), rect, dual_painter->fill_alphas[state]);
291   dual_painter->stroke_painter->Paint(
292       canvas.get(), rect, dual_painter->stroke_alphas[state]);
293 }
294
295 void NativeThemeAura::PaintDualPainterTransition(
296     NativeThemeAura::DualPainter* dual_painter,
297     SkCanvas* sk_canvas,
298     const gfx::Rect& rect,
299     State startState,
300     State endState,
301     double progress) const {
302   DCHECK(dual_painter);
303   scoped_ptr<gfx::Canvas> canvas(CommonThemeCreateCanvas(sk_canvas));
304   uint8 fill_alpha = dual_painter->fill_alphas[startState] +
305                      (dual_painter->fill_alphas[endState] -
306                       dual_painter->fill_alphas[startState]) *
307                          progress;
308   uint8 stroke_alpha = dual_painter->stroke_alphas[startState] +
309                        (dual_painter->stroke_alphas[endState] -
310                         dual_painter->stroke_alphas[startState]) *
311                            progress;
312
313   dual_painter->fill_painter->Paint(canvas.get(), rect, fill_alpha);
314   dual_painter->stroke_painter->Paint(canvas.get(), rect, stroke_alpha);
315 }
316
317 NativeThemeAura::DualPainter::DualPainter(
318     scoped_ptr<NineImagePainter> fill_painter,
319     const uint8 fill_alphas[kNumStates],
320     scoped_ptr<NineImagePainter> stroke_painter,
321     const uint8 stroke_alphas[kNumStates])
322     : fill_painter(fill_painter.Pass()),
323       fill_alphas(fill_alphas),
324       stroke_painter(stroke_painter.Pass()),
325       stroke_alphas(stroke_alphas) {}
326
327 NativeThemeAura::DualPainter::~DualPainter() {}
328
329 }  // namespace ui