Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(373)

Side by Side Diff: gfx/native_theme_win.cc

Issue 6246027: Move src/gfx/ to src/ui/gfx... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « gfx/native_theme_win.h ('k') | gfx/native_theme_win_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 "gfx/native_theme_win.h"
6
7 #include <windows.h>
8 #include <uxtheme.h>
9 #include <vsstyle.h>
10 #include <vssym32.h>
11
12 #include "base/logging.h"
13 #include "base/scoped_handle.h"
14 #include "base/win/scoped_gdi_object.h"
15 #include "base/win/scoped_hdc.h"
16 #include "base/win/windows_version.h"
17 #include "gfx/gdi_util.h"
18 #include "gfx/rect.h"
19 #include "skia/ext/platform_canvas.h"
20 #include "skia/ext/skia_utils_win.h"
21 #include "third_party/skia/include/core/SkShader.h"
22
23 namespace {
24
25 void SetCheckerboardShader(SkPaint* paint, const RECT& align_rect) {
26 // Create a 2x2 checkerboard pattern using the 3D face and highlight colors.
27 SkColor face = skia::COLORREFToSkColor(GetSysColor(COLOR_3DFACE));
28 SkColor highlight = skia::COLORREFToSkColor(GetSysColor(COLOR_3DHILIGHT));
29 SkColor buffer[] = { face, highlight, highlight, face };
30 // Confusing bit: we first create a temporary bitmap with our desired pattern,
31 // then copy it to another bitmap. The temporary bitmap doesn't take
32 // ownership of the pixel data, and so will point to garbage when this
33 // function returns. The copy will copy the pixel data into a place owned by
34 // the bitmap, which is in turn owned by the shader, etc., so it will live
35 // until we're done using it.
36 SkBitmap temp_bitmap;
37 temp_bitmap.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
38 temp_bitmap.setPixels(buffer);
39 SkBitmap bitmap;
40 temp_bitmap.copyTo(&bitmap, temp_bitmap.config());
41 SkShader* shader = SkShader::CreateBitmapShader(bitmap,
42 SkShader::kRepeat_TileMode,
43 SkShader::kRepeat_TileMode);
44
45 // Align the pattern with the upper corner of |align_rect|.
46 SkMatrix matrix;
47 matrix.setTranslate(SkIntToScalar(align_rect.left),
48 SkIntToScalar(align_rect.top));
49 shader->setLocalMatrix(matrix);
50 SkSafeUnref(paint->setShader(shader));
51 }
52
53 } // namespace
54
55 namespace gfx {
56
57 /* static */
58 const NativeTheme* NativeTheme::instance() {
59 // The global NativeTheme instance.
60 static const NativeTheme s_native_theme;
61 return &s_native_theme;
62 }
63
64 NativeTheme::NativeTheme()
65 : theme_dll_(LoadLibrary(L"uxtheme.dll")),
66 draw_theme_(NULL),
67 draw_theme_ex_(NULL),
68 get_theme_color_(NULL),
69 get_theme_content_rect_(NULL),
70 get_theme_part_size_(NULL),
71 open_theme_(NULL),
72 close_theme_(NULL),
73 set_theme_properties_(NULL),
74 is_theme_active_(NULL),
75 get_theme_int_(NULL) {
76 if (theme_dll_) {
77 draw_theme_ = reinterpret_cast<DrawThemeBackgroundPtr>(
78 GetProcAddress(theme_dll_, "DrawThemeBackground"));
79 draw_theme_ex_ = reinterpret_cast<DrawThemeBackgroundExPtr>(
80 GetProcAddress(theme_dll_, "DrawThemeBackgroundEx"));
81 get_theme_color_ = reinterpret_cast<GetThemeColorPtr>(
82 GetProcAddress(theme_dll_, "GetThemeColor"));
83 get_theme_content_rect_ = reinterpret_cast<GetThemeContentRectPtr>(
84 GetProcAddress(theme_dll_, "GetThemeBackgroundContentRect"));
85 get_theme_part_size_ = reinterpret_cast<GetThemePartSizePtr>(
86 GetProcAddress(theme_dll_, "GetThemePartSize"));
87 open_theme_ = reinterpret_cast<OpenThemeDataPtr>(
88 GetProcAddress(theme_dll_, "OpenThemeData"));
89 close_theme_ = reinterpret_cast<CloseThemeDataPtr>(
90 GetProcAddress(theme_dll_, "CloseThemeData"));
91 set_theme_properties_ = reinterpret_cast<SetThemeAppPropertiesPtr>(
92 GetProcAddress(theme_dll_, "SetThemeAppProperties"));
93 is_theme_active_ = reinterpret_cast<IsThemeActivePtr>(
94 GetProcAddress(theme_dll_, "IsThemeActive"));
95 get_theme_int_ = reinterpret_cast<GetThemeIntPtr>(
96 GetProcAddress(theme_dll_, "GetThemeInt"));
97 }
98 memset(theme_handles_, 0, sizeof(theme_handles_));
99 }
100
101 NativeTheme::~NativeTheme() {
102 if (theme_dll_) {
103 // todo (cpu): fix this soon.
104 // CloseHandles();
105 FreeLibrary(theme_dll_);
106 }
107 }
108
109 HRESULT NativeTheme::PaintButton(HDC hdc,
110 int part_id,
111 int state_id,
112 int classic_state,
113 RECT* rect) const {
114 HANDLE handle = GetThemeHandle(BUTTON);
115 if (handle && draw_theme_)
116 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
117
118 // Draw it manually.
119 // All pressed states have both low bits set, and no other states do.
120 const bool focused = ((state_id & ETS_FOCUSED) == ETS_FOCUSED);
121 const bool pressed = ((state_id & PBS_PRESSED) == PBS_PRESSED);
122 if ((BP_PUSHBUTTON == part_id) && (pressed || focused)) {
123 // BP_PUSHBUTTON has a focus rect drawn around the outer edge, and the
124 // button itself is shrunk by 1 pixel.
125 HBRUSH brush = GetSysColorBrush(COLOR_3DDKSHADOW);
126 if (brush) {
127 FrameRect(hdc, rect, brush);
128 InflateRect(rect, -1, -1);
129 }
130 }
131 DrawFrameControl(hdc, rect, DFC_BUTTON, classic_state);
132
133 // Draw the focus rectangle (the dotted line box) only on buttons. For radio
134 // and checkboxes, we let webkit draw the focus rectangle (orange glow).
135 if ((BP_PUSHBUTTON == part_id) && focused) {
136 // The focus rect is inside the button. The exact number of pixels depends
137 // on whether we're in classic mode or using uxtheme.
138 if (handle && get_theme_content_rect_) {
139 get_theme_content_rect_(handle, hdc, part_id, state_id, rect, rect);
140 } else {
141 InflateRect(rect, -GetSystemMetrics(SM_CXEDGE),
142 -GetSystemMetrics(SM_CYEDGE));
143 }
144 DrawFocusRect(hdc, rect);
145 }
146
147 return S_OK;
148 }
149
150 HRESULT NativeTheme::PaintDialogBackground(HDC hdc, bool active,
151 RECT* rect) const {
152 HANDLE handle = GetThemeHandle(WINDOW);
153 if (handle && draw_theme_) {
154 return draw_theme_(handle, hdc, WP_DIALOG,
155 active ? FS_ACTIVE : FS_INACTIVE, rect, NULL);
156 }
157
158 // Classic just renders a flat color background.
159 FillRect(hdc, rect, reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1));
160 return S_OK;
161 }
162
163 HRESULT NativeTheme::PaintListBackground(HDC hdc,
164 bool enabled,
165 RECT* rect) const {
166 HANDLE handle = GetThemeHandle(LIST);
167 if (handle && draw_theme_)
168 return draw_theme_(handle, hdc, 1, TS_NORMAL, rect, NULL);
169
170 // Draw it manually.
171 HBRUSH bg_brush = GetSysColorBrush(COLOR_WINDOW);
172 FillRect(hdc, rect, bg_brush);
173 DrawEdge(hdc, rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
174 return S_OK;
175 }
176
177 HRESULT NativeTheme::PaintMenuArrow(ThemeName theme,
178 HDC hdc,
179 int part_id,
180 int state_id,
181 RECT* rect,
182 MenuArrowDirection arrow_direction,
183 ControlState control_state) const {
184 HANDLE handle = GetThemeHandle(MENU);
185 if (handle && draw_theme_) {
186 if (arrow_direction == RIGHT_POINTING_ARROW) {
187 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
188 } else {
189 // There is no way to tell the uxtheme API to draw a left pointing arrow;
190 // it doesn't have a flag equivalent to DFCS_MENUARROWRIGHT. But they
191 // are needed for RTL locales on Vista. So use a memory DC and mirror
192 // the region with GDI's StretchBlt.
193 Rect r(*rect);
194 base::win::ScopedHDC mem_dc(CreateCompatibleDC(hdc));
195 base::win::ScopedBitmap mem_bitmap(CreateCompatibleBitmap(hdc, r.width(),
196 r.height()));
197 HGDIOBJ old_bitmap = SelectObject(mem_dc, mem_bitmap);
198 // Copy and horizontally mirror the background from hdc into mem_dc. Use
199 // a negative-width source rect, starting at the rightmost pixel.
200 StretchBlt(mem_dc, 0, 0, r.width(), r.height(),
201 hdc, r.right()-1, r.y(), -r.width(), r.height(), SRCCOPY);
202 // Draw the arrow.
203 RECT theme_rect = {0, 0, r.width(), r.height()};
204 HRESULT result = draw_theme_(handle, mem_dc, part_id,
205 state_id, &theme_rect, NULL);
206 // Copy and mirror the result back into mem_dc.
207 StretchBlt(hdc, r.x(), r.y(), r.width(), r.height(),
208 mem_dc, r.width()-1, 0, -r.width(), r.height(), SRCCOPY);
209 SelectObject(mem_dc, old_bitmap);
210 return result;
211 }
212 }
213
214 // For some reason, Windows uses the name DFCS_MENUARROWRIGHT to indicate a
215 // left pointing arrow. This makes the following 'if' statement slightly
216 // counterintuitive.
217 UINT state;
218 if (arrow_direction == RIGHT_POINTING_ARROW)
219 state = DFCS_MENUARROW;
220 else
221 state = DFCS_MENUARROWRIGHT;
222 return PaintFrameControl(hdc, rect, DFC_MENU, state, control_state);
223 }
224
225 HRESULT NativeTheme::PaintMenuBackground(ThemeName theme,
226 HDC hdc,
227 int part_id,
228 int state_id,
229 RECT* rect) const {
230 HANDLE handle = GetThemeHandle(MENU);
231 if (handle && draw_theme_) {
232 HRESULT result = draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
233 FrameRect(hdc, rect, GetSysColorBrush(COLOR_3DSHADOW));
234 return result;
235 }
236
237 FillRect(hdc, rect, GetSysColorBrush(COLOR_MENU));
238 DrawEdge(hdc, rect, EDGE_RAISED, BF_RECT);
239 return S_OK;
240 }
241
242 HRESULT NativeTheme::PaintMenuCheckBackground(ThemeName theme,
243 HDC hdc,
244 int part_id,
245 int state_id,
246 RECT* rect) const {
247 HANDLE handle = GetThemeHandle(MENU);
248 if (handle && draw_theme_)
249 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
250 // Nothing to do for background.
251 return S_OK;
252 }
253
254 HRESULT NativeTheme::PaintMenuCheck(ThemeName theme,
255 HDC hdc,
256 int part_id,
257 int state_id,
258 RECT* rect,
259 ControlState control_state) const {
260 HANDLE handle = GetThemeHandle(MENU);
261 if (handle && draw_theme_) {
262 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
263 }
264 return PaintFrameControl(hdc, rect, DFC_MENU, DFCS_MENUCHECK, control_state);
265 }
266
267 HRESULT NativeTheme::PaintMenuGutter(HDC hdc,
268 int part_id,
269 int state_id,
270 RECT* rect) const {
271 HANDLE handle = GetThemeHandle(MENU);
272 if (handle && draw_theme_)
273 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
274 return E_NOTIMPL;
275 }
276
277 HRESULT NativeTheme::PaintMenuItemBackground(ThemeName theme,
278 HDC hdc,
279 int part_id,
280 int state_id,
281 bool selected,
282 RECT* rect) const {
283 HANDLE handle = GetThemeHandle(MENU);
284 if (handle && draw_theme_)
285 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
286 if (selected)
287 FillRect(hdc, rect, GetSysColorBrush(COLOR_HIGHLIGHT));
288 return S_OK;
289 }
290
291 HRESULT NativeTheme::PaintMenuList(HDC hdc,
292 int part_id,
293 int state_id,
294 int classic_state,
295 RECT* rect) const {
296 HANDLE handle = GetThemeHandle(MENULIST);
297 if (handle && draw_theme_)
298 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
299
300 // Draw it manually.
301 DrawFrameControl(hdc, rect, DFC_SCROLL, DFCS_SCROLLCOMBOBOX | classic_state);
302 return S_OK;
303 }
304
305 HRESULT NativeTheme::PaintMenuSeparator(HDC hdc,
306 int part_id,
307 int state_id,
308 RECT* rect) const {
309 HANDLE handle = GetThemeHandle(MENU);
310 if (handle && draw_theme_)
311 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
312 DrawEdge(hdc, rect, EDGE_ETCHED, BF_TOP);
313 return S_OK;
314 }
315
316 HRESULT NativeTheme::PaintScrollbarArrow(HDC hdc,
317 int state_id,
318 int classic_state,
319 RECT* rect) const {
320 HANDLE handle = GetThemeHandle(SCROLLBAR);
321 if (handle && draw_theme_)
322 return draw_theme_(handle, hdc, SBP_ARROWBTN, state_id, rect, NULL);
323
324 // Draw it manually.
325 DrawFrameControl(hdc, rect, DFC_SCROLL, classic_state);
326 return S_OK;
327 }
328
329 HRESULT NativeTheme::PaintScrollbarTrack(
330 HDC hdc,
331 int part_id,
332 int state_id,
333 int classic_state,
334 RECT* target_rect,
335 RECT* align_rect,
336 skia::PlatformCanvas* canvas) const {
337 HANDLE handle = GetThemeHandle(SCROLLBAR);
338 if (handle && draw_theme_)
339 return draw_theme_(handle, hdc, part_id, state_id, target_rect, NULL);
340
341 // Draw it manually.
342 const DWORD colorScrollbar = GetSysColor(COLOR_SCROLLBAR);
343 const DWORD color3DFace = GetSysColor(COLOR_3DFACE);
344 if ((colorScrollbar != color3DFace) &&
345 (colorScrollbar != GetSysColor(COLOR_WINDOW))) {
346 FillRect(hdc, target_rect, reinterpret_cast<HBRUSH>(COLOR_SCROLLBAR + 1));
347 } else {
348 SkPaint paint;
349 SetCheckerboardShader(&paint, *align_rect);
350 canvas->drawIRect(skia::RECTToSkIRect(*target_rect), paint);
351 }
352 if (classic_state & DFCS_PUSHED)
353 InvertRect(hdc, target_rect);
354 return S_OK;
355 }
356
357 HRESULT NativeTheme::PaintScrollbarThumb(HDC hdc,
358 int part_id,
359 int state_id,
360 int classic_state,
361 RECT* rect) const {
362 HANDLE handle = GetThemeHandle(SCROLLBAR);
363 if (handle && draw_theme_)
364 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
365
366 // Draw it manually.
367 if ((part_id == SBP_THUMBBTNHORZ) || (part_id == SBP_THUMBBTNVERT))
368 DrawEdge(hdc, rect, EDGE_RAISED, BF_RECT | BF_MIDDLE);
369 // Classic mode doesn't have a gripper.
370 return S_OK;
371 }
372
373 HRESULT NativeTheme::PaintSpinButton(HDC hdc,
374 int part_id,
375 int state_id,
376 int classic_state,
377 RECT* rect) const {
378 HANDLE handle = GetThemeHandle(SPIN);
379 if (handle && draw_theme_)
380 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
381 DrawFrameControl(hdc, rect, DFC_SCROLL, classic_state);
382 return S_OK;
383 }
384
385 HRESULT NativeTheme::PaintStatusGripper(HDC hdc,
386 int part_id,
387 int state_id,
388 int classic_state,
389 RECT* rect) const {
390 HANDLE handle = GetThemeHandle(STATUS);
391 if (handle && draw_theme_) {
392 // Paint the status bar gripper. There doesn't seem to be a
393 // standard gripper in Windows for the space between
394 // scrollbars. This is pretty close, but it's supposed to be
395 // painted over a status bar.
396 return draw_theme_(handle, hdc, SP_GRIPPER, 0, rect, NULL);
397 }
398
399 // Draw a windows classic scrollbar gripper.
400 DrawFrameControl(hdc, rect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
401 return S_OK;
402 }
403
404 HRESULT NativeTheme::PaintTabPanelBackground(HDC hdc, RECT* rect) const {
405 HANDLE handle = GetThemeHandle(TAB);
406 if (handle && draw_theme_)
407 return draw_theme_(handle, hdc, TABP_BODY, 0, rect, NULL);
408
409 // Classic just renders a flat color background.
410 FillRect(hdc, rect, reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1));
411 return S_OK;
412 }
413
414 HRESULT NativeTheme::PaintTrackbar(HDC hdc,
415 int part_id,
416 int state_id,
417 int classic_state,
418 RECT* rect,
419 skia::PlatformCanvas* canvas) const {
420 // Make the channel be 4 px thick in the center of the supplied rect. (4 px
421 // matches what XP does in various menus; GetThemePartSize() doesn't seem to
422 // return good values here.)
423 RECT channel_rect = *rect;
424 const int channel_thickness = 4;
425 if (part_id == TKP_TRACK) {
426 channel_rect.top +=
427 ((channel_rect.bottom - channel_rect.top - channel_thickness) / 2);
428 channel_rect.bottom = channel_rect.top + channel_thickness;
429 } else if (part_id == TKP_TRACKVERT) {
430 channel_rect.left +=
431 ((channel_rect.right - channel_rect.left - channel_thickness) / 2);
432 channel_rect.right = channel_rect.left + channel_thickness;
433 } // else this isn't actually a channel, so |channel_rect| == |rect|.
434
435 HANDLE handle = GetThemeHandle(TRACKBAR);
436 if (handle && draw_theme_)
437 return draw_theme_(handle, hdc, part_id, state_id, &channel_rect, NULL);
438
439 // Classic mode, draw it manually.
440 if ((part_id == TKP_TRACK) || (part_id == TKP_TRACKVERT)) {
441 DrawEdge(hdc, &channel_rect, EDGE_SUNKEN, BF_RECT);
442 } else if (part_id == TKP_THUMBVERT) {
443 DrawEdge(hdc, rect, EDGE_RAISED, BF_RECT | BF_SOFT | BF_MIDDLE);
444 } else {
445 // Split rect into top and bottom pieces.
446 RECT top_section = *rect;
447 RECT bottom_section = *rect;
448 top_section.bottom -= ((bottom_section.right - bottom_section.left) / 2);
449 bottom_section.top = top_section.bottom;
450 DrawEdge(hdc, &top_section, EDGE_RAISED,
451 BF_LEFT | BF_TOP | BF_RIGHT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
452
453 // Split triangular piece into two diagonals.
454 RECT& left_half = bottom_section;
455 RECT right_half = bottom_section;
456 right_half.left += ((bottom_section.right - bottom_section.left) / 2);
457 left_half.right = right_half.left;
458 DrawEdge(hdc, &left_half, EDGE_RAISED,
459 BF_DIAGONAL_ENDTOPLEFT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
460 DrawEdge(hdc, &right_half, EDGE_RAISED,
461 BF_DIAGONAL_ENDBOTTOMLEFT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
462
463 // If the button is pressed, draw hatching.
464 if (classic_state & DFCS_PUSHED) {
465 SkPaint paint;
466 SetCheckerboardShader(&paint, *rect);
467
468 // Fill all three pieces with the pattern.
469 canvas->drawIRect(skia::RECTToSkIRect(top_section), paint);
470
471 SkScalar left_triangle_top = SkIntToScalar(left_half.top);
472 SkScalar left_triangle_right = SkIntToScalar(left_half.right);
473 SkPath left_triangle;
474 left_triangle.moveTo(SkIntToScalar(left_half.left), left_triangle_top);
475 left_triangle.lineTo(left_triangle_right, left_triangle_top);
476 left_triangle.lineTo(left_triangle_right,
477 SkIntToScalar(left_half.bottom));
478 left_triangle.close();
479 canvas->drawPath(left_triangle, paint);
480
481 SkScalar right_triangle_left = SkIntToScalar(right_half.left);
482 SkScalar right_triangle_top = SkIntToScalar(right_half.top);
483 SkPath right_triangle;
484 right_triangle.moveTo(right_triangle_left, right_triangle_top);
485 right_triangle.lineTo(SkIntToScalar(right_half.right),
486 right_triangle_top);
487 right_triangle.lineTo(right_triangle_left,
488 SkIntToScalar(right_half.bottom));
489 right_triangle.close();
490 canvas->drawPath(right_triangle, paint);
491 }
492 }
493 return S_OK;
494 }
495
496 // <-a->
497 // [ ***** ]
498 // ____ | |
499 // <-a-> <------b----->
500 // a: object_width
501 // b: frame_width
502 // *: animating object
503 //
504 // - the animation goes from "[" to "]" repeatedly.
505 // - the animation offset is at first "|"
506 //
507 static int ComputeAnimationProgress(int frame_width,
508 int object_width,
509 int pixels_per_second,
510 double animated_seconds) {
511 int animation_width = frame_width + object_width;
512 double interval = static_cast<double>(animation_width) / pixels_per_second;
513 double ratio = fmod(animated_seconds, interval) / interval;
514 return static_cast<int>(animation_width * ratio) - object_width;
515 }
516
517 static RECT InsetRect(const RECT* rect, int size) {
518 gfx::Rect result(*rect);
519 result.Inset(size, size);
520 return result.ToRECT();
521 }
522
523 HRESULT NativeTheme::PaintProgressBar(HDC hdc,
524 RECT* bar_rect,
525 RECT* value_rect,
526 bool determinate,
527 double animated_seconds,
528 skia::PlatformCanvas* canvas) const {
529 // There is no documentation about the animation speed, frame-rate, nor
530 // size of moving overlay of the indeterminate progress bar.
531 // So we just observed real-world programs and guessed following parameters.
532 const int kDeteminateOverlayPixelsPerSecond = 300;
533 const int kDeteminateOverlayWidth = 120;
534 const int kIndeterminateOverlayPixelsPerSecond = 175;
535 const int kVistaIndeterminateOverlayWidth = 120;
536 const int kXPIndeterminateOverlayWidth = 55;
537 // The thickness of the bar frame inside |value_rect|
538 const int kXPBarPadding = 3;
539
540 bool pre_vista = base::win::GetVersion() < base::win::VERSION_VISTA;
541 HANDLE handle = GetThemeHandle(PROGRESS);
542 if (handle && draw_theme_ && draw_theme_ex_) {
543 draw_theme_(handle, hdc, PP_BAR, 0, bar_rect, NULL);
544
545 int bar_width = bar_rect->right - bar_rect->left;
546 if (determinate) {
547 // TODO(morrita): this RTL guess can be wrong.
548 // We should pass the direction from WebKit side.
549 bool is_rtl = (bar_rect->right == value_rect->right &&
550 bar_rect->left != value_rect->left);
551 // We should care the direction here because PP_CNUNK painting
552 // is asymmetric.
553 DTBGOPTS value_draw_options;
554 value_draw_options.dwSize = sizeof(DTBGOPTS);
555 value_draw_options.dwFlags = is_rtl ? DTBG_MIRRORDC : 0;
556 value_draw_options.rcClip = *bar_rect;
557
558 if (pre_vista) {
559 // On XP, progress bar is chunk-style and has no glossy effect.
560 // We need to shrink destination rect to fit the part inside the bar
561 // with an appropriate margin.
562 RECT shrunk_value_rect = InsetRect(value_rect, kXPBarPadding);
563 draw_theme_ex_(handle, hdc, PP_CHUNK, 0,
564 &shrunk_value_rect, &value_draw_options);
565 } else {
566 // On Vista or later, the progress bar part has a
567 // single-block value part. It also has glossy effect.
568 // And the value part has exactly same height as the bar part
569 // so we don't need to shrink the rect.
570 draw_theme_ex_(handle, hdc, PP_FILL, 0,
571 value_rect, &value_draw_options);
572
573 int dx = ComputeAnimationProgress(bar_width,
574 kDeteminateOverlayWidth,
575 kDeteminateOverlayPixelsPerSecond,
576 animated_seconds);
577 RECT overlay_rect = *value_rect;
578 overlay_rect.left += dx;
579 overlay_rect.right = overlay_rect.left + kDeteminateOverlayWidth;
580 draw_theme_(handle, hdc, PP_MOVEOVERLAY, 0, &overlay_rect, value_rect);
581 }
582 } else {
583 // A glossy overlay for indeterminate progress bar has small pause
584 // after each animation. We emulate this by adding an invisible margin
585 // the animation has to traverse.
586 int width_with_margin = bar_width + kIndeterminateOverlayPixelsPerSecond;
587 int overlay_width = pre_vista ?
588 kXPIndeterminateOverlayWidth : kVistaIndeterminateOverlayWidth;
589 int dx = ComputeAnimationProgress(width_with_margin,
590 overlay_width,
591 kIndeterminateOverlayPixelsPerSecond,
592 animated_seconds);
593 RECT overlay_rect = *bar_rect;
594 overlay_rect.left += dx;
595 overlay_rect.right = overlay_rect.left + overlay_width;
596 if (pre_vista) {
597 RECT shrunk_rect = InsetRect(&overlay_rect, kXPBarPadding);
598 RECT shrunk_bar_rect = InsetRect(bar_rect, kXPBarPadding);
599 draw_theme_(handle, hdc, PP_CHUNK, 0, &shrunk_rect, &shrunk_bar_rect);
600 } else {
601 draw_theme_(handle, hdc, PP_MOVEOVERLAY, 0, &overlay_rect, bar_rect);
602 }
603 }
604
605 return S_OK;
606 }
607
608 HBRUSH bg_brush = GetSysColorBrush(COLOR_BTNFACE);
609 HBRUSH fg_brush = GetSysColorBrush(COLOR_BTNSHADOW);
610 FillRect(hdc, bar_rect, bg_brush);
611 FillRect(hdc, value_rect, fg_brush);
612 DrawEdge(hdc, bar_rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
613 return S_OK;
614 }
615
616 HRESULT NativeTheme::PaintTextField(HDC hdc,
617 int part_id,
618 int state_id,
619 int classic_state,
620 RECT* rect,
621 COLORREF color,
622 bool fill_content_area,
623 bool draw_edges) const {
624 // TODO(ojan): http://b/1210017 Figure out how to give the ability to
625 // exclude individual edges from being drawn.
626
627 HANDLE handle = GetThemeHandle(TEXTFIELD);
628 // TODO(mpcomplete): can we detect if the color is specified by the user,
629 // and if not, just use the system color?
630 // CreateSolidBrush() accepts a RGB value but alpha must be 0.
631 HBRUSH bg_brush = CreateSolidBrush(color);
632 HRESULT hr;
633 // DrawThemeBackgroundEx was introduced in XP SP2, so that it's possible
634 // draw_theme_ex_ is NULL and draw_theme_ is non-null.
635 if (handle && (draw_theme_ex_ || (draw_theme_ && draw_edges))) {
636 if (draw_theme_ex_) {
637 static DTBGOPTS omit_border_options = {
638 sizeof(DTBGOPTS),
639 DTBG_OMITBORDER,
640 {0,0,0,0}
641 };
642 DTBGOPTS* draw_opts = draw_edges ? NULL : &omit_border_options;
643 hr = draw_theme_ex_(handle, hdc, part_id, state_id, rect, draw_opts);
644 } else {
645 hr = draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
646 }
647
648 // TODO(maruel): Need to be fixed if get_theme_content_rect_ is NULL.
649 if (fill_content_area && get_theme_content_rect_) {
650 RECT content_rect;
651 hr = get_theme_content_rect_(handle, hdc, part_id, state_id, rect,
652 &content_rect);
653 FillRect(hdc, &content_rect, bg_brush);
654 }
655 } else {
656 // Draw it manually.
657 if (draw_edges)
658 DrawEdge(hdc, rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
659
660 if (fill_content_area) {
661 FillRect(hdc, rect, (classic_state & DFCS_INACTIVE) ?
662 reinterpret_cast<HBRUSH>(COLOR_BTNFACE + 1) : bg_brush);
663 }
664 hr = S_OK;
665 }
666 DeleteObject(bg_brush);
667 return hr;
668 }
669
670 bool NativeTheme::IsThemingActive() const {
671 if (is_theme_active_)
672 return !!is_theme_active_();
673 return false;
674 }
675
676 HRESULT NativeTheme::GetThemePartSize(ThemeName theme_name,
677 HDC hdc,
678 int part_id,
679 int state_id,
680 RECT* rect,
681 int ts,
682 SIZE* size) const {
683 HANDLE handle = GetThemeHandle(theme_name);
684 if (handle && get_theme_part_size_)
685 return get_theme_part_size_(handle, hdc, part_id, state_id, rect, ts, size);
686
687 return E_NOTIMPL;
688 }
689
690 HRESULT NativeTheme::GetThemeColor(ThemeName theme,
691 int part_id,
692 int state_id,
693 int prop_id,
694 SkColor* color) const {
695 HANDLE handle = GetThemeHandle(theme);
696 if (handle && get_theme_color_) {
697 COLORREF color_ref;
698 if (get_theme_color_(handle, part_id, state_id, prop_id, &color_ref) ==
699 S_OK) {
700 *color = skia::COLORREFToSkColor(color_ref);
701 return S_OK;
702 }
703 }
704 return E_NOTIMPL;
705 }
706
707 SkColor NativeTheme::GetThemeColorWithDefault(ThemeName theme,
708 int part_id,
709 int state_id,
710 int prop_id,
711 int default_sys_color) const {
712 SkColor color;
713 if (GetThemeColor(theme, part_id, state_id, prop_id, &color) != S_OK)
714 color = skia::COLORREFToSkColor(GetSysColor(default_sys_color));
715 return color;
716 }
717
718 HRESULT NativeTheme::GetThemeInt(ThemeName theme,
719 int part_id,
720 int state_id,
721 int prop_id,
722 int *value) const {
723 HANDLE handle = GetThemeHandle(theme);
724 if (handle && get_theme_int_)
725 return get_theme_int_(handle, part_id, state_id, prop_id, value);
726 return E_NOTIMPL;
727 }
728
729 Size NativeTheme::GetThemeBorderSize(ThemeName theme) const {
730 // For simplicity use the wildcard state==0, part==0, since it works
731 // for the cases we currently depend on.
732 int border;
733 if (GetThemeInt(theme, 0, 0, TMT_BORDERSIZE, &border) == S_OK)
734 return Size(border, border);
735 else
736 return Size(GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
737 }
738
739
740 void NativeTheme::DisableTheming() const {
741 if (!set_theme_properties_)
742 return;
743 set_theme_properties_(0);
744 }
745
746 HRESULT NativeTheme::PaintFrameControl(HDC hdc,
747 RECT* rect,
748 UINT type,
749 UINT state,
750 ControlState control_state) const {
751 const int width = rect->right - rect->left;
752 const int height = rect->bottom - rect->top;
753
754 // DrawFrameControl for menu arrow/check wants a monochrome bitmap.
755 base::win::ScopedBitmap mask_bitmap(CreateBitmap(width, height, 1, 1, NULL));
756
757 if (mask_bitmap == NULL)
758 return E_OUTOFMEMORY;
759
760 base::win::ScopedHDC bitmap_dc(CreateCompatibleDC(NULL));
761 HGDIOBJ org_bitmap = SelectObject(bitmap_dc, mask_bitmap);
762 RECT local_rect = { 0, 0, width, height };
763 DrawFrameControl(bitmap_dc, &local_rect, type, state);
764
765 // We're going to use BitBlt with a b&w mask. This results in using the dest
766 // dc's text color for the black bits in the mask, and the dest dc's
767 // background color for the white bits in the mask. DrawFrameControl draws the
768 // check in black, and the background in white.
769 int bg_color_key;
770 int text_color_key;
771 switch (control_state) {
772 case CONTROL_HIGHLIGHTED:
773 bg_color_key = COLOR_HIGHLIGHT;
774 text_color_key = COLOR_HIGHLIGHTTEXT;
775 break;
776 case CONTROL_NORMAL:
777 bg_color_key = COLOR_MENU;
778 text_color_key = COLOR_MENUTEXT;
779 break;
780 case CONTROL_DISABLED:
781 bg_color_key = COLOR_MENU;
782 text_color_key = COLOR_GRAYTEXT;
783 break;
784 default:
785 NOTREACHED();
786 bg_color_key = COLOR_MENU;
787 text_color_key = COLOR_MENUTEXT;
788 break;
789 }
790 COLORREF old_bg_color = SetBkColor(hdc, GetSysColor(bg_color_key));
791 COLORREF old_text_color = SetTextColor(hdc, GetSysColor(text_color_key));
792 BitBlt(hdc, rect->left, rect->top, width, height, bitmap_dc, 0, 0, SRCCOPY);
793 SetBkColor(hdc, old_bg_color);
794 SetTextColor(hdc, old_text_color);
795
796 SelectObject(bitmap_dc, org_bitmap);
797
798 return S_OK;
799 }
800
801 void NativeTheme::CloseHandles() const
802 {
803 if (!close_theme_)
804 return;
805
806 for (int i = 0; i < LAST; ++i) {
807 if (theme_handles_[i])
808 close_theme_(theme_handles_[i]);
809 theme_handles_[i] = NULL;
810 }
811 }
812
813 bool NativeTheme::IsClassicTheme(ThemeName name) const {
814 if (!theme_dll_)
815 return true;
816
817 return !GetThemeHandle(name);
818 }
819
820 HANDLE NativeTheme::GetThemeHandle(ThemeName theme_name) const
821 {
822 if (!open_theme_ || theme_name < 0 || theme_name >= LAST)
823 return 0;
824
825 if (theme_handles_[theme_name])
826 return theme_handles_[theme_name];
827
828 // Not found, try to load it.
829 HANDLE handle = 0;
830 switch (theme_name) {
831 case BUTTON:
832 handle = open_theme_(NULL, L"Button");
833 break;
834 case LIST:
835 handle = open_theme_(NULL, L"Listview");
836 break;
837 case MENU:
838 handle = open_theme_(NULL, L"Menu");
839 break;
840 case MENULIST:
841 handle = open_theme_(NULL, L"Combobox");
842 break;
843 case SCROLLBAR:
844 handle = open_theme_(NULL, L"Scrollbar");
845 break;
846 case STATUS:
847 handle = open_theme_(NULL, L"Status");
848 break;
849 case TAB:
850 handle = open_theme_(NULL, L"Tab");
851 break;
852 case TEXTFIELD:
853 handle = open_theme_(NULL, L"Edit");
854 break;
855 case TRACKBAR:
856 handle = open_theme_(NULL, L"Trackbar");
857 break;
858 case WINDOW:
859 handle = open_theme_(NULL, L"Window");
860 break;
861 case PROGRESS:
862 handle = open_theme_(NULL, L"Progress");
863 break;
864 case SPIN:
865 handle = open_theme_(NULL, L"Spin");
866 break;
867 default:
868 NOTREACHED();
869 }
870 theme_handles_[theme_name] = handle;
871 return handle;
872 }
873
874 } // namespace gfx
OLDNEW
« no previous file with comments | « gfx/native_theme_win.h ('k') | gfx/native_theme_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698