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

Side by Side Diff: base/gfx/native_theme.cc

Issue 259047: Move classes depending on Skia out of base/gfx and into app/gfx. Rename... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 2 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 | « base/gfx/native_theme.h ('k') | base/gfx/native_theme_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) 2006-2008 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 "base/gfx/native_theme.h"
6
7 #include <windows.h>
8 #include <uxtheme.h>
9 #include <vsstyle.h>
10 #include <vssym32.h>
11
12 #include "base/gfx/gdi_util.h"
13 #include "base/gfx/rect.h"
14 #include "base/logging.h"
15 #include "base/scoped_handle.h"
16 #include "skia/ext/platform_canvas.h"
17 #include "skia/ext/skia_utils_win.h"
18 #include "third_party/skia/include/core/SkShader.h"
19
20 namespace {
21
22 void SetCheckerboardShader(SkPaint* paint, const RECT& align_rect) {
23 // Create a 2x2 checkerboard pattern using the 3D face and highlight colors.
24 SkColor face = skia::COLORREFToSkColor(GetSysColor(COLOR_3DFACE));
25 SkColor highlight = skia::COLORREFToSkColor(GetSysColor(COLOR_3DHILIGHT));
26 SkColor buffer[] = { face, highlight, highlight, face };
27 // Confusing bit: we first create a temporary bitmap with our desired pattern,
28 // then copy it to another bitmap. The temporary bitmap doesn't take
29 // ownership of the pixel data, and so will point to garbage when this
30 // function returns. The copy will copy the pixel data into a place owned by
31 // the bitmap, which is in turn owned by the shader, etc., so it will live
32 // until we're done using it.
33 SkBitmap temp_bitmap;
34 temp_bitmap.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
35 temp_bitmap.setPixels(buffer);
36 SkBitmap bitmap;
37 temp_bitmap.copyTo(&bitmap, temp_bitmap.config());
38 SkShader* shader = SkShader::CreateBitmapShader(bitmap,
39 SkShader::kRepeat_TileMode,
40 SkShader::kRepeat_TileMode);
41
42 // Align the pattern with the upper corner of |align_rect|.
43 SkMatrix matrix;
44 matrix.setTranslate(SkIntToScalar(align_rect.left),
45 SkIntToScalar(align_rect.top));
46 shader->setLocalMatrix(matrix);
47 paint->setShader(shader)->safeUnref();
48 }
49
50 } // namespace
51
52 namespace gfx {
53
54 /* static */
55 const NativeTheme* NativeTheme::instance() {
56 // The global NativeTheme instance.
57 static const NativeTheme s_native_theme;
58 return &s_native_theme;
59 }
60
61 NativeTheme::NativeTheme()
62 : theme_dll_(LoadLibrary(L"uxtheme.dll")),
63 draw_theme_(NULL),
64 draw_theme_ex_(NULL),
65 get_theme_color_(NULL),
66 get_theme_content_rect_(NULL),
67 get_theme_part_size_(NULL),
68 open_theme_(NULL),
69 close_theme_(NULL),
70 set_theme_properties_(NULL),
71 is_theme_active_(NULL),
72 get_theme_int_(NULL) {
73 if (theme_dll_) {
74 draw_theme_ = reinterpret_cast<DrawThemeBackgroundPtr>(
75 GetProcAddress(theme_dll_, "DrawThemeBackground"));
76 draw_theme_ex_ = reinterpret_cast<DrawThemeBackgroundExPtr>(
77 GetProcAddress(theme_dll_, "DrawThemeBackgroundEx"));
78 get_theme_color_ = reinterpret_cast<GetThemeColorPtr>(
79 GetProcAddress(theme_dll_, "GetThemeColor"));
80 get_theme_content_rect_ = reinterpret_cast<GetThemeContentRectPtr>(
81 GetProcAddress(theme_dll_, "GetThemeBackgroundContentRect"));
82 get_theme_part_size_ = reinterpret_cast<GetThemePartSizePtr>(
83 GetProcAddress(theme_dll_, "GetThemePartSize"));
84 open_theme_ = reinterpret_cast<OpenThemeDataPtr>(
85 GetProcAddress(theme_dll_, "OpenThemeData"));
86 close_theme_ = reinterpret_cast<CloseThemeDataPtr>(
87 GetProcAddress(theme_dll_, "CloseThemeData"));
88 set_theme_properties_ = reinterpret_cast<SetThemeAppPropertiesPtr>(
89 GetProcAddress(theme_dll_, "SetThemeAppProperties"));
90 is_theme_active_ = reinterpret_cast<IsThemeActivePtr>(
91 GetProcAddress(theme_dll_, "IsThemeActive"));
92 get_theme_int_ = reinterpret_cast<GetThemeIntPtr>(
93 GetProcAddress(theme_dll_, "GetThemeInt"));
94 }
95 memset(theme_handles_, 0, sizeof(theme_handles_));
96 }
97
98 NativeTheme::~NativeTheme() {
99 if (theme_dll_) {
100 // todo (cpu): fix this soon.
101 // CloseHandles();
102 FreeLibrary(theme_dll_);
103 }
104 }
105
106 HRESULT NativeTheme::PaintButton(HDC hdc,
107 int part_id,
108 int state_id,
109 int classic_state,
110 RECT* rect) const {
111 HANDLE handle = GetThemeHandle(BUTTON);
112 if (handle && draw_theme_)
113 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
114
115 // Draw it manually.
116 // All pressed states have both low bits set, and no other states do.
117 const bool focused = ((state_id & ETS_FOCUSED) == ETS_FOCUSED);
118 const bool pressed = ((state_id & PBS_PRESSED) == PBS_PRESSED);
119 if ((BP_PUSHBUTTON == part_id) && (pressed || focused)) {
120 // BP_PUSHBUTTON has a focus rect drawn around the outer edge, and the
121 // button itself is shrunk by 1 pixel.
122 HBRUSH brush = GetSysColorBrush(COLOR_3DDKSHADOW);
123 if (brush) {
124 FrameRect(hdc, rect, brush);
125 InflateRect(rect, -1, -1);
126 }
127 }
128 DrawFrameControl(hdc, rect, DFC_BUTTON, classic_state);
129
130 // Draw the focus rectangle (the dotted line box) only on buttons. For radio
131 // and checkboxes, we let webkit draw the focus rectangle (orange glow).
132 if ((BP_PUSHBUTTON == part_id) && focused) {
133 // The focus rect is inside the button. The exact number of pixels depends
134 // on whether we're in classic mode or using uxtheme.
135 if (handle && get_theme_content_rect_) {
136 get_theme_content_rect_(handle, hdc, part_id, state_id, rect, rect);
137 } else {
138 InflateRect(rect, -GetSystemMetrics(SM_CXEDGE),
139 -GetSystemMetrics(SM_CYEDGE));
140 }
141 DrawFocusRect(hdc, rect);
142 }
143
144 return S_OK;
145 }
146
147 HRESULT NativeTheme::PaintDialogBackground(HDC hdc, bool active,
148 RECT* rect) const {
149 HANDLE handle = GetThemeHandle(WINDOW);
150 if (handle && draw_theme_) {
151 return draw_theme_(handle, hdc, WP_DIALOG,
152 active ? FS_ACTIVE : FS_INACTIVE, rect, NULL);
153 }
154
155 // Classic just renders a flat color background.
156 FillRect(hdc, rect, reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1));
157 return S_OK;
158 }
159
160 HRESULT NativeTheme::PaintListBackground(HDC hdc,
161 bool enabled,
162 RECT* rect) const {
163 HANDLE handle = GetThemeHandle(LIST);
164 if (handle && draw_theme_)
165 return draw_theme_(handle, hdc, 1, TS_NORMAL, rect, NULL);
166
167 // Draw it manually.
168 HBRUSH bg_brush = GetSysColorBrush(COLOR_WINDOW);
169 FillRect(hdc, rect, bg_brush);
170 DrawEdge(hdc, rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
171 return S_OK;
172 }
173
174 HRESULT NativeTheme::PaintMenuArrow(ThemeName theme,
175 HDC hdc,
176 int part_id,
177 int state_id,
178 RECT* rect,
179 MenuArrowDirection arrow_direction,
180 bool is_highlighted) const {
181 HANDLE handle = GetThemeHandle(MENU);
182 if (handle && draw_theme_) {
183 if (arrow_direction == RIGHT_POINTING_ARROW) {
184 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
185 } else {
186 // There is no way to tell the uxtheme API to draw a left pointing arrow;
187 // it doesn't have a flag equivalent to DFCS_MENUARROWRIGHT. But they
188 // are needed for RTL locales on Vista. So use a memory DC and mirror
189 // the region with GDI's StretchBlt.
190 Rect r(*rect);
191 ScopedHDC mem_dc(CreateCompatibleDC(hdc));
192 ScopedBitmap mem_bitmap(CreateCompatibleBitmap(hdc, r.width(),
193 r.height()));
194 HGDIOBJ old_bitmap = SelectObject(mem_dc, mem_bitmap);
195 // Copy and horizontally mirror the background from hdc into mem_dc. Use
196 // a negative-width source rect, starting at the rightmost pixel.
197 StretchBlt(mem_dc, 0, 0, r.width(), r.height(),
198 hdc, r.right()-1, r.y(), -r.width(), r.height(), SRCCOPY);
199 // Draw the arrow.
200 RECT theme_rect = {0, 0, r.width(), r.height()};
201 HRESULT result = draw_theme_(handle, mem_dc, part_id,
202 state_id, &theme_rect, NULL);
203 // Copy and mirror the result back into mem_dc.
204 StretchBlt(hdc, r.x(), r.y(), r.width(), r.height(),
205 mem_dc, r.width()-1, 0, -r.width(), r.height(), SRCCOPY);
206 SelectObject(mem_dc, old_bitmap);
207 return result;
208 }
209 }
210
211 // For some reason, Windows uses the name DFCS_MENUARROWRIGHT to indicate a
212 // left pointing arrow. This makes the following 'if' statement slightly
213 // counterintuitive.
214 UINT state;
215 if (arrow_direction == RIGHT_POINTING_ARROW)
216 state = DFCS_MENUARROW;
217 else
218 state = DFCS_MENUARROWRIGHT;
219 return PaintFrameControl(hdc, rect, DFC_MENU, state, is_highlighted);
220 }
221
222 HRESULT NativeTheme::PaintMenuBackground(ThemeName theme,
223 HDC hdc,
224 int part_id,
225 int state_id,
226 RECT* rect) const {
227 HANDLE handle = GetThemeHandle(MENU);
228 if (handle && draw_theme_) {
229 HRESULT result = draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
230 FrameRect(hdc, rect, GetSysColorBrush(COLOR_3DSHADOW));
231 return result;
232 }
233
234 FillRect(hdc, rect, GetSysColorBrush(COLOR_MENU));
235 DrawEdge(hdc, rect, EDGE_RAISED, BF_RECT);
236 return S_OK;
237 }
238
239 HRESULT NativeTheme::PaintMenuCheckBackground(ThemeName theme,
240 HDC hdc,
241 int part_id,
242 int state_id,
243 RECT* rect) const {
244 HANDLE handle = GetThemeHandle(MENU);
245 if (handle && draw_theme_)
246 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
247 // Nothing to do for background.
248 return S_OK;
249 }
250
251 HRESULT NativeTheme::PaintMenuCheck(ThemeName theme,
252 HDC hdc,
253 int part_id,
254 int state_id,
255 RECT* rect,
256 bool is_highlighted) const {
257 HANDLE handle = GetThemeHandle(MENU);
258 if (handle && draw_theme_) {
259 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
260 }
261 return PaintFrameControl(hdc, rect, DFC_MENU, DFCS_MENUCHECK, is_highlighted);
262 }
263
264 HRESULT NativeTheme::PaintMenuGutter(HDC hdc,
265 int part_id,
266 int state_id,
267 RECT* rect) const {
268 HANDLE handle = GetThemeHandle(MENU);
269 if (handle && draw_theme_)
270 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
271 return E_NOTIMPL;
272 }
273
274 HRESULT NativeTheme::PaintMenuItemBackground(ThemeName theme,
275 HDC hdc,
276 int part_id,
277 int state_id,
278 bool selected,
279 RECT* rect) const {
280 HANDLE handle = GetThemeHandle(MENU);
281 if (handle && draw_theme_)
282 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
283 if (selected)
284 FillRect(hdc, rect, GetSysColorBrush(COLOR_HIGHLIGHT));
285 return S_OK;
286 }
287
288 HRESULT NativeTheme::PaintMenuList(HDC hdc,
289 int part_id,
290 int state_id,
291 int classic_state,
292 RECT* rect) const {
293 HANDLE handle = GetThemeHandle(MENULIST);
294 if (handle && draw_theme_)
295 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
296
297 // Draw it manually.
298 DrawFrameControl(hdc, rect, DFC_SCROLL, DFCS_SCROLLCOMBOBOX | classic_state);
299 return S_OK;
300 }
301
302 HRESULT NativeTheme::PaintMenuSeparator(HDC hdc,
303 int part_id,
304 int state_id,
305 RECT* rect) const {
306 HANDLE handle = GetThemeHandle(MENU);
307 if (handle && draw_theme_)
308 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
309 DrawEdge(hdc, rect, EDGE_ETCHED, BF_TOP);
310 return S_OK;
311 }
312
313 HRESULT NativeTheme::PaintScrollbarArrow(HDC hdc,
314 int state_id,
315 int classic_state,
316 RECT* rect) const {
317 HANDLE handle = GetThemeHandle(SCROLLBAR);
318 if (handle && draw_theme_)
319 return draw_theme_(handle, hdc, SBP_ARROWBTN, state_id, rect, NULL);
320
321 // Draw it manually.
322 DrawFrameControl(hdc, rect, DFC_SCROLL, classic_state);
323 return S_OK;
324 }
325
326 HRESULT NativeTheme::PaintScrollbarTrack(
327 HDC hdc,
328 int part_id,
329 int state_id,
330 int classic_state,
331 RECT* target_rect,
332 RECT* align_rect,
333 skia::PlatformCanvas* canvas) const {
334 HANDLE handle = GetThemeHandle(SCROLLBAR);
335 if (handle && draw_theme_)
336 return draw_theme_(handle, hdc, part_id, state_id, target_rect, NULL);
337
338 // Draw it manually.
339 const DWORD colorScrollbar = GetSysColor(COLOR_SCROLLBAR);
340 const DWORD color3DFace = GetSysColor(COLOR_3DFACE);
341 if ((colorScrollbar != color3DFace) &&
342 (colorScrollbar != GetSysColor(COLOR_WINDOW))) {
343 FillRect(hdc, target_rect, reinterpret_cast<HBRUSH>(COLOR_SCROLLBAR + 1));
344 } else {
345 SkPaint paint;
346 SetCheckerboardShader(&paint, *align_rect);
347 canvas->drawIRect(skia::RECTToSkIRect(*target_rect), paint);
348 }
349 if (classic_state & DFCS_PUSHED)
350 InvertRect(hdc, target_rect);
351 return S_OK;
352 }
353
354 HRESULT NativeTheme::PaintScrollbarThumb(HDC hdc,
355 int part_id,
356 int state_id,
357 int classic_state,
358 RECT* rect) const {
359 HANDLE handle = GetThemeHandle(SCROLLBAR);
360 if (handle && draw_theme_)
361 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
362
363 // Draw it manually.
364 if ((part_id == SBP_THUMBBTNHORZ) || (part_id == SBP_THUMBBTNVERT))
365 DrawEdge(hdc, rect, EDGE_RAISED, BF_RECT | BF_MIDDLE);
366 // Classic mode doesn't have a gripper.
367 return S_OK;
368 }
369
370 HRESULT NativeTheme::PaintStatusGripper(HDC hdc,
371 int part_id,
372 int state_id,
373 int classic_state,
374 RECT* rect) const {
375 HANDLE handle = GetThemeHandle(STATUS);
376 if (handle && draw_theme_) {
377 // Paint the status bar gripper. There doesn't seem to be a
378 // standard gripper in Windows for the space between
379 // scrollbars. This is pretty close, but it's supposed to be
380 // painted over a status bar.
381 return draw_theme_(handle, hdc, SP_GRIPPER, 0, rect, NULL);
382 }
383
384 // Draw a windows classic scrollbar gripper.
385 DrawFrameControl(hdc, rect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
386 return S_OK;
387 }
388
389 HRESULT NativeTheme::PaintTabPanelBackground(HDC hdc, RECT* rect) const {
390 HANDLE handle = GetThemeHandle(TAB);
391 if (handle && draw_theme_)
392 return draw_theme_(handle, hdc, TABP_BODY, 0, rect, NULL);
393
394 // Classic just renders a flat color background.
395 FillRect(hdc, rect, reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1));
396 return S_OK;
397 }
398
399 HRESULT NativeTheme::PaintTrackbar(HDC hdc,
400 int part_id,
401 int state_id,
402 int classic_state,
403 RECT* rect,
404 skia::PlatformCanvas* canvas) const {
405 // Make the channel be 4 px thick in the center of the supplied rect. (4 px
406 // matches what XP does in various menus; GetThemePartSize() doesn't seem to
407 // return good values here.)
408 RECT channel_rect = *rect;
409 const int channel_thickness = 4;
410 if (part_id == TKP_TRACK) {
411 channel_rect.top +=
412 ((channel_rect.bottom - channel_rect.top - channel_thickness) / 2);
413 channel_rect.bottom = channel_rect.top + channel_thickness;
414 } else if (part_id == TKP_TRACKVERT) {
415 channel_rect.left +=
416 ((channel_rect.right - channel_rect.left - channel_thickness) / 2);
417 channel_rect.right = channel_rect.left + channel_thickness;
418 } // else this isn't actually a channel, so |channel_rect| == |rect|.
419
420 HANDLE handle = GetThemeHandle(TRACKBAR);
421 if (handle && draw_theme_)
422 return draw_theme_(handle, hdc, part_id, state_id, &channel_rect, NULL);
423
424 // Classic mode, draw it manually.
425 if ((part_id == TKP_TRACK) || (part_id == TKP_TRACKVERT)) {
426 DrawEdge(hdc, &channel_rect, EDGE_SUNKEN, BF_RECT);
427 } else if (part_id == TKP_THUMBVERT) {
428 DrawEdge(hdc, rect, EDGE_RAISED, BF_RECT | BF_SOFT | BF_MIDDLE);
429 } else {
430 // Split rect into top and bottom pieces.
431 RECT top_section = *rect;
432 RECT bottom_section = *rect;
433 top_section.bottom -= ((bottom_section.right - bottom_section.left) / 2);
434 bottom_section.top = top_section.bottom;
435 DrawEdge(hdc, &top_section, EDGE_RAISED,
436 BF_LEFT | BF_TOP | BF_RIGHT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
437
438 // Split triangular piece into two diagonals.
439 RECT& left_half = bottom_section;
440 RECT right_half = bottom_section;
441 right_half.left += ((bottom_section.right - bottom_section.left) / 2);
442 left_half.right = right_half.left;
443 DrawEdge(hdc, &left_half, EDGE_RAISED,
444 BF_DIAGONAL_ENDTOPLEFT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
445 DrawEdge(hdc, &right_half, EDGE_RAISED,
446 BF_DIAGONAL_ENDBOTTOMLEFT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
447
448 // If the button is pressed, draw hatching.
449 if (classic_state & DFCS_PUSHED) {
450 SkPaint paint;
451 SetCheckerboardShader(&paint, *rect);
452
453 // Fill all three pieces with the pattern.
454 canvas->drawIRect(skia::RECTToSkIRect(top_section), paint);
455
456 SkScalar left_triangle_top = SkIntToScalar(left_half.top);
457 SkScalar left_triangle_right = SkIntToScalar(left_half.right);
458 SkPath left_triangle;
459 left_triangle.moveTo(SkIntToScalar(left_half.left), left_triangle_top);
460 left_triangle.lineTo(left_triangle_right, left_triangle_top);
461 left_triangle.lineTo(left_triangle_right,
462 SkIntToScalar(left_half.bottom));
463 left_triangle.close();
464 canvas->drawPath(left_triangle, paint);
465
466 SkScalar right_triangle_left = SkIntToScalar(right_half.left);
467 SkScalar right_triangle_top = SkIntToScalar(right_half.top);
468 SkPath right_triangle;
469 right_triangle.moveTo(right_triangle_left, right_triangle_top);
470 right_triangle.lineTo(SkIntToScalar(right_half.right),
471 right_triangle_top);
472 right_triangle.lineTo(right_triangle_left,
473 SkIntToScalar(right_half.bottom));
474 right_triangle.close();
475 canvas->drawPath(right_triangle, paint);
476 }
477 }
478 return S_OK;
479 }
480
481 HRESULT NativeTheme::PaintTextField(HDC hdc,
482 int part_id,
483 int state_id,
484 int classic_state,
485 RECT* rect,
486 COLORREF color,
487 bool fill_content_area,
488 bool draw_edges) const {
489 // TODO(ojan): http://b/1210017 Figure out how to give the ability to
490 // exclude individual edges from being drawn.
491
492 HANDLE handle = GetThemeHandle(TEXTFIELD);
493 // TODO(mpcomplete): can we detect if the color is specified by the user,
494 // and if not, just use the system color?
495 // CreateSolidBrush() accepts a RGB value but alpha must be 0.
496 HBRUSH bg_brush = CreateSolidBrush(color);
497 HRESULT hr;
498 // DrawThemeBackgroundEx was introduced in XP SP2, so that it's possible
499 // draw_theme_ex_ is NULL and draw_theme_ is non-null.
500 if (handle && (draw_theme_ex_ || (draw_theme_ && draw_edges))) {
501 if (draw_theme_ex_) {
502 static DTBGOPTS omit_border_options = {
503 sizeof(DTBGOPTS),
504 DTBG_OMITBORDER,
505 {0,0,0,0}
506 };
507 DTBGOPTS* draw_opts = draw_edges ? NULL : &omit_border_options;
508 hr = draw_theme_ex_(handle, hdc, part_id, state_id, rect, draw_opts);
509 } else {
510 hr = draw_theme_(handle, hdc, part_id, state_id, rect, NULL);
511 }
512
513 // TODO(maruel): Need to be fixed if get_theme_content_rect_ is NULL.
514 if (fill_content_area && get_theme_content_rect_) {
515 RECT content_rect;
516 hr = get_theme_content_rect_(handle, hdc, part_id, state_id, rect,
517 &content_rect);
518 FillRect(hdc, &content_rect, bg_brush);
519 }
520 } else {
521 // Draw it manually.
522 if (draw_edges)
523 DrawEdge(hdc, rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
524
525 if (fill_content_area) {
526 FillRect(hdc, rect, (classic_state & DFCS_INACTIVE) ?
527 reinterpret_cast<HBRUSH>(COLOR_BTNFACE + 1) : bg_brush);
528 }
529 hr = S_OK;
530 }
531 DeleteObject(bg_brush);
532 return hr;
533 }
534
535 bool NativeTheme::IsThemingActive() const {
536 if (is_theme_active_)
537 return !!is_theme_active_();
538 return false;
539 }
540
541 HRESULT NativeTheme::GetThemePartSize(ThemeName theme_name,
542 HDC hdc,
543 int part_id,
544 int state_id,
545 RECT* rect,
546 int ts,
547 SIZE* size) const {
548 HANDLE handle = GetThemeHandle(theme_name);
549 if (handle && get_theme_part_size_)
550 return get_theme_part_size_(handle, hdc, part_id, state_id, rect, ts, size);
551
552 return E_NOTIMPL;
553 }
554
555 HRESULT NativeTheme::GetThemeColor(ThemeName theme,
556 int part_id,
557 int state_id,
558 int prop_id,
559 SkColor* color) const {
560 HANDLE handle = GetThemeHandle(theme);
561 if (handle && get_theme_color_) {
562 COLORREF color_ref;
563 if (get_theme_color_(handle, part_id, state_id, prop_id, &color_ref) ==
564 S_OK) {
565 *color = skia::COLORREFToSkColor(color_ref);
566 return S_OK;
567 }
568 }
569 return E_NOTIMPL;
570 }
571
572 SkColor NativeTheme::GetThemeColorWithDefault(ThemeName theme,
573 int part_id,
574 int state_id,
575 int prop_id,
576 int default_sys_color) const {
577 SkColor color;
578 if (GetThemeColor(theme, part_id, state_id, prop_id, &color) != S_OK)
579 color = skia::COLORREFToSkColor(GetSysColor(default_sys_color));
580 return color;
581 }
582
583 HRESULT NativeTheme::GetThemeInt(ThemeName theme,
584 int part_id,
585 int state_id,
586 int prop_id,
587 int *value) const {
588 HANDLE handle = GetThemeHandle(theme);
589 if (handle && get_theme_int_)
590 return get_theme_int_(handle, part_id, state_id, prop_id, value);
591 return E_NOTIMPL;
592 }
593
594 Size NativeTheme::GetThemeBorderSize(ThemeName theme) const {
595 // For simplicity use the wildcard state==0, part==0, since it works
596 // for the cases we currently depend on.
597 int border;
598 if (GetThemeInt(theme, 0, 0, TMT_BORDERSIZE, &border) == S_OK)
599 return Size(border, border);
600 else
601 return Size(GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
602 }
603
604
605 void NativeTheme::DisableTheming() const {
606 if (!set_theme_properties_)
607 return;
608 set_theme_properties_(0);
609 }
610
611 HRESULT NativeTheme::PaintFrameControl(HDC hdc,
612 RECT* rect,
613 UINT type,
614 UINT state,
615 bool is_highlighted) const {
616 const int width = rect->right - rect->left;
617 const int height = rect->bottom - rect->top;
618
619 // DrawFrameControl for menu arrow/check wants a monochrome bitmap.
620 ScopedBitmap mask_bitmap(CreateBitmap(width, height, 1, 1, NULL));
621
622 if (mask_bitmap == NULL)
623 return E_OUTOFMEMORY;
624
625 ScopedHDC bitmap_dc(CreateCompatibleDC(NULL));
626 HGDIOBJ org_bitmap = SelectObject(bitmap_dc, mask_bitmap);
627 RECT local_rect = { 0, 0, width, height };
628 DrawFrameControl(bitmap_dc, &local_rect, type, state);
629
630 // We're going to use BitBlt with a b&w mask. This results in using the dest
631 // dc's text color for the black bits in the mask, and the dest dc's
632 // background color for the white bits in the mask. DrawFrameControl draws the
633 // check in black, and the background in white.
634 COLORREF old_bg_color =
635 SetBkColor(hdc,
636 GetSysColor(is_highlighted ? COLOR_HIGHLIGHT : COLOR_MENU));
637 COLORREF old_text_color =
638 SetTextColor(hdc,
639 GetSysColor(is_highlighted ? COLOR_HIGHLIGHTTEXT :
640 COLOR_MENUTEXT));
641 BitBlt(hdc, rect->left, rect->top, width, height, bitmap_dc, 0, 0, SRCCOPY);
642 SetBkColor(hdc, old_bg_color);
643 SetTextColor(hdc, old_text_color);
644
645 SelectObject(bitmap_dc, org_bitmap);
646
647 return S_OK;
648 }
649
650 void NativeTheme::CloseHandles() const
651 {
652 if (!close_theme_)
653 return;
654
655 for (int i = 0; i < LAST; ++i) {
656 if (theme_handles_[i])
657 close_theme_(theme_handles_[i]);
658 theme_handles_[i] = NULL;
659 }
660 }
661
662 HANDLE NativeTheme::GetThemeHandle(ThemeName theme_name) const
663 {
664 if (!open_theme_ || theme_name < 0 || theme_name >= LAST)
665 return 0;
666
667 if (theme_handles_[theme_name])
668 return theme_handles_[theme_name];
669
670 // Not found, try to load it.
671 HANDLE handle = 0;
672 switch (theme_name) {
673 case BUTTON:
674 handle = open_theme_(NULL, L"Button");
675 break;
676 case LIST:
677 handle = open_theme_(NULL, L"Listview");
678 break;
679 case MENU:
680 handle = open_theme_(NULL, L"Menu");
681 break;
682 case MENULIST:
683 handle = open_theme_(NULL, L"Combobox");
684 break;
685 case SCROLLBAR:
686 handle = open_theme_(NULL, L"Scrollbar");
687 break;
688 case STATUS:
689 handle = open_theme_(NULL, L"Status");
690 break;
691 case TAB:
692 handle = open_theme_(NULL, L"Tab");
693 break;
694 case TEXTFIELD:
695 handle = open_theme_(NULL, L"Edit");
696 break;
697 case TRACKBAR:
698 handle = open_theme_(NULL, L"Trackbar");
699 break;
700 case WINDOW:
701 handle = open_theme_(NULL, L"Window");
702 break;
703 default:
704 NOTREACHED();
705 }
706 theme_handles_[theme_name] = handle;
707 return handle;
708 }
709
710 } // namespace gfx
OLDNEW
« no previous file with comments | « base/gfx/native_theme.h ('k') | base/gfx/native_theme_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698