• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::kMaxState][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::kMaxState][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::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.
51 };
52 
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.
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
instance()72 NativeTheme* NativeTheme::instance() {
73   return NativeThemeAura::instance();
74 }
75 
76 // static
instance()77 NativeThemeAura* NativeThemeAura::instance() {
78   CR_DEFINE_STATIC_LOCAL(NativeThemeAura, s_native_theme, ());
79   return &s_native_theme;
80 }
81 #endif
82 
NativeThemeAura()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_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);
95 }
96 
~NativeThemeAura()97 NativeThemeAura::~NativeThemeAura() {
98 }
99 
PaintMenuPopupBackground(SkCanvas * canvas,const gfx::Size & size,const MenuBackgroundExtraParams & menu_background) const100 void NativeThemeAura::PaintMenuPopupBackground(
101     SkCanvas* canvas,
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) {
106     SkPaint paint;
107     paint.setStyle(SkPaint::kFill_Style);
108     paint.setFlags(SkPaint::kAntiAlias_Flag);
109     paint.setColor(color);
110 
111     gfx::Path path;
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);
118 
119     canvas->drawPath(path, paint);
120   } else {
121     canvas->drawColor(color, SkXfermode::kSrc_Mode);
122   }
123 }
124 
PaintMenuItemBackground(SkCanvas * canvas,State state,const gfx::Rect & rect,const MenuListExtraParams & menu_list) const125 void NativeThemeAura::PaintMenuItemBackground(
126     SkCanvas* canvas,
127     State state,
128     const gfx::Rect& rect,
129     const MenuListExtraParams& menu_list) const {
130   CommonThemePaintMenuItemBackground(canvas, state, rect);
131 }
132 
PaintArrowButton(SkCanvas * gc,const gfx::Rect & rect,Part direction,State state) const133 void NativeThemeAura::PaintArrowButton(
134       SkCanvas* gc,
135       const gfx::Rect& rect,
136       Part direction,
137       State state) const {
138   if (direction == kInnerSpinButton) {
139     FallbackTheme::PaintArrowButton(gc, rect, direction, state);
140     return;
141   }
142   PaintPainter(GetOrCreatePainter(
143                    kScrollbarArrowButtonImages, state,
144                    scrollbar_arrow_button_painters_),
145                gc, rect);
146 
147   // Aura-win uses slightly different arrow colors.
148   SkColor arrow_color = GetArrowColor(state);
149   switch (state) {
150     case kHovered:
151     case kNormal:
152       arrow_color = SkColorSetRGB(0x50, 0x50, 0x50);
153       break;
154     case kPressed:
155       arrow_color = SK_ColorWHITE;
156     default:
157       break;
158   }
159   PaintArrow(gc, rect, direction, arrow_color);
160 }
161 
PaintScrollbarTrack(SkCanvas * sk_canvas,Part part,State state,const ScrollbarTrackExtraParams & extra_params,const gfx::Rect & rect) const162 void NativeThemeAura::PaintScrollbarTrack(
163     SkCanvas* sk_canvas,
164     Part part,
165     State state,
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);
173 }
174 
PaintScrollbarThumb(SkCanvas * sk_canvas,Part part,State state,const gfx::Rect & rect) const175 void NativeThemeAura::PaintScrollbarThumb(SkCanvas* sk_canvas,
176                                           Part part,
177                                           State state,
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)
184       return;
185 
186     if (!scrollbar_overlay_thumb_painter_) {
187       scrollbar_overlay_thumb_painter_ =
188           CreateDualPainter(kScrollbarOverlayThumbFillImages,
189                             kScrollbarOverlayThumbFillAlphas,
190                             kScrollbarOverlayThumbStrokeImages,
191                             kScrollbarOverlayThumbStrokeAlphas);
192     }
193 
194     PaintDualPainter(
195         scrollbar_overlay_thumb_painter_.get(), sk_canvas, thumb_rect, state);
196     return;
197   }
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);
203   else
204     thumb_rect.Inset(extra_padding, 2, extra_padding, 2);
205   PaintPainter(GetOrCreatePainter(
206                    kScrollbarThumbImages, state, scrollbar_thumb_painters_),
207                sk_canvas,
208                thumb_rect);
209 }
210 
PaintScrollbarThumbStateTransition(SkCanvas * canvas,State startState,State endState,double progress,const gfx::Rect & rect) const211 void NativeThemeAura::PaintScrollbarThumbStateTransition(
212     SkCanvas* canvas,
213     State startState,
214     State endState,
215     double progress,
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);
225   }
226 
227   PaintDualPainterTransition(scrollbar_overlay_thumb_painter_.get(),
228                              canvas,
229                              rect,
230                              startState,
231                              endState,
232                              progress);
233 }
234 
PaintScrollbarCorner(SkCanvas * canvas,State state,const gfx::Rect & rect) const235 void NativeThemeAura::PaintScrollbarCorner(SkCanvas* canvas,
236                                            State state,
237                                            const gfx::Rect& rect) const {
238   // Overlay Scrollbar should never paint a scrollbar corner.
239   DCHECK(!IsOverlayScrollbarEnabled());
240   SkPaint paint;
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);
245 }
246 
GetOrCreatePainter(const int images[kMaxState][9],State state,scoped_ptr<NineImagePainter> painters[kMaxState]) const247 NineImagePainter* NativeThemeAura::GetOrCreatePainter(
248     const int images[kMaxState][9],
249     State state,
250     scoped_ptr<NineImagePainter> painters[kMaxState]) const {
251   if (painters[state])
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);
257   }
258   painters[state] = CreateNineImagePainter(images[state]);
259   return painters[state].get();
260 }
261 
PaintPainter(NineImagePainter * painter,SkCanvas * sk_canvas,const gfx::Rect & rect) const262 void NativeThemeAura::PaintPainter(NineImagePainter* painter,
263                                    SkCanvas* sk_canvas,
264                                    const gfx::Rect& rect) const {
265   DCHECK(painter);
266   scoped_ptr<gfx::Canvas> canvas(CommonThemeCreateCanvas(sk_canvas));
267   painter->Paint(canvas.get(), rect);
268 }
269 
CreateDualPainter(const int fill_image_ids[9],const uint8 fill_alphas[kMaxState],const int stroke_image_ids[9],const uint8 stroke_alphas[kMaxState]) const270 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),
277                                        fill_alphas,
278                                        CreateNineImagePainter(stroke_image_ids),
279                                        stroke_alphas));
280   return dual_painter.Pass();
281 }
282 
PaintDualPainter(NativeThemeAura::DualPainter * dual_painter,SkCanvas * sk_canvas,const gfx::Rect & rect,State state) const283 void NativeThemeAura::PaintDualPainter(
284     NativeThemeAura::DualPainter* dual_painter,
285     SkCanvas* sk_canvas,
286     const gfx::Rect& rect,
287     State state) const {
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]);
294 }
295 
PaintDualPainterTransition(NativeThemeAura::DualPainter * dual_painter,SkCanvas * sk_canvas,const gfx::Rect & rect,State startState,State endState,double progress) const296 void NativeThemeAura::PaintDualPainterTransition(
297     NativeThemeAura::DualPainter* dual_painter,
298     SkCanvas* sk_canvas,
299     const gfx::Rect& rect,
300     State startState,
301     State endState,
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]) *
308                          progress;
309   uint8 stroke_alpha = dual_painter->stroke_alphas[startState] +
310                        (dual_painter->stroke_alphas[endState] -
311                         dual_painter->stroke_alphas[startState]) *
312                            progress;
313 
314   dual_painter->fill_painter->Paint(canvas.get(), rect, fill_alpha);
315   dual_painter->stroke_painter->Paint(canvas.get(), rect, stroke_alpha);
316 }
317 
DualPainter(scoped_ptr<NineImagePainter> fill_painter,const uint8 fill_alphas[kMaxState],scoped_ptr<NineImagePainter> stroke_painter,const uint8 stroke_alphas[kMaxState])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) {}
327 
~DualPainter()328 NativeThemeAura::DualPainter::~DualPainter() {}
329 
330 }  // namespace ui
331