1// Copyright (c) 2011 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 "webkit/glue/webthemeengine_impl_win.h"
6
7#include <vsstyle.h>  // To convert to gfx::NativeTheme::State
8
9#include "base/logging.h"
10#include "skia/ext/platform_canvas.h"
11#include "skia/ext/skia_utils_win.h"
12#include "third_party/WebKit/Source/WebKit/chromium/public/WebRect.h"
13#include "ui/gfx/native_theme_win.h"
14
15using WebKit::WebCanvas;
16using WebKit::WebColor;
17using WebKit::WebRect;
18
19namespace webkit_glue {
20
21static RECT WebRectToRECT(const WebRect& rect) {
22  RECT result;
23  result.left = rect.x;
24  result.top = rect.y;
25  result.right = rect.x + rect.width;
26  result.bottom = rect.y + rect.height;
27  return result;
28}
29
30static gfx::NativeTheme::State WebButtonStateToGfx(
31    int part,
32    int state,
33    gfx::NativeTheme::ButtonExtraParams* extra) {
34  gfx::NativeTheme::State gfx_state = gfx::NativeTheme::kNormal;
35
36  if (part == BP_PUSHBUTTON) {
37    switch(state) {
38      case PBS_NORMAL:
39        gfx_state = gfx::NativeTheme::kNormal;
40        extra->checked = false;
41        extra->indeterminate = false;
42        extra->is_default = false;
43        break;
44      case PBS_HOT:
45        gfx_state = gfx::NativeTheme::kHovered;
46        extra->checked = false;
47        extra->indeterminate = false;
48        extra->is_default = false;
49        break;
50      case PBS_PRESSED:
51        gfx_state = gfx::NativeTheme::kPressed;
52        extra->checked = false;
53        extra->indeterminate = false;
54        extra->is_default = false;
55        break;
56      case PBS_DISABLED:
57        gfx_state = gfx::NativeTheme::kDisabled;
58        extra->checked = false;
59        extra->indeterminate = false;
60        extra->is_default = false;
61        break;
62      case PBS_DEFAULTED:
63        gfx_state = gfx::NativeTheme::kNormal;
64        extra->checked = false;
65        extra->indeterminate = false;
66        extra->is_default = true;
67        break;
68      case PBS_DEFAULTED_ANIMATING:
69        gfx_state = gfx::NativeTheme::kNormal;
70        extra->checked = false;
71        extra->indeterminate = false;
72        extra->is_default = true;
73        break;
74      default:
75        NOTREACHED() << "Invalid state: " << state;
76    }
77  } else if (part == BP_RADIOBUTTON) {
78    switch(state) {
79      case RBS_UNCHECKEDNORMAL:
80        gfx_state = gfx::NativeTheme::kNormal;
81        extra->checked = false;
82        extra->indeterminate = false;
83        extra->is_default = false;
84        break;
85      case RBS_UNCHECKEDHOT:
86        gfx_state = gfx::NativeTheme::kHovered;
87        extra->checked = false;
88        extra->indeterminate = false;
89        extra->is_default = false;
90        break;
91      case RBS_UNCHECKEDPRESSED:
92        gfx_state = gfx::NativeTheme::kPressed;
93        extra->checked = false;
94        extra->indeterminate = false;
95        extra->is_default = false;
96        break;
97      case RBS_UNCHECKEDDISABLED:
98        gfx_state = gfx::NativeTheme::kDisabled;
99        extra->checked = false;
100        extra->indeterminate = false;
101        extra->is_default = false;
102        break;
103      case RBS_CHECKEDNORMAL:
104        gfx_state = gfx::NativeTheme::kNormal;
105        extra->checked = true;
106        extra->indeterminate = false;
107        extra->is_default = false;
108        break;
109      case RBS_CHECKEDHOT:
110        gfx_state = gfx::NativeTheme::kHovered;
111        extra->checked = true;
112        extra->indeterminate = false;
113        extra->is_default = false;
114        break;
115      case RBS_CHECKEDPRESSED:
116        gfx_state = gfx::NativeTheme::kPressed;
117        extra->checked = true;
118        extra->indeterminate = false;
119        extra->is_default = false;
120        break;
121      case RBS_CHECKEDDISABLED:
122        gfx_state = gfx::NativeTheme::kDisabled;
123        extra->checked = true;
124        extra->indeterminate = false;
125        extra->is_default = false;
126        break;
127      default:
128        NOTREACHED() << "Invalid state: " << state;
129        break;
130    }
131  } else if (part == BP_CHECKBOX) {
132    switch(state) {
133      case CBS_UNCHECKEDNORMAL:
134        gfx_state = gfx::NativeTheme::kNormal;
135        extra->checked = false;
136        extra->indeterminate = false;
137        extra->is_default = false;
138        break;
139      case CBS_UNCHECKEDHOT:
140        gfx_state = gfx::NativeTheme::kHovered;
141        extra->checked = false;
142        extra->indeterminate = false;
143        extra->is_default = false;
144        break;
145      case CBS_UNCHECKEDPRESSED:
146        gfx_state = gfx::NativeTheme::kPressed;
147        extra->checked = false;
148        extra->indeterminate = false;
149        extra->is_default = false;
150        break;
151      case CBS_UNCHECKEDDISABLED:
152        gfx_state = gfx::NativeTheme::kDisabled;
153        extra->checked = false;
154        extra->indeterminate = false;
155        extra->is_default = false;
156        break;
157      case CBS_CHECKEDNORMAL:
158        gfx_state = gfx::NativeTheme::kNormal;
159        extra->checked = true;
160        extra->indeterminate = false;
161        extra->is_default = false;
162        break;
163      case CBS_CHECKEDHOT:
164        gfx_state = gfx::NativeTheme::kHovered;
165        extra->checked = true;
166        extra->indeterminate = false;
167        extra->is_default = false;
168        break;
169      case CBS_CHECKEDPRESSED:
170        gfx_state = gfx::NativeTheme::kPressed;
171        extra->checked = true;
172        extra->indeterminate = false;
173        extra->is_default = false;
174        break;
175      case CBS_CHECKEDDISABLED:
176        gfx_state = gfx::NativeTheme::kDisabled;
177        extra->checked = true;
178        extra->indeterminate = false;
179        extra->is_default = false;
180        break;
181      case CBS_MIXEDNORMAL:
182        gfx_state = gfx::NativeTheme::kNormal;
183        extra->checked = false;
184        extra->indeterminate = true;
185        extra->is_default = false;
186        break;
187      case CBS_MIXEDHOT:
188        gfx_state = gfx::NativeTheme::kHovered;
189        extra->checked = false;
190        extra->indeterminate = true;
191        extra->is_default = false;
192        break;
193      case CBS_MIXEDPRESSED:
194        gfx_state = gfx::NativeTheme::kPressed;
195        extra->checked = false;
196        extra->indeterminate = true;
197        extra->is_default = false;
198        break;
199      case CBS_MIXEDDISABLED:
200        gfx_state = gfx::NativeTheme::kDisabled;
201        extra->checked = false;
202        extra->indeterminate = true;
203        extra->is_default = false;
204        break;
205      case CBS_IMPLICITNORMAL:
206        gfx_state = gfx::NativeTheme::kNormal;
207        extra->checked = false;
208        extra->indeterminate = false;
209        extra->is_default = false;
210        break;
211      case CBS_IMPLICITHOT:
212        gfx_state = gfx::NativeTheme::kHovered;
213        extra->checked = false;
214        extra->indeterminate = false;
215        extra->is_default = false;
216        break;
217      case CBS_IMPLICITPRESSED:
218        gfx_state = gfx::NativeTheme::kPressed;
219        extra->checked = false;
220        extra->indeterminate = false;
221        extra->is_default = false;
222        break;
223      case CBS_IMPLICITDISABLED:
224        gfx_state = gfx::NativeTheme::kDisabled;
225        extra->checked = false;
226        extra->indeterminate = false;
227        extra->is_default = false;
228        break;
229      case CBS_EXCLUDEDNORMAL:
230        gfx_state = gfx::NativeTheme::kNormal;
231        extra->checked = false;
232        extra->indeterminate = false;
233        extra->is_default = false;
234        break;
235      case CBS_EXCLUDEDHOT:
236        gfx_state = gfx::NativeTheme::kHovered;
237        extra->checked = false;
238        extra->indeterminate = false;
239        extra->is_default = false;
240        break;
241      case CBS_EXCLUDEDPRESSED:
242        gfx_state = gfx::NativeTheme::kPressed;
243        extra->checked = false;
244        extra->indeterminate = false;
245        extra->is_default = false;
246        break;
247      case CBS_EXCLUDEDDISABLED:
248        gfx_state = gfx::NativeTheme::kDisabled;
249        extra->checked = false;
250        extra->indeterminate = false;
251        extra->is_default = false;
252        break;
253      default:
254        NOTREACHED() << "Invalid state: " << state;
255        break;
256    }
257  } else if (part == BP_GROUPBOX) {
258    switch(state) {
259      case GBS_NORMAL:
260        gfx_state = gfx::NativeTheme::kNormal;
261        extra->checked = false;
262        extra->indeterminate = false;
263        extra->is_default = false;
264        break;
265      case GBS_DISABLED:
266        gfx_state = gfx::NativeTheme::kDisabled;
267        extra->checked = false;
268        extra->indeterminate = false;
269        extra->is_default = false;
270        break;
271      default:
272        NOTREACHED() << "Invalid state: " << state;
273        break;
274    }
275  } else if (part == BP_COMMANDLINK) {
276    switch(state) {
277      case CMDLS_NORMAL:
278        gfx_state = gfx::NativeTheme::kNormal;
279        extra->checked = false;
280        extra->indeterminate = false;
281        extra->is_default = false;
282        break;
283      case CMDLS_HOT:
284        gfx_state = gfx::NativeTheme::kHovered;
285        extra->checked = false;
286        extra->indeterminate = false;
287        extra->is_default = false;
288        break;
289      case CMDLS_PRESSED:
290        gfx_state = gfx::NativeTheme::kPressed;
291        extra->checked = false;
292        extra->indeterminate = false;
293        extra->is_default = false;
294        break;
295      case CMDLS_DISABLED:
296        gfx_state = gfx::NativeTheme::kDisabled;
297        extra->checked = false;
298        extra->indeterminate = false;
299        extra->is_default = false;
300        break;
301      case CMDLS_DEFAULTED:
302        gfx_state = gfx::NativeTheme::kNormal;
303        extra->checked = false;
304        extra->indeterminate = false;
305        extra->is_default = true;
306        break;
307      case CMDLS_DEFAULTED_ANIMATING:
308        gfx_state = gfx::NativeTheme::kNormal;
309        extra->checked = false;
310        extra->indeterminate = false;
311        extra->is_default = true;
312        break;
313      default:
314        NOTREACHED() << "Invalid state: " << state;
315        break;
316    }
317  } else if (part == BP_COMMANDLINKGLYPH) {
318    switch(state) {
319      case CMDLGS_NORMAL:
320        gfx_state = gfx::NativeTheme::kNormal;
321        extra->checked = false;
322        extra->indeterminate = false;
323        extra->is_default = false;
324        break;
325      case CMDLGS_HOT:
326        gfx_state = gfx::NativeTheme::kHovered;
327        extra->checked = false;
328        extra->indeterminate = false;
329        extra->is_default = false;
330        break;
331      case CMDLGS_PRESSED:
332        gfx_state = gfx::NativeTheme::kPressed;
333        extra->checked = false;
334        extra->indeterminate = false;
335        extra->is_default = false;
336        break;
337      case CMDLGS_DISABLED:
338        gfx_state = gfx::NativeTheme::kDisabled;
339        extra->checked = false;
340        extra->indeterminate = false;
341        extra->is_default = false;
342        break;
343      case CMDLGS_DEFAULTED:
344        gfx_state = gfx::NativeTheme::kNormal;
345        extra->checked = false;
346        extra->indeterminate = false;
347        extra->is_default = true;
348        break;
349      default:
350        NOTREACHED() << "Invalid state: " << state;
351        break;
352    }
353  }
354  return gfx_state;
355}
356
357void WebThemeEngineImpl::paintButton(
358    WebCanvas* canvas, int part, int state, int classic_state,
359    const WebRect& rect) {
360  gfx::NativeTheme::Part native_part = gfx::NativeTheme::kPushButton;
361  switch(part) {
362    case BP_PUSHBUTTON:
363      native_part = gfx::NativeTheme::kPushButton;
364      break;
365    case BP_CHECKBOX:
366      native_part = gfx::NativeTheme::kCheckbox;
367      break;
368    case BP_RADIOBUTTON:
369      native_part = gfx::NativeTheme::kRadio;
370      break;
371    default:
372      break;
373  }
374  gfx::NativeTheme::ExtraParams extra;
375  gfx::NativeTheme::State native_state = WebButtonStateToGfx(part, state,
376                                                             &extra.button);
377  extra.button.classic_state = classic_state;
378  gfx::Rect gfx_rect(rect.x, rect.y, rect.width, rect.height);
379  gfx::NativeTheme::instance()->Paint(canvas, native_part,
380                                      native_state, gfx_rect, extra);
381}
382
383void WebThemeEngineImpl::paintMenuList(
384    WebCanvas* canvas, int part, int state, int classic_state,
385    const WebRect& rect) {
386  HDC hdc = skia::BeginPlatformPaint(canvas);
387
388  RECT native_rect = WebRectToRECT(rect);
389  gfx::NativeThemeWin::instance()->PaintMenuList(
390      hdc, part, state, classic_state, &native_rect);
391
392  skia::EndPlatformPaint(canvas);
393}
394
395void WebThemeEngineImpl::paintScrollbarArrow(
396    WebCanvas* canvas, int state, int classic_state,
397    const WebRect& rect) {
398  HDC hdc = skia::BeginPlatformPaint(canvas);
399
400  RECT native_rect = WebRectToRECT(rect);
401  gfx::NativeThemeWin::instance()->PaintScrollbarArrow(
402      hdc, state, classic_state, &native_rect);
403
404  skia::EndPlatformPaint(canvas);
405}
406
407void WebThemeEngineImpl::paintScrollbarThumb(
408    WebCanvas* canvas, int part, int state, int classic_state,
409    const WebRect& rect) {
410  HDC hdc = skia::BeginPlatformPaint(canvas);
411
412  RECT native_rect = WebRectToRECT(rect);
413  gfx::NativeThemeWin::instance()->PaintScrollbarThumb(
414      hdc, part, state, classic_state, &native_rect);
415
416  skia::EndPlatformPaint(canvas);
417}
418
419void WebThemeEngineImpl::paintScrollbarTrack(
420    WebCanvas* canvas, int part, int state, int classic_state,
421    const WebRect& rect, const WebRect& align_rect) {
422  HDC hdc = skia::BeginPlatformPaint(canvas);
423
424  RECT native_rect = WebRectToRECT(rect);
425  RECT native_align_rect = WebRectToRECT(align_rect);
426  gfx::NativeThemeWin::instance()->PaintScrollbarTrack(
427      hdc, part, state, classic_state, &native_rect, &native_align_rect,
428      canvas);
429
430  skia::EndPlatformPaint(canvas);
431}
432
433void WebThemeEngineImpl::paintSpinButton(
434    WebCanvas* canvas, int part, int state, int classic_state,
435    const WebRect& rect) {
436  HDC hdc = skia::BeginPlatformPaint(canvas);
437
438  RECT native_rect = WebRectToRECT(rect);
439  gfx::NativeThemeWin::instance()->PaintSpinButton(
440      hdc, part, state, classic_state, &native_rect);
441
442  skia::EndPlatformPaint(canvas);
443}
444
445void WebThemeEngineImpl::paintTextField(
446    WebCanvas* canvas, int part, int state, int classic_state,
447    const WebRect& rect, WebColor color, bool fill_content_area,
448    bool draw_edges) {
449  HDC hdc = skia::BeginPlatformPaint(canvas);
450
451  RECT native_rect = WebRectToRECT(rect);
452  COLORREF c = skia::SkColorToCOLORREF(color);
453
454  gfx::NativeThemeWin::instance()->PaintTextField(
455      hdc, part, state, classic_state, &native_rect, c, fill_content_area,
456      draw_edges);
457
458  skia::EndPlatformPaint(canvas);
459}
460
461void WebThemeEngineImpl::paintTrackbar(
462    WebCanvas* canvas, int part, int state, int classic_state,
463    const WebRect& rect) {
464  HDC hdc = skia::BeginPlatformPaint(canvas);
465
466  RECT native_rect = WebRectToRECT(rect);
467  gfx::NativeThemeWin::instance()->PaintTrackbar(
468      hdc, part, state, classic_state, &native_rect, canvas);
469
470  skia::EndPlatformPaint(canvas);
471}
472
473void WebThemeEngineImpl::paintProgressBar(
474    WebCanvas* canvas, const WebRect& barRect, const WebRect& valueRect,
475    bool determinate, double animatedSeconds)
476{
477  HDC hdc = skia::BeginPlatformPaint(canvas);
478
479  RECT native_bar_rect = WebRectToRECT(barRect);
480  RECT native_value_rect = WebRectToRECT(valueRect);
481  gfx::NativeThemeWin::instance()->PaintProgressBar(
482      hdc, &native_bar_rect,
483      &native_value_rect, determinate, animatedSeconds, canvas);
484
485  skia::EndPlatformPaint(canvas);
486}
487
488}  // namespace webkit_glue
489