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_win.h" 6 7#include <windows.h> 8#include <uxtheme.h> 9#include <vsstyle.h> 10#include <vssym32.h> 11 12#include "base/basictypes.h" 13#include "base/logging.h" 14#include "base/memory/scoped_ptr.h" 15#include "base/win/scoped_gdi_object.h" 16#include "base/win/scoped_hdc.h" 17#include "base/win/scoped_select_object.h" 18#include "base/win/windows_version.h" 19#include "skia/ext/bitmap_platform_device.h" 20#include "skia/ext/platform_canvas.h" 21#include "skia/ext/skia_utils_win.h" 22#include "third_party/skia/include/core/SkCanvas.h" 23#include "third_party/skia/include/core/SkColorPriv.h" 24#include "third_party/skia/include/core/SkShader.h" 25#include "ui/gfx/color_utils.h" 26#include "ui/gfx/gdi_util.h" 27#include "ui/gfx/rect.h" 28#include "ui/gfx/rect_conversions.h" 29#include "ui/gfx/win/dpi.h" 30#include "ui/native_theme/common_theme.h" 31 32// This was removed from Winvers.h but is still used. 33#if !defined(COLOR_MENUHIGHLIGHT) 34#define COLOR_MENUHIGHLIGHT 29 35#endif 36 37namespace { 38 39// TODO: Obtain the correct colors using GetSysColor. 40// Theme colors returned by GetSystemColor(). 41const SkColor kInvalidColorIdColor = SkColorSetRGB(255, 0, 128); 42// Dialogs: 43const SkColor kDialogBackgroundColor = SkColorSetRGB(251, 251, 251); 44// FocusableBorder: 45const SkColor kFocusedBorderColor = SkColorSetRGB(0x4d, 0x90, 0xfe); 46const SkColor kUnfocusedBorderColor = SkColorSetRGB(0xd9, 0xd9, 0xd9); 47// Button: 48const SkColor kButtonBackgroundColor = SkColorSetRGB(0xde, 0xde, 0xde); 49const SkColor kButtonHighlightColor = SkColorSetARGB(200, 255, 255, 255); 50const SkColor kButtonHoverColor = SkColorSetRGB(6, 45, 117); 51const SkColor kButtonHoverBackgroundColor = SkColorSetRGB(0xEA, 0xEA, 0xEA); 52// MenuItem: 53const SkColor kEnabledMenuItemForegroundColor = SkColorSetRGB(6, 45, 117); 54const SkColor kDisabledMenuItemForegroundColor = SkColorSetRGB(161, 161, 146); 55const SkColor kFocusedMenuItemBackgroundColor = SkColorSetRGB(246, 249, 253); 56const SkColor kMenuSeparatorColor = SkColorSetARGB(50, 0, 0, 0); 57// Table: 58const SkColor kTreeSelectionBackgroundUnfocused = SkColorSetRGB(240, 240, 240); 59 60// Windows system color IDs cached and updated by the native theme. 61const int kSystemColors[] = { 62 COLOR_3DFACE, 63 COLOR_BTNTEXT, 64 COLOR_GRAYTEXT, 65 COLOR_HIGHLIGHT, 66 COLOR_HIGHLIGHTTEXT, 67 COLOR_SCROLLBAR, 68 COLOR_WINDOW, 69 COLOR_WINDOWTEXT, 70 COLOR_BTNFACE, 71 COLOR_MENUHIGHLIGHT, 72}; 73 74void SetCheckerboardShader(SkPaint* paint, const RECT& align_rect) { 75 // Create a 2x2 checkerboard pattern using the 3D face and highlight colors. 76 const SkColor face = color_utils::GetSysSkColor(COLOR_3DFACE); 77 const SkColor highlight = color_utils::GetSysSkColor(COLOR_3DHILIGHT); 78 SkColor buffer[] = { face, highlight, highlight, face }; 79 // Confusing bit: we first create a temporary bitmap with our desired pattern, 80 // then copy it to another bitmap. The temporary bitmap doesn't take 81 // ownership of the pixel data, and so will point to garbage when this 82 // function returns. The copy will copy the pixel data into a place owned by 83 // the bitmap, which is in turn owned by the shader, etc., so it will live 84 // until we're done using it. 85 SkImageInfo info = SkImageInfo::MakeN32Premul(2, 2); 86 SkBitmap temp_bitmap; 87 temp_bitmap.installPixels(info, buffer, info.minRowBytes()); 88 SkBitmap bitmap; 89 temp_bitmap.copyTo(&bitmap); 90 91 // Align the pattern with the upper corner of |align_rect|. 92 SkMatrix local_matrix; 93 local_matrix.setTranslate(SkIntToScalar(align_rect.left), 94 SkIntToScalar(align_rect.top)); 95 skia::RefPtr<SkShader> shader = 96 skia::AdoptRef(SkShader::CreateBitmapShader(bitmap, 97 SkShader::kRepeat_TileMode, 98 SkShader::kRepeat_TileMode, 99 &local_matrix)); 100 paint->setShader(shader.get()); 101} 102 103// <-a-> 104// [ ***** ] 105// ____ | | 106// <-a-> <------b-----> 107// a: object_width 108// b: frame_width 109// *: animating object 110// 111// - the animation goes from "[" to "]" repeatedly. 112// - the animation offset is at first "|" 113// 114int ComputeAnimationProgress(int frame_width, 115 int object_width, 116 int pixels_per_second, 117 double animated_seconds) { 118 int animation_width = frame_width + object_width; 119 double interval = static_cast<double>(animation_width) / pixels_per_second; 120 double ratio = fmod(animated_seconds, interval) / interval; 121 return static_cast<int>(animation_width * ratio) - object_width; 122} 123 124RECT InsetRect(const RECT* rect, int size) { 125 gfx::Rect result(*rect); 126 result.Inset(size, size); 127 return result.ToRECT(); 128} 129 130} // namespace 131 132namespace ui { 133 134bool NativeThemeWin::IsThemingActive() const { 135 return is_theme_active_ && is_theme_active_(); 136} 137 138bool NativeThemeWin::IsUsingHighContrastTheme() const { 139 if (is_using_high_contrast_valid_) 140 return is_using_high_contrast_; 141 HIGHCONTRAST result; 142 result.cbSize = sizeof(HIGHCONTRAST); 143 is_using_high_contrast_ = 144 SystemParametersInfo(SPI_GETHIGHCONTRAST, result.cbSize, &result, 0) && 145 (result.dwFlags & HCF_HIGHCONTRASTON) == HCF_HIGHCONTRASTON; 146 is_using_high_contrast_valid_ = true; 147 return is_using_high_contrast_; 148} 149 150HRESULT NativeThemeWin::GetThemeColor(ThemeName theme, 151 int part_id, 152 int state_id, 153 int prop_id, 154 SkColor* color) const { 155 HANDLE handle = GetThemeHandle(theme); 156 if (!handle || !get_theme_color_) 157 return E_NOTIMPL; 158 COLORREF color_ref; 159 if (get_theme_color_(handle, part_id, state_id, prop_id, &color_ref) != S_OK) 160 return E_NOTIMPL; 161 *color = skia::COLORREFToSkColor(color_ref); 162 return S_OK; 163} 164 165SkColor NativeThemeWin::GetThemeColorWithDefault(ThemeName theme, 166 int part_id, 167 int state_id, 168 int prop_id, 169 int default_sys_color) const { 170 SkColor color; 171 return (GetThemeColor(theme, part_id, state_id, prop_id, &color) == S_OK) ? 172 color : color_utils::GetSysSkColor(default_sys_color); 173} 174 175gfx::Size NativeThemeWin::GetThemeBorderSize(ThemeName theme) const { 176 // For simplicity use the wildcard state==0, part==0, since it works 177 // for the cases we currently depend on. 178 int border; 179 return (GetThemeInt(theme, 0, 0, TMT_BORDERSIZE, &border) == S_OK) ? 180 gfx::Size(border, border) : 181 gfx::Size(GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE)); 182} 183 184void NativeThemeWin::DisableTheming() const { 185 if (set_theme_properties_) 186 set_theme_properties_(0); 187} 188 189void NativeThemeWin::CloseHandles() const { 190 if (!close_theme_) 191 return; 192 193 for (int i = 0; i < LAST; ++i) { 194 if (theme_handles_[i]) { 195 close_theme_(theme_handles_[i]); 196 theme_handles_[i] = NULL; 197 } 198 } 199} 200 201bool NativeThemeWin::IsClassicTheme(ThemeName name) const { 202 return !theme_dll_ || !GetThemeHandle(name); 203} 204 205// static 206NativeThemeWin* NativeThemeWin::instance() { 207 CR_DEFINE_STATIC_LOCAL(NativeThemeWin, s_native_theme, ()); 208 return &s_native_theme; 209} 210 211gfx::Size NativeThemeWin::GetPartSize(Part part, 212 State state, 213 const ExtraParams& extra) const { 214 gfx::Size part_size = CommonThemeGetPartSize(part, state, extra); 215 if (!part_size.IsEmpty()) 216 return part_size; 217 218 // The GetThemePartSize call below returns the default size without 219 // accounting for user customization (crbug/218291). 220 switch (part) { 221 case kScrollbarDownArrow: 222 case kScrollbarLeftArrow: 223 case kScrollbarRightArrow: 224 case kScrollbarUpArrow: 225 case kScrollbarHorizontalThumb: 226 case kScrollbarVerticalThumb: 227 case kScrollbarHorizontalTrack: 228 case kScrollbarVerticalTrack: { 229 int size = gfx::win::GetSystemMetricsInDIP(SM_CXVSCROLL); 230 if (size == 0) 231 size = 17; 232 return gfx::Size(size, size); 233 } 234 default: 235 break; 236 } 237 238 int part_id = GetWindowsPart(part, state, extra); 239 int state_id = GetWindowsState(part, state, extra); 240 241 base::win::ScopedGetDC screen_dc(NULL); 242 SIZE size; 243 if (SUCCEEDED(GetThemePartSize(GetThemeName(part), screen_dc, part_id, 244 state_id, NULL, TS_TRUE, &size))) 245 return gfx::Size(size.cx, size.cy); 246 247 // TODO(rogerta): For now, we need to support radio buttons and checkboxes 248 // when theming is not enabled. Support for other parts can be added 249 // if/when needed. 250 return (part == kCheckbox || part == kRadio) ? 251 gfx::Size(13, 13) : gfx::Size(); 252} 253 254void NativeThemeWin::Paint(SkCanvas* canvas, 255 Part part, 256 State state, 257 const gfx::Rect& rect, 258 const ExtraParams& extra) const { 259 if (rect.IsEmpty()) 260 return; 261 262 switch (part) { 263 case kComboboxArrow: 264 CommonThemePaintComboboxArrow(canvas, rect); 265 return; 266 case kMenuPopupGutter: 267 CommonThemePaintMenuGutter(canvas, rect); 268 return; 269 case kMenuPopupSeparator: 270 CommonThemePaintMenuSeparator(canvas, rect, extra.menu_separator); 271 return; 272 case kMenuPopupBackground: 273 CommonThemePaintMenuBackground(canvas, rect); 274 return; 275 case kMenuItemBackground: 276 CommonThemePaintMenuItemBackground(canvas, state, rect); 277 return; 278 default: 279 break; 280 } 281 282 bool needs_paint_indirect = false; 283 if (!skia::SupportsPlatformPaint(canvas)) { 284 // This block will only get hit with --enable-accelerated-drawing flag. 285 needs_paint_indirect = true; 286 } else { 287 // Scrollbar components on Windows Classic theme (on all Windows versions) 288 // have particularly problematic alpha values, so always draw them 289 // indirectly. In addition, scrollbar thumbs and grippers for the Windows XP 290 // theme (available only on Windows XP) also need their alpha values 291 // fixed. 292 switch (part) { 293 case kScrollbarDownArrow: 294 case kScrollbarUpArrow: 295 case kScrollbarLeftArrow: 296 case kScrollbarRightArrow: 297 needs_paint_indirect = !GetThemeHandle(SCROLLBAR); 298 break; 299 case kScrollbarHorizontalThumb: 300 case kScrollbarVerticalThumb: 301 case kScrollbarHorizontalGripper: 302 case kScrollbarVerticalGripper: 303 needs_paint_indirect = !GetThemeHandle(SCROLLBAR) || 304 base::win::GetVersion() == base::win::VERSION_XP; 305 break; 306 default: 307 break; 308 } 309 } 310 311 if (needs_paint_indirect) 312 PaintIndirect(canvas, part, state, rect, extra); 313 else 314 PaintDirect(canvas, part, state, rect, extra); 315} 316 317NativeThemeWin::NativeThemeWin() 318 : theme_dll_(LoadLibrary(L"uxtheme.dll")), 319 draw_theme_(NULL), 320 draw_theme_ex_(NULL), 321 get_theme_color_(NULL), 322 get_theme_content_rect_(NULL), 323 get_theme_part_size_(NULL), 324 open_theme_(NULL), 325 close_theme_(NULL), 326 set_theme_properties_(NULL), 327 is_theme_active_(NULL), 328 get_theme_int_(NULL), 329 color_change_listener_(this), 330 is_using_high_contrast_(false), 331 is_using_high_contrast_valid_(false) { 332 if (theme_dll_) { 333 draw_theme_ = reinterpret_cast<DrawThemeBackgroundPtr>( 334 GetProcAddress(theme_dll_, "DrawThemeBackground")); 335 draw_theme_ex_ = reinterpret_cast<DrawThemeBackgroundExPtr>( 336 GetProcAddress(theme_dll_, "DrawThemeBackgroundEx")); 337 get_theme_color_ = reinterpret_cast<GetThemeColorPtr>( 338 GetProcAddress(theme_dll_, "GetThemeColor")); 339 get_theme_content_rect_ = reinterpret_cast<GetThemeContentRectPtr>( 340 GetProcAddress(theme_dll_, "GetThemeBackgroundContentRect")); 341 get_theme_part_size_ = reinterpret_cast<GetThemePartSizePtr>( 342 GetProcAddress(theme_dll_, "GetThemePartSize")); 343 open_theme_ = reinterpret_cast<OpenThemeDataPtr>( 344 GetProcAddress(theme_dll_, "OpenThemeData")); 345 close_theme_ = reinterpret_cast<CloseThemeDataPtr>( 346 GetProcAddress(theme_dll_, "CloseThemeData")); 347 set_theme_properties_ = reinterpret_cast<SetThemeAppPropertiesPtr>( 348 GetProcAddress(theme_dll_, "SetThemeAppProperties")); 349 is_theme_active_ = reinterpret_cast<IsThemeActivePtr>( 350 GetProcAddress(theme_dll_, "IsThemeActive")); 351 get_theme_int_ = reinterpret_cast<GetThemeIntPtr>( 352 GetProcAddress(theme_dll_, "GetThemeInt")); 353 } 354 memset(theme_handles_, 0, sizeof(theme_handles_)); 355 356 // Initialize the cached system colors. 357 UpdateSystemColors(); 358} 359 360NativeThemeWin::~NativeThemeWin() { 361 if (theme_dll_) { 362 // todo (cpu): fix this soon. Making a call to CloseHandles() here breaks 363 // certain tests and the reliability bots. 364 // CloseHandles(); 365 FreeLibrary(theme_dll_); 366 } 367} 368 369void NativeThemeWin::OnSysColorChange() { 370 UpdateSystemColors(); 371 is_using_high_contrast_valid_ = false; 372 NotifyObservers(); 373} 374 375void NativeThemeWin::UpdateSystemColors() { 376 for (int i = 0; i < arraysize(kSystemColors); ++i) { 377 system_colors_[kSystemColors[i]] = 378 color_utils::GetSysSkColor(kSystemColors[i]); 379 } 380} 381 382void NativeThemeWin::PaintDirect(SkCanvas* canvas, 383 Part part, 384 State state, 385 const gfx::Rect& rect, 386 const ExtraParams& extra) const { 387 skia::ScopedPlatformPaint scoped_platform_paint(canvas); 388 HDC hdc = scoped_platform_paint.GetPlatformSurface(); 389 390 switch (part) { 391 case kCheckbox: 392 PaintCheckbox(hdc, part, state, rect, extra.button); 393 return; 394 case kInnerSpinButton: 395 PaintSpinButton(hdc, part, state, rect, extra.inner_spin); 396 return; 397 case kMenuList: 398 PaintMenuList(hdc, state, rect, extra.menu_list); 399 return; 400 case kMenuCheck: 401 PaintMenuCheck(hdc, state, rect, extra.menu_check); 402 return; 403 case kMenuCheckBackground: 404 PaintMenuCheckBackground(hdc, state, rect); 405 return; 406 case kMenuPopupArrow: 407 PaintMenuArrow(hdc, state, rect, extra.menu_arrow); 408 return; 409 case kMenuPopupBackground: 410 PaintMenuBackground(hdc, rect); 411 return; 412 case kMenuPopupGutter: 413 PaintMenuGutter(hdc, rect); 414 return; 415 case kMenuPopupSeparator: 416 PaintMenuSeparator(hdc, rect, extra.menu_separator); 417 return; 418 case kMenuItemBackground: 419 PaintMenuItemBackground(hdc, state, rect, extra.menu_item); 420 return; 421 case kProgressBar: 422 PaintProgressBar(hdc, rect, extra.progress_bar); 423 return; 424 case kPushButton: 425 PaintPushButton(hdc, part, state, rect, extra.button); 426 return; 427 case kRadio: 428 PaintRadioButton(hdc, part, state, rect, extra.button); 429 return; 430 case kScrollbarDownArrow: 431 case kScrollbarUpArrow: 432 case kScrollbarLeftArrow: 433 case kScrollbarRightArrow: 434 PaintScrollbarArrow(hdc, part, state, rect, extra.scrollbar_arrow); 435 return; 436 case kScrollbarHorizontalThumb: 437 case kScrollbarVerticalThumb: 438 case kScrollbarHorizontalGripper: 439 case kScrollbarVerticalGripper: 440 PaintScrollbarThumb(hdc, part, state, rect, extra.scrollbar_thumb); 441 return; 442 case kScrollbarHorizontalTrack: 443 case kScrollbarVerticalTrack: 444 PaintScrollbarTrack(canvas, hdc, part, state, rect, 445 extra.scrollbar_track); 446 return; 447 case kScrollbarCorner: 448 canvas->drawColor(SK_ColorWHITE, SkXfermode::kSrc_Mode); 449 return; 450 case kTabPanelBackground: 451 PaintTabPanelBackground(hdc, rect); 452 return; 453 case kTextField: 454 PaintTextField(hdc, part, state, rect, extra.text_field); 455 return; 456 case kTrackbarThumb: 457 case kTrackbarTrack: 458 PaintTrackbar(canvas, hdc, part, state, rect, extra.trackbar); 459 return; 460 case kWindowResizeGripper: 461 PaintWindowResizeGripper(hdc, rect); 462 return; 463 case kComboboxArrow: 464 case kSliderTrack: 465 case kSliderThumb: 466 case kMaxPart: 467 NOTREACHED(); 468 } 469} 470 471SkColor NativeThemeWin::GetSystemColor(ColorId color_id) const { 472 SkColor color; 473 if (CommonThemeGetSystemColor(color_id, &color)) 474 return color; 475 476 switch (color_id) { 477 // Windows 478 case kColorId_WindowBackground: 479 return system_colors_[COLOR_WINDOW]; 480 481 // Dialogs 482 case kColorId_DialogBackground: 483 return gfx::IsInvertedColorScheme() ? 484 color_utils::InvertColor(kDialogBackgroundColor) : 485 kDialogBackgroundColor; 486 487 // FocusableBorder 488 case kColorId_FocusedBorderColor: 489 return kFocusedBorderColor; 490 case kColorId_UnfocusedBorderColor: 491 return kUnfocusedBorderColor; 492 493 // Button 494 case kColorId_ButtonBackgroundColor: 495 return kButtonBackgroundColor; 496 case kColorId_ButtonEnabledColor: 497 return system_colors_[COLOR_BTNTEXT]; 498 case kColorId_ButtonDisabledColor: 499 return system_colors_[COLOR_GRAYTEXT]; 500 case kColorId_ButtonHighlightColor: 501 return kButtonHighlightColor; 502 case kColorId_ButtonHoverColor: 503 return kButtonHoverColor; 504 case kColorId_ButtonHoverBackgroundColor: 505 return kButtonHoverBackgroundColor; 506 case kColorId_BlueButtonEnabledColor: 507 case kColorId_BlueButtonDisabledColor: 508 case kColorId_BlueButtonPressedColor: 509 case kColorId_BlueButtonHoverColor: 510 NOTREACHED(); 511 return kInvalidColorIdColor; 512 513 // MenuItem 514 case kColorId_EnabledMenuItemForegroundColor: 515 return kEnabledMenuItemForegroundColor; 516 case kColorId_DisabledMenuItemForegroundColor: 517 return kDisabledMenuItemForegroundColor; 518 case kColorId_DisabledEmphasizedMenuItemForegroundColor: 519 return SK_ColorBLACK; 520 case kColorId_FocusedMenuItemBackgroundColor: 521 return kFocusedMenuItemBackgroundColor; 522 case kColorId_MenuSeparatorColor: 523 return kMenuSeparatorColor; 524 case kColorId_SelectedMenuItemForegroundColor: 525 case kColorId_HoverMenuItemBackgroundColor: 526 case kColorId_MenuBackgroundColor: 527 case kColorId_MenuBorderColor: 528 NOTREACHED(); 529 return kInvalidColorIdColor; 530 531 // MenuButton 532 case kColorId_EnabledMenuButtonBorderColor: 533 case kColorId_FocusedMenuButtonBorderColor: 534 case kColorId_HoverMenuButtonBorderColor: 535 NOTREACHED(); 536 return kInvalidColorIdColor; 537 538 // Label 539 case kColorId_LabelEnabledColor: 540 return system_colors_[COLOR_BTNTEXT]; 541 case kColorId_LabelDisabledColor: 542 return system_colors_[COLOR_GRAYTEXT]; 543 case kColorId_LabelBackgroundColor: 544 return system_colors_[COLOR_WINDOW]; 545 546 // Textfield 547 case kColorId_TextfieldDefaultColor: 548 return system_colors_[COLOR_WINDOWTEXT]; 549 case kColorId_TextfieldDefaultBackground: 550 return system_colors_[COLOR_WINDOW]; 551 case kColorId_TextfieldReadOnlyColor: 552 return system_colors_[COLOR_GRAYTEXT]; 553 case kColorId_TextfieldReadOnlyBackground: 554 return system_colors_[COLOR_3DFACE]; 555 case kColorId_TextfieldSelectionColor: 556 return system_colors_[COLOR_HIGHLIGHTTEXT]; 557 case kColorId_TextfieldSelectionBackgroundFocused: 558 return system_colors_[COLOR_HIGHLIGHT]; 559 560 // Tooltip 561 case kColorId_TooltipBackground: 562 case kColorId_TooltipText: 563 NOTREACHED(); 564 return kInvalidColorIdColor; 565 566 // Tree 567 // NOTE: these aren't right for all themes, but as close as I could get. 568 case kColorId_TreeBackground: 569 return system_colors_[COLOR_WINDOW]; 570 case kColorId_TreeText: 571 return system_colors_[COLOR_WINDOWTEXT]; 572 case kColorId_TreeSelectedText: 573 return system_colors_[COLOR_HIGHLIGHTTEXT]; 574 case kColorId_TreeSelectedTextUnfocused: 575 return system_colors_[COLOR_BTNTEXT]; 576 case kColorId_TreeSelectionBackgroundFocused: 577 return system_colors_[COLOR_HIGHLIGHT]; 578 case kColorId_TreeSelectionBackgroundUnfocused: 579 return system_colors_[IsUsingHighContrastTheme() ? 580 COLOR_MENUHIGHLIGHT : COLOR_BTNFACE]; 581 case kColorId_TreeArrow: 582 return system_colors_[COLOR_WINDOWTEXT]; 583 584 // Table 585 case kColorId_TableBackground: 586 return system_colors_[COLOR_WINDOW]; 587 case kColorId_TableText: 588 return system_colors_[COLOR_WINDOWTEXT]; 589 case kColorId_TableSelectedText: 590 return system_colors_[COLOR_HIGHLIGHTTEXT]; 591 case kColorId_TableSelectedTextUnfocused: 592 return system_colors_[COLOR_BTNTEXT]; 593 case kColorId_TableSelectionBackgroundFocused: 594 return system_colors_[COLOR_HIGHLIGHT]; 595 case kColorId_TableSelectionBackgroundUnfocused: 596 return system_colors_[IsUsingHighContrastTheme() ? 597 COLOR_MENUHIGHLIGHT : COLOR_BTNFACE]; 598 case kColorId_TableGroupingIndicatorColor: 599 return system_colors_[COLOR_GRAYTEXT]; 600 601 // Results Tables 602 case kColorId_ResultsTableNormalBackground: 603 return system_colors_[COLOR_WINDOW]; 604 case kColorId_ResultsTableHoveredBackground: 605 return color_utils::AlphaBlend(system_colors_[COLOR_HIGHLIGHT], 606 system_colors_[COLOR_WINDOW], 0x40); 607 case kColorId_ResultsTableSelectedBackground: 608 return system_colors_[COLOR_HIGHLIGHT]; 609 case kColorId_ResultsTableNormalText: 610 case kColorId_ResultsTableHoveredText: 611 return system_colors_[COLOR_WINDOWTEXT]; 612 case kColorId_ResultsTableSelectedText: 613 return system_colors_[COLOR_HIGHLIGHTTEXT]; 614 case kColorId_ResultsTableNormalDimmedText: 615 return color_utils::AlphaBlend(system_colors_[COLOR_WINDOWTEXT], 616 system_colors_[COLOR_WINDOW], 0x80); 617 case kColorId_ResultsTableHoveredDimmedText: 618 return color_utils::AlphaBlend( 619 system_colors_[COLOR_WINDOWTEXT], 620 GetSystemColor(kColorId_ResultsTableHoveredBackground), 0x80); 621 case kColorId_ResultsTableSelectedDimmedText: 622 return color_utils::AlphaBlend(system_colors_[COLOR_HIGHLIGHTTEXT], 623 system_colors_[COLOR_HIGHLIGHT], 0x80); 624 case kColorId_ResultsTableNormalUrl: 625 return color_utils::GetReadableColor(SkColorSetRGB(0, 128, 0), 626 system_colors_[COLOR_WINDOW]); 627 case kColorId_ResultsTableHoveredUrl: 628 return color_utils::GetReadableColor( 629 SkColorSetRGB(0, 128, 0), 630 GetSystemColor(kColorId_ResultsTableHoveredBackground)); 631 case kColorId_ResultsTableSelectedUrl: 632 return color_utils::GetReadableColor(SkColorSetRGB(0, 128, 0), 633 system_colors_[COLOR_HIGHLIGHT]); 634 case kColorId_ResultsTableNormalDivider: 635 return color_utils::AlphaBlend(system_colors_[COLOR_WINDOWTEXT], 636 system_colors_[COLOR_WINDOW], 0x34); 637 case kColorId_ResultsTableHoveredDivider: 638 return color_utils::AlphaBlend( 639 system_colors_[COLOR_WINDOWTEXT], 640 GetSystemColor(kColorId_ResultsTableHoveredBackground), 0x34); 641 case kColorId_ResultsTableSelectedDivider: 642 return color_utils::AlphaBlend(system_colors_[COLOR_HIGHLIGHTTEXT], 643 system_colors_[COLOR_HIGHLIGHT], 0x34); 644 } 645 NOTREACHED(); 646 return kInvalidColorIdColor; 647} 648 649void NativeThemeWin::PaintIndirect(SkCanvas* canvas, 650 Part part, 651 State state, 652 const gfx::Rect& rect, 653 const ExtraParams& extra) const { 654 // TODO(asvitkine): This path is pretty inefficient - for each paint operation 655 // it creates a new offscreen bitmap Skia canvas. This can 656 // be sped up by doing it only once per part/state and 657 // keeping a cache of the resulting bitmaps. 658 659 // Create an offscreen canvas that is backed by an HDC. 660 skia::RefPtr<skia::BitmapPlatformDevice> device = skia::AdoptRef( 661 skia::BitmapPlatformDevice::Create( 662 rect.width(), rect.height(), false, NULL)); 663 DCHECK(device); 664 SkCanvas offscreen_canvas(device.get()); 665 DCHECK(skia::SupportsPlatformPaint(&offscreen_canvas)); 666 667 // Some of the Windows theme drawing operations do not write correct alpha 668 // values for fully-opaque pixels; instead the pixels get alpha 0. This is 669 // especially a problem on Windows XP or when using the Classic theme. 670 // 671 // To work-around this, mark all pixels with a placeholder value, to detect 672 // which pixels get touched by the paint operation. After paint, set any 673 // pixels that have alpha 0 to opaque and placeholders to fully-transparent. 674 const SkColor placeholder = SkColorSetARGB(1, 0, 0, 0); 675 offscreen_canvas.clear(placeholder); 676 677 // Offset destination rects to have origin (0,0). 678 gfx::Rect adjusted_rect(rect.size()); 679 ExtraParams adjusted_extra(extra); 680 switch (part) { 681 case kProgressBar: 682 adjusted_extra.progress_bar.value_rect_x = 0; 683 adjusted_extra.progress_bar.value_rect_y = 0; 684 break; 685 case kScrollbarHorizontalTrack: 686 case kScrollbarVerticalTrack: 687 adjusted_extra.scrollbar_track.track_x = 0; 688 adjusted_extra.scrollbar_track.track_y = 0; 689 break; 690 default: 691 break; 692 } 693 // Draw the theme controls using existing HDC-drawing code. 694 PaintDirect(&offscreen_canvas, part, state, adjusted_rect, adjusted_extra); 695 696 // Copy the pixels to a bitmap that has ref-counted pixel storage, which is 697 // necessary to have when drawing to a SkPicture. 698 const SkBitmap& hdc_bitmap = 699 offscreen_canvas.getDevice()->accessBitmap(false); 700 SkBitmap bitmap; 701 hdc_bitmap.copyTo(&bitmap, kN32_SkColorType); 702 703 // Post-process the pixels to fix up the alpha values (see big comment above). 704 const SkPMColor placeholder_value = SkPreMultiplyColor(placeholder); 705 const int pixel_count = rect.width() * rect.height(); 706 SkPMColor* pixels = bitmap.getAddr32(0, 0); 707 for (int i = 0; i < pixel_count; i++) { 708 if (pixels[i] == placeholder_value) { 709 // Pixel wasn't touched - make it fully transparent. 710 pixels[i] = SkPackARGB32(0, 0, 0, 0); 711 } else if (SkGetPackedA32(pixels[i]) == 0) { 712 // Pixel was touched but has incorrect alpha of 0, make it fully opaque. 713 pixels[i] = SkPackARGB32(0xFF, 714 SkGetPackedR32(pixels[i]), 715 SkGetPackedG32(pixels[i]), 716 SkGetPackedB32(pixels[i])); 717 } 718 } 719 720 // Draw the offscreen bitmap to the destination canvas. 721 canvas->drawBitmap(bitmap, rect.x(), rect.y()); 722} 723 724HRESULT NativeThemeWin::GetThemePartSize(ThemeName theme_name, 725 HDC hdc, 726 int part_id, 727 int state_id, 728 RECT* rect, 729 int ts, 730 SIZE* size) const { 731 HANDLE handle = GetThemeHandle(theme_name); 732 return (handle && get_theme_part_size_) ? 733 get_theme_part_size_(handle, hdc, part_id, state_id, rect, ts, size) : 734 E_NOTIMPL; 735} 736 737HRESULT NativeThemeWin::PaintButton(HDC hdc, 738 State state, 739 const ButtonExtraParams& extra, 740 int part_id, 741 int state_id, 742 RECT* rect) const { 743 HANDLE handle = GetThemeHandle(BUTTON); 744 if (handle && draw_theme_) 745 return draw_theme_(handle, hdc, part_id, state_id, rect, NULL); 746 747 // Adjust classic_state based on part, state, and extras. 748 int classic_state = extra.classic_state; 749 switch (part_id) { 750 case BP_CHECKBOX: 751 classic_state |= DFCS_BUTTONCHECK; 752 break; 753 case BP_RADIOBUTTON: 754 classic_state |= DFCS_BUTTONRADIO; 755 break; 756 case BP_PUSHBUTTON: 757 classic_state |= DFCS_BUTTONPUSH; 758 break; 759 default: 760 NOTREACHED(); 761 break; 762 } 763 764 switch (state) { 765 case kDisabled: 766 classic_state |= DFCS_INACTIVE; 767 break; 768 case kHovered: 769 case kNormal: 770 break; 771 case kPressed: 772 classic_state |= DFCS_PUSHED; 773 break; 774 case kNumStates: 775 NOTREACHED(); 776 break; 777 } 778 779 if (extra.checked) 780 classic_state |= DFCS_CHECKED; 781 782 // Draw it manually. 783 // All pressed states have both low bits set, and no other states do. 784 const bool focused = ((state_id & ETS_FOCUSED) == ETS_FOCUSED); 785 const bool pressed = ((state_id & PBS_PRESSED) == PBS_PRESSED); 786 if ((BP_PUSHBUTTON == part_id) && (pressed || focused)) { 787 // BP_PUSHBUTTON has a focus rect drawn around the outer edge, and the 788 // button itself is shrunk by 1 pixel. 789 HBRUSH brush = GetSysColorBrush(COLOR_3DDKSHADOW); 790 if (brush) { 791 FrameRect(hdc, rect, brush); 792 InflateRect(rect, -1, -1); 793 } 794 } 795 DrawFrameControl(hdc, rect, DFC_BUTTON, classic_state); 796 797 // Draw the focus rectangle (the dotted line box) only on buttons. For radio 798 // and checkboxes, we let webkit draw the focus rectangle (orange glow). 799 if ((BP_PUSHBUTTON == part_id) && focused) { 800 // The focus rect is inside the button. The exact number of pixels depends 801 // on whether we're in classic mode or using uxtheme. 802 if (handle && get_theme_content_rect_) { 803 get_theme_content_rect_(handle, hdc, part_id, state_id, rect, rect); 804 } else { 805 InflateRect(rect, -GetSystemMetrics(SM_CXEDGE), 806 -GetSystemMetrics(SM_CYEDGE)); 807 } 808 DrawFocusRect(hdc, rect); 809 } 810 811 // Classic theme doesn't support indeterminate checkboxes. We draw 812 // a recangle inside a checkbox like IE10 does. 813 if (part_id == BP_CHECKBOX && extra.indeterminate) { 814 RECT inner_rect = *rect; 815 // "4 / 13" is same as IE10 in classic theme. 816 int padding = (inner_rect.right - inner_rect.left) * 4 / 13; 817 InflateRect(&inner_rect, -padding, -padding); 818 int color_index = state == kDisabled ? COLOR_GRAYTEXT : COLOR_WINDOWTEXT; 819 FillRect(hdc, &inner_rect, GetSysColorBrush(color_index)); 820 } 821 822 return S_OK; 823} 824 825HRESULT NativeThemeWin::PaintMenuSeparator( 826 HDC hdc, 827 const gfx::Rect& rect, 828 const MenuSeparatorExtraParams& extra) const { 829 RECT rect_win = rect.ToRECT(); 830 831 HANDLE handle = GetThemeHandle(MENU); 832 if (handle && draw_theme_) { 833 // Delta is needed for non-classic to move separator up slightly. 834 --rect_win.top; 835 --rect_win.bottom; 836 return draw_theme_(handle, hdc, MENU_POPUPSEPARATOR, MPI_NORMAL, &rect_win, 837 NULL); 838 } 839 840 DrawEdge(hdc, &rect_win, EDGE_ETCHED, BF_TOP); 841 return S_OK; 842} 843 844HRESULT NativeThemeWin::PaintMenuGutter(HDC hdc, 845 const gfx::Rect& rect) const { 846 RECT rect_win = rect.ToRECT(); 847 HANDLE handle = GetThemeHandle(MENU); 848 return (handle && draw_theme_) ? 849 draw_theme_(handle, hdc, MENU_POPUPGUTTER, MPI_NORMAL, &rect_win, NULL) : 850 E_NOTIMPL; 851} 852 853HRESULT NativeThemeWin::PaintMenuArrow( 854 HDC hdc, 855 State state, 856 const gfx::Rect& rect, 857 const MenuArrowExtraParams& extra) const { 858 int state_id = MSM_NORMAL; 859 if (state == kDisabled) 860 state_id = MSM_DISABLED; 861 862 HANDLE handle = GetThemeHandle(MENU); 863 RECT rect_win = rect.ToRECT(); 864 if (handle && draw_theme_) { 865 if (extra.pointing_right) { 866 return draw_theme_(handle, hdc, MENU_POPUPSUBMENU, state_id, &rect_win, 867 NULL); 868 } 869 // There is no way to tell the uxtheme API to draw a left pointing arrow; it 870 // doesn't have a flag equivalent to DFCS_MENUARROWRIGHT. But they are 871 // needed for RTL locales on Vista. So use a memory DC and mirror the 872 // region with GDI's StretchBlt. 873 gfx::Rect r(rect); 874 base::win::ScopedCreateDC mem_dc(CreateCompatibleDC(hdc)); 875 base::win::ScopedBitmap mem_bitmap(CreateCompatibleBitmap(hdc, r.width(), 876 r.height())); 877 base::win::ScopedSelectObject select_bitmap(mem_dc.Get(), mem_bitmap); 878 // Copy and horizontally mirror the background from hdc into mem_dc. Use 879 // a negative-width source rect, starting at the rightmost pixel. 880 StretchBlt(mem_dc.Get(), 0, 0, r.width(), r.height(), 881 hdc, r.right()-1, r.y(), -r.width(), r.height(), SRCCOPY); 882 // Draw the arrow. 883 RECT theme_rect = {0, 0, r.width(), r.height()}; 884 HRESULT result = draw_theme_(handle, mem_dc.Get(), MENU_POPUPSUBMENU, 885 state_id, &theme_rect, NULL); 886 // Copy and mirror the result back into mem_dc. 887 StretchBlt(hdc, r.x(), r.y(), r.width(), r.height(), 888 mem_dc.Get(), r.width()-1, 0, -r.width(), r.height(), SRCCOPY); 889 return result; 890 } 891 892 // For some reason, Windows uses the name DFCS_MENUARROWRIGHT to indicate a 893 // left pointing arrow. This makes the following statement counterintuitive. 894 UINT pfc_state = extra.pointing_right ? DFCS_MENUARROW : DFCS_MENUARROWRIGHT; 895 return PaintFrameControl(hdc, rect, DFC_MENU, pfc_state, extra.is_selected, 896 state); 897} 898 899HRESULT NativeThemeWin::PaintMenuBackground(HDC hdc, 900 const gfx::Rect& rect) const { 901 HANDLE handle = GetThemeHandle(MENU); 902 RECT rect_win = rect.ToRECT(); 903 if (handle && draw_theme_) { 904 HRESULT result = draw_theme_(handle, hdc, MENU_POPUPBACKGROUND, 0, 905 &rect_win, NULL); 906 FrameRect(hdc, &rect_win, GetSysColorBrush(COLOR_3DSHADOW)); 907 return result; 908 } 909 910 FillRect(hdc, &rect_win, GetSysColorBrush(COLOR_MENU)); 911 DrawEdge(hdc, &rect_win, EDGE_RAISED, BF_RECT); 912 return S_OK; 913} 914 915HRESULT NativeThemeWin::PaintMenuCheck( 916 HDC hdc, 917 State state, 918 const gfx::Rect& rect, 919 const MenuCheckExtraParams& extra) const { 920 HANDLE handle = GetThemeHandle(MENU); 921 if (handle && draw_theme_) { 922 const int state_id = extra.is_radio ? 923 ((state == kDisabled) ? MC_BULLETDISABLED : MC_BULLETNORMAL) : 924 ((state == kDisabled) ? MC_CHECKMARKDISABLED : MC_CHECKMARKNORMAL); 925 RECT rect_win = rect.ToRECT(); 926 return draw_theme_(handle, hdc, MENU_POPUPCHECK, state_id, &rect_win, NULL); 927 } 928 929 return PaintFrameControl(hdc, rect, DFC_MENU, 930 extra.is_radio ? DFCS_MENUBULLET : DFCS_MENUCHECK, 931 extra.is_selected, state); 932} 933 934HRESULT NativeThemeWin::PaintMenuCheckBackground(HDC hdc, 935 State state, 936 const gfx::Rect& rect) const { 937 HANDLE handle = GetThemeHandle(MENU); 938 if (!handle || !draw_theme_) 939 return S_OK; // Nothing to do for background. 940 941 int state_id = state == kDisabled ? MCB_DISABLED : MCB_NORMAL; 942 RECT rect_win = rect.ToRECT(); 943 return draw_theme_(handle, hdc, MENU_POPUPCHECKBACKGROUND, state_id, 944 &rect_win, NULL); 945} 946 947HRESULT NativeThemeWin::PaintMenuItemBackground( 948 HDC hdc, 949 State state, 950 const gfx::Rect& rect, 951 const MenuItemExtraParams& extra) const { 952 HANDLE handle = GetThemeHandle(MENU); 953 RECT rect_win = rect.ToRECT(); 954 int state_id = MPI_NORMAL; 955 switch (state) { 956 case kDisabled: 957 state_id = extra.is_selected ? MPI_DISABLEDHOT : MPI_DISABLED; 958 break; 959 case kHovered: 960 state_id = MPI_HOT; 961 break; 962 case kNormal: 963 break; 964 case kPressed: 965 case kNumStates: 966 NOTREACHED(); 967 break; 968 } 969 970 if (handle && draw_theme_) 971 return draw_theme_(handle, hdc, MENU_POPUPITEM, state_id, &rect_win, NULL); 972 973 if (extra.is_selected) 974 FillRect(hdc, &rect_win, GetSysColorBrush(COLOR_HIGHLIGHT)); 975 return S_OK; 976} 977 978HRESULT NativeThemeWin::PaintPushButton(HDC hdc, 979 Part part, 980 State state, 981 const gfx::Rect& rect, 982 const ButtonExtraParams& extra) const { 983 int state_id = extra.is_default ? PBS_DEFAULTED : PBS_NORMAL; 984 switch (state) { 985 case kDisabled: 986 state_id = PBS_DISABLED; 987 break; 988 case kHovered: 989 state_id = PBS_HOT; 990 break; 991 case kNormal: 992 break; 993 case kPressed: 994 state_id = PBS_PRESSED; 995 break; 996 case kNumStates: 997 NOTREACHED(); 998 break; 999 } 1000 1001 RECT rect_win = rect.ToRECT(); 1002 return PaintButton(hdc, state, extra, BP_PUSHBUTTON, state_id, &rect_win); 1003} 1004 1005HRESULT NativeThemeWin::PaintRadioButton(HDC hdc, 1006 Part part, 1007 State state, 1008 const gfx::Rect& rect, 1009 const ButtonExtraParams& extra) const { 1010 int state_id = extra.checked ? RBS_CHECKEDNORMAL : RBS_UNCHECKEDNORMAL; 1011 switch (state) { 1012 case kDisabled: 1013 state_id = extra.checked ? RBS_CHECKEDDISABLED : RBS_UNCHECKEDDISABLED; 1014 break; 1015 case kHovered: 1016 state_id = extra.checked ? RBS_CHECKEDHOT : RBS_UNCHECKEDHOT; 1017 break; 1018 case kNormal: 1019 break; 1020 case kPressed: 1021 state_id = extra.checked ? RBS_CHECKEDPRESSED : RBS_UNCHECKEDPRESSED; 1022 break; 1023 case kNumStates: 1024 NOTREACHED(); 1025 break; 1026 } 1027 1028 RECT rect_win = rect.ToRECT(); 1029 return PaintButton(hdc, state, extra, BP_RADIOBUTTON, state_id, &rect_win); 1030} 1031 1032HRESULT NativeThemeWin::PaintCheckbox(HDC hdc, 1033 Part part, 1034 State state, 1035 const gfx::Rect& rect, 1036 const ButtonExtraParams& extra) const { 1037 int state_id = extra.checked ? 1038 CBS_CHECKEDNORMAL : 1039 (extra.indeterminate ? CBS_MIXEDNORMAL : CBS_UNCHECKEDNORMAL); 1040 switch (state) { 1041 case kDisabled: 1042 state_id = extra.checked ? 1043 CBS_CHECKEDDISABLED : 1044 (extra.indeterminate ? CBS_MIXEDDISABLED : CBS_UNCHECKEDDISABLED); 1045 break; 1046 case kHovered: 1047 state_id = extra.checked ? 1048 CBS_CHECKEDHOT : 1049 (extra.indeterminate ? CBS_MIXEDHOT : CBS_UNCHECKEDHOT); 1050 break; 1051 case kNormal: 1052 break; 1053 case kPressed: 1054 state_id = extra.checked ? 1055 CBS_CHECKEDPRESSED : 1056 (extra.indeterminate ? CBS_MIXEDPRESSED : CBS_UNCHECKEDPRESSED); 1057 break; 1058 case kNumStates: 1059 NOTREACHED(); 1060 break; 1061 } 1062 1063 RECT rect_win = rect.ToRECT(); 1064 return PaintButton(hdc, state, extra, BP_CHECKBOX, state_id, &rect_win); 1065} 1066 1067HRESULT NativeThemeWin::PaintMenuList(HDC hdc, 1068 State state, 1069 const gfx::Rect& rect, 1070 const MenuListExtraParams& extra) const { 1071 HANDLE handle = GetThemeHandle(MENULIST); 1072 RECT rect_win = rect.ToRECT(); 1073 int state_id = CBXS_NORMAL; 1074 switch (state) { 1075 case kDisabled: 1076 state_id = CBXS_DISABLED; 1077 break; 1078 case kHovered: 1079 state_id = CBXS_HOT; 1080 break; 1081 case kNormal: 1082 break; 1083 case kPressed: 1084 state_id = CBXS_PRESSED; 1085 break; 1086 case kNumStates: 1087 NOTREACHED(); 1088 break; 1089 } 1090 1091 if (handle && draw_theme_) 1092 return draw_theme_(handle, hdc, CP_DROPDOWNBUTTON, state_id, &rect_win, 1093 NULL); 1094 1095 // Draw it manually. 1096 DrawFrameControl(hdc, &rect_win, DFC_SCROLL, 1097 DFCS_SCROLLCOMBOBOX | extra.classic_state); 1098 return S_OK; 1099} 1100 1101HRESULT NativeThemeWin::PaintScrollbarArrow( 1102 HDC hdc, 1103 Part part, 1104 State state, 1105 const gfx::Rect& rect, 1106 const ScrollbarArrowExtraParams& extra) const { 1107 static const int state_id_matrix[4][kNumStates] = { 1108 ABS_DOWNDISABLED, ABS_DOWNHOT, ABS_DOWNNORMAL, ABS_DOWNPRESSED, 1109 ABS_LEFTDISABLED, ABS_LEFTHOT, ABS_LEFTNORMAL, ABS_LEFTPRESSED, 1110 ABS_RIGHTDISABLED, ABS_RIGHTHOT, ABS_RIGHTNORMAL, ABS_RIGHTPRESSED, 1111 ABS_UPDISABLED, ABS_UPHOT, ABS_UPNORMAL, ABS_UPPRESSED 1112 }; 1113 HANDLE handle = GetThemeHandle(SCROLLBAR); 1114 RECT rect_win = rect.ToRECT(); 1115 if (handle && draw_theme_) { 1116 int index = part - kScrollbarDownArrow; 1117 DCHECK_GE(index, 0); 1118 DCHECK_LT(static_cast<size_t>(index), arraysize(state_id_matrix)); 1119 int state_id = state_id_matrix[index][state]; 1120 1121 // Hovering means that the cursor is over the scroolbar, but not over the 1122 // specific arrow itself. We don't want to show it "hot" mode, but only 1123 // in "hover" mode. 1124 if (state == kHovered && extra.is_hovering) { 1125 switch (part) { 1126 case kScrollbarDownArrow: 1127 state_id = ABS_DOWNHOVER; 1128 break; 1129 case kScrollbarLeftArrow: 1130 state_id = ABS_LEFTHOVER; 1131 break; 1132 case kScrollbarRightArrow: 1133 state_id = ABS_RIGHTHOVER; 1134 break; 1135 case kScrollbarUpArrow: 1136 state_id = ABS_UPHOVER; 1137 break; 1138 default: 1139 NOTREACHED(); 1140 break; 1141 } 1142 } 1143 return PaintScaledTheme(handle, hdc, SBP_ARROWBTN, state_id, rect); 1144 } 1145 1146 int classic_state = DFCS_SCROLLDOWN; 1147 switch (part) { 1148 case kScrollbarDownArrow: 1149 break; 1150 case kScrollbarLeftArrow: 1151 classic_state = DFCS_SCROLLLEFT; 1152 break; 1153 case kScrollbarRightArrow: 1154 classic_state = DFCS_SCROLLRIGHT; 1155 break; 1156 case kScrollbarUpArrow: 1157 classic_state = DFCS_SCROLLUP; 1158 break; 1159 default: 1160 NOTREACHED(); 1161 break; 1162 } 1163 switch (state) { 1164 case kDisabled: 1165 classic_state |= DFCS_INACTIVE; 1166 break; 1167 case kHovered: 1168 classic_state |= DFCS_HOT; 1169 break; 1170 case kNormal: 1171 break; 1172 case kPressed: 1173 classic_state |= DFCS_PUSHED; 1174 break; 1175 case kNumStates: 1176 NOTREACHED(); 1177 break; 1178 } 1179 DrawFrameControl(hdc, &rect_win, DFC_SCROLL, classic_state); 1180 return S_OK; 1181} 1182 1183HRESULT NativeThemeWin::PaintScrollbarThumb( 1184 HDC hdc, 1185 Part part, 1186 State state, 1187 const gfx::Rect& rect, 1188 const ScrollbarThumbExtraParams& extra) const { 1189 HANDLE handle = GetThemeHandle(SCROLLBAR); 1190 RECT rect_win = rect.ToRECT(); 1191 1192 int part_id = SBP_THUMBBTNVERT; 1193 switch (part) { 1194 case kScrollbarHorizontalThumb: 1195 part_id = SBP_THUMBBTNHORZ; 1196 break; 1197 case kScrollbarVerticalThumb: 1198 break; 1199 case kScrollbarHorizontalGripper: 1200 part_id = SBP_GRIPPERHORZ; 1201 break; 1202 case kScrollbarVerticalGripper: 1203 part_id = SBP_GRIPPERVERT; 1204 break; 1205 default: 1206 NOTREACHED(); 1207 break; 1208 } 1209 1210 int state_id = SCRBS_NORMAL; 1211 switch (state) { 1212 case kDisabled: 1213 state_id = SCRBS_DISABLED; 1214 break; 1215 case kHovered: 1216 state_id = extra.is_hovering ? SCRBS_HOVER : SCRBS_HOT; 1217 break; 1218 case kNormal: 1219 break; 1220 case kPressed: 1221 state_id = SCRBS_PRESSED; 1222 break; 1223 case kNumStates: 1224 NOTREACHED(); 1225 break; 1226 } 1227 1228 if (handle && draw_theme_) 1229 return PaintScaledTheme(handle, hdc, part_id, state_id, rect); 1230 1231 // Draw it manually. 1232 if ((part_id == SBP_THUMBBTNHORZ) || (part_id == SBP_THUMBBTNVERT)) 1233 DrawEdge(hdc, &rect_win, EDGE_RAISED, BF_RECT | BF_MIDDLE); 1234 // Classic mode doesn't have a gripper. 1235 return S_OK; 1236} 1237 1238HRESULT NativeThemeWin::PaintScrollbarTrack( 1239 SkCanvas* canvas, 1240 HDC hdc, 1241 Part part, 1242 State state, 1243 const gfx::Rect& rect, 1244 const ScrollbarTrackExtraParams& extra) const { 1245 HANDLE handle = GetThemeHandle(SCROLLBAR); 1246 RECT rect_win = rect.ToRECT(); 1247 1248 const int part_id = extra.is_upper ? 1249 ((part == kScrollbarHorizontalTrack) ? 1250 SBP_UPPERTRACKHORZ : SBP_UPPERTRACKVERT) : 1251 ((part == kScrollbarHorizontalTrack) ? 1252 SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT); 1253 1254 int state_id = SCRBS_NORMAL; 1255 switch (state) { 1256 case kDisabled: 1257 state_id = SCRBS_DISABLED; 1258 break; 1259 case kHovered: 1260 state_id = SCRBS_HOVER; 1261 break; 1262 case kNormal: 1263 break; 1264 case kPressed: 1265 state_id = SCRBS_PRESSED; 1266 break; 1267 case kNumStates: 1268 NOTREACHED(); 1269 break; 1270 } 1271 1272 if (handle && draw_theme_) 1273 return draw_theme_(handle, hdc, part_id, state_id, &rect_win, NULL); 1274 1275 // Draw it manually. 1276 if ((system_colors_[COLOR_SCROLLBAR] != system_colors_[COLOR_3DFACE]) && 1277 (system_colors_[COLOR_SCROLLBAR] != system_colors_[COLOR_WINDOW])) { 1278 FillRect(hdc, &rect_win, reinterpret_cast<HBRUSH>(COLOR_SCROLLBAR + 1)); 1279 } else { 1280 SkPaint paint; 1281 RECT align_rect = gfx::Rect(extra.track_x, extra.track_y, extra.track_width, 1282 extra.track_height).ToRECT(); 1283 SetCheckerboardShader(&paint, align_rect); 1284 canvas->drawIRect(skia::RECTToSkIRect(rect_win), paint); 1285 } 1286 if (extra.classic_state & DFCS_PUSHED) 1287 InvertRect(hdc, &rect_win); 1288 return S_OK; 1289} 1290 1291HRESULT NativeThemeWin::PaintSpinButton( 1292 HDC hdc, 1293 Part part, 1294 State state, 1295 const gfx::Rect& rect, 1296 const InnerSpinButtonExtraParams& extra) const { 1297 HANDLE handle = GetThemeHandle(SPIN); 1298 RECT rect_win = rect.ToRECT(); 1299 int part_id = extra.spin_up ? SPNP_UP : SPNP_DOWN; 1300 int state_id = extra.spin_up ? UPS_NORMAL : DNS_NORMAL; 1301 switch (state) { 1302 case kDisabled: 1303 state_id = extra.spin_up ? UPS_DISABLED : DNS_DISABLED; 1304 break; 1305 case kHovered: 1306 state_id = extra.spin_up ? UPS_HOT : DNS_HOT; 1307 break; 1308 case kNormal: 1309 break; 1310 case kPressed: 1311 state_id = extra.spin_up ? UPS_PRESSED : DNS_PRESSED; 1312 break; 1313 case kNumStates: 1314 NOTREACHED(); 1315 break; 1316 } 1317 1318 if (handle && draw_theme_) 1319 return draw_theme_(handle, hdc, part_id, state_id, &rect_win, NULL); 1320 DrawFrameControl(hdc, &rect_win, DFC_SCROLL, extra.classic_state); 1321 return S_OK; 1322} 1323 1324HRESULT NativeThemeWin::PaintTrackbar( 1325 SkCanvas* canvas, 1326 HDC hdc, 1327 Part part, 1328 State state, 1329 const gfx::Rect& rect, 1330 const TrackbarExtraParams& extra) const { 1331 const int part_id = extra.vertical ? 1332 ((part == kTrackbarTrack) ? TKP_TRACKVERT : TKP_THUMBVERT) : 1333 ((part == kTrackbarTrack) ? TKP_TRACK : TKP_THUMBBOTTOM); 1334 1335 int state_id = TUS_NORMAL; 1336 switch (state) { 1337 case kDisabled: 1338 state_id = TUS_DISABLED; 1339 break; 1340 case kHovered: 1341 state_id = TUS_HOT; 1342 break; 1343 case kNormal: 1344 break; 1345 case kPressed: 1346 state_id = TUS_PRESSED; 1347 break; 1348 case kNumStates: 1349 NOTREACHED(); 1350 break; 1351 } 1352 1353 // Make the channel be 4 px thick in the center of the supplied rect. (4 px 1354 // matches what XP does in various menus; GetThemePartSize() doesn't seem to 1355 // return good values here.) 1356 RECT rect_win = rect.ToRECT(); 1357 RECT channel_rect = rect.ToRECT(); 1358 const int channel_thickness = 4; 1359 if (part_id == TKP_TRACK) { 1360 channel_rect.top += 1361 ((channel_rect.bottom - channel_rect.top - channel_thickness) / 2); 1362 channel_rect.bottom = channel_rect.top + channel_thickness; 1363 } else if (part_id == TKP_TRACKVERT) { 1364 channel_rect.left += 1365 ((channel_rect.right - channel_rect.left - channel_thickness) / 2); 1366 channel_rect.right = channel_rect.left + channel_thickness; 1367 } // else this isn't actually a channel, so |channel_rect| == |rect|. 1368 1369 HANDLE handle = GetThemeHandle(TRACKBAR); 1370 if (handle && draw_theme_) 1371 return draw_theme_(handle, hdc, part_id, state_id, &channel_rect, NULL); 1372 1373 // Classic mode, draw it manually. 1374 if ((part_id == TKP_TRACK) || (part_id == TKP_TRACKVERT)) { 1375 DrawEdge(hdc, &channel_rect, EDGE_SUNKEN, BF_RECT); 1376 } else if (part_id == TKP_THUMBVERT) { 1377 DrawEdge(hdc, &rect_win, EDGE_RAISED, BF_RECT | BF_SOFT | BF_MIDDLE); 1378 } else { 1379 // Split rect into top and bottom pieces. 1380 RECT top_section = rect.ToRECT(); 1381 RECT bottom_section = rect.ToRECT(); 1382 top_section.bottom -= ((bottom_section.right - bottom_section.left) / 2); 1383 bottom_section.top = top_section.bottom; 1384 DrawEdge(hdc, &top_section, EDGE_RAISED, 1385 BF_LEFT | BF_TOP | BF_RIGHT | BF_SOFT | BF_MIDDLE | BF_ADJUST); 1386 1387 // Split triangular piece into two diagonals. 1388 RECT& left_half = bottom_section; 1389 RECT right_half = bottom_section; 1390 right_half.left += ((bottom_section.right - bottom_section.left) / 2); 1391 left_half.right = right_half.left; 1392 DrawEdge(hdc, &left_half, EDGE_RAISED, 1393 BF_DIAGONAL_ENDTOPLEFT | BF_SOFT | BF_MIDDLE | BF_ADJUST); 1394 DrawEdge(hdc, &right_half, EDGE_RAISED, 1395 BF_DIAGONAL_ENDBOTTOMLEFT | BF_SOFT | BF_MIDDLE | BF_ADJUST); 1396 1397 // If the button is pressed, draw hatching. 1398 if (extra.classic_state & DFCS_PUSHED) { 1399 SkPaint paint; 1400 SetCheckerboardShader(&paint, rect_win); 1401 1402 // Fill all three pieces with the pattern. 1403 canvas->drawIRect(skia::RECTToSkIRect(top_section), paint); 1404 1405 SkScalar left_triangle_top = SkIntToScalar(left_half.top); 1406 SkScalar left_triangle_right = SkIntToScalar(left_half.right); 1407 SkPath left_triangle; 1408 left_triangle.moveTo(SkIntToScalar(left_half.left), left_triangle_top); 1409 left_triangle.lineTo(left_triangle_right, left_triangle_top); 1410 left_triangle.lineTo(left_triangle_right, 1411 SkIntToScalar(left_half.bottom)); 1412 left_triangle.close(); 1413 canvas->drawPath(left_triangle, paint); 1414 1415 SkScalar right_triangle_left = SkIntToScalar(right_half.left); 1416 SkScalar right_triangle_top = SkIntToScalar(right_half.top); 1417 SkPath right_triangle; 1418 right_triangle.moveTo(right_triangle_left, right_triangle_top); 1419 right_triangle.lineTo(SkIntToScalar(right_half.right), 1420 right_triangle_top); 1421 right_triangle.lineTo(right_triangle_left, 1422 SkIntToScalar(right_half.bottom)); 1423 right_triangle.close(); 1424 canvas->drawPath(right_triangle, paint); 1425 } 1426 } 1427 return S_OK; 1428} 1429 1430HRESULT NativeThemeWin::PaintProgressBar( 1431 HDC hdc, 1432 const gfx::Rect& rect, 1433 const ProgressBarExtraParams& extra) const { 1434 // There is no documentation about the animation speed, frame-rate, nor 1435 // size of moving overlay of the indeterminate progress bar. 1436 // So we just observed real-world programs and guessed following parameters. 1437 const int kDeterminateOverlayPixelsPerSecond = 300; 1438 const int kDeterminateOverlayWidth = 120; 1439 const int kIndeterminateOverlayPixelsPerSecond = 175; 1440 const int kVistaIndeterminateOverlayWidth = 120; 1441 const int kXPIndeterminateOverlayWidth = 55; 1442 // The thickness of the bar frame inside |value_rect| 1443 const int kXPBarPadding = 3; 1444 1445 RECT bar_rect = rect.ToRECT(); 1446 RECT value_rect = gfx::Rect(extra.value_rect_x, 1447 extra.value_rect_y, 1448 extra.value_rect_width, 1449 extra.value_rect_height).ToRECT(); 1450 1451 HANDLE handle = GetThemeHandle(PROGRESS); 1452 if (!handle || !draw_theme_ || !draw_theme_ex_) { 1453 FillRect(hdc, &bar_rect, GetSysColorBrush(COLOR_BTNFACE)); 1454 FillRect(hdc, &value_rect, GetSysColorBrush(COLOR_BTNSHADOW)); 1455 DrawEdge(hdc, &bar_rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); 1456 return S_OK; 1457 } 1458 1459 draw_theme_(handle, hdc, PP_BAR, 0, &bar_rect, NULL); 1460 1461 bool pre_vista = base::win::GetVersion() < base::win::VERSION_VISTA; 1462 int bar_width = bar_rect.right - bar_rect.left; 1463 if (!extra.determinate) { 1464 // The glossy overlay for the indeterminate progress bar has a small pause 1465 // after each animation. We emulate this by adding an invisible margin the 1466 // animation has to traverse. 1467 int width_with_margin = bar_width + kIndeterminateOverlayPixelsPerSecond; 1468 int overlay_width = pre_vista ? 1469 kXPIndeterminateOverlayWidth : kVistaIndeterminateOverlayWidth; 1470 RECT overlay_rect = bar_rect; 1471 overlay_rect.left += ComputeAnimationProgress( 1472 width_with_margin, overlay_width, kIndeterminateOverlayPixelsPerSecond, 1473 extra.animated_seconds); 1474 overlay_rect.right = overlay_rect.left + overlay_width; 1475 if (pre_vista) { 1476 RECT shrunk_rect = InsetRect(&overlay_rect, kXPBarPadding); 1477 RECT shrunk_bar_rect = InsetRect(&bar_rect, kXPBarPadding); 1478 draw_theme_(handle, hdc, PP_CHUNK, 0, &shrunk_rect, &shrunk_bar_rect); 1479 } else { 1480 draw_theme_(handle, hdc, PP_MOVEOVERLAY, 0, &overlay_rect, &bar_rect); 1481 } 1482 return S_OK; 1483 } 1484 1485 // We care about the direction here because PP_CHUNK painting is asymmetric. 1486 // TODO(morrita): This RTL guess can be wrong. We should pass in the 1487 // direction from WebKit. 1488 const DTBGOPTS value_draw_options = { 1489 sizeof(DTBGOPTS), 1490 (bar_rect.right == value_rect.right && bar_rect.left != value_rect.left) ? 1491 DTBG_MIRRORDC : 0, 1492 bar_rect 1493 }; 1494 if (pre_vista) { 1495 // On XP, the progress bar is chunk-style and has no glossy effect. We need 1496 // to shrink the destination rect to fit the part inside the bar with an 1497 // appropriate margin. 1498 RECT shrunk_value_rect = InsetRect(&value_rect, kXPBarPadding); 1499 draw_theme_ex_(handle, hdc, PP_CHUNK, 0, &shrunk_value_rect, 1500 &value_draw_options); 1501 } else { 1502 // On Vista or later, the progress bar part has a single-block value part 1503 // and a glossy effect. The value part has exactly same height as the bar 1504 // part, so we don't need to shrink the rect. 1505 draw_theme_ex_(handle, hdc, PP_FILL, 0, &value_rect, &value_draw_options); 1506 1507 RECT overlay_rect = value_rect; 1508 overlay_rect.left += ComputeAnimationProgress( 1509 bar_width, kDeterminateOverlayWidth, kDeterminateOverlayPixelsPerSecond, 1510 extra.animated_seconds); 1511 overlay_rect.right = overlay_rect.left + kDeterminateOverlayWidth; 1512 draw_theme_(handle, hdc, PP_MOVEOVERLAY, 0, &overlay_rect, &value_rect); 1513 } 1514 return S_OK; 1515} 1516 1517HRESULT NativeThemeWin::PaintWindowResizeGripper(HDC hdc, 1518 const gfx::Rect& rect) const { 1519 HANDLE handle = GetThemeHandle(STATUS); 1520 RECT rect_win = rect.ToRECT(); 1521 if (handle && draw_theme_) { 1522 // Paint the status bar gripper. There doesn't seem to be a standard 1523 // gripper in Windows for the space between scrollbars. This is pretty 1524 // close, but it's supposed to be painted over a status bar. 1525 return draw_theme_(handle, hdc, SP_GRIPPER, 0, &rect_win, NULL); 1526 } 1527 1528 // Draw a windows classic scrollbar gripper. 1529 DrawFrameControl(hdc, &rect_win, DFC_SCROLL, DFCS_SCROLLSIZEGRIP); 1530 return S_OK; 1531} 1532 1533HRESULT NativeThemeWin::PaintTabPanelBackground(HDC hdc, 1534 const gfx::Rect& rect) const { 1535 HANDLE handle = GetThemeHandle(TAB); 1536 RECT rect_win = rect.ToRECT(); 1537 if (handle && draw_theme_) 1538 return draw_theme_(handle, hdc, TABP_BODY, 0, &rect_win, NULL); 1539 1540 // Classic just renders a flat color background. 1541 FillRect(hdc, &rect_win, reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1)); 1542 return S_OK; 1543} 1544 1545HRESULT NativeThemeWin::PaintTextField( 1546 HDC hdc, 1547 Part part, 1548 State state, 1549 const gfx::Rect& rect, 1550 const TextFieldExtraParams& extra) const { 1551 int state_id = ETS_NORMAL; 1552 switch (state) { 1553 case kDisabled: 1554 state_id = ETS_DISABLED; 1555 break; 1556 case kHovered: 1557 state_id = ETS_HOT; 1558 break; 1559 case kNormal: 1560 if (extra.is_read_only) 1561 state_id = ETS_READONLY; 1562 else if (extra.is_focused) 1563 state_id = ETS_FOCUSED; 1564 break; 1565 case kPressed: 1566 state_id = ETS_SELECTED; 1567 break; 1568 case kNumStates: 1569 NOTREACHED(); 1570 break; 1571 } 1572 1573 RECT rect_win = rect.ToRECT(); 1574 return PaintTextField(hdc, EP_EDITTEXT, state_id, extra.classic_state, 1575 &rect_win, 1576 skia::SkColorToCOLORREF(extra.background_color), 1577 extra.fill_content_area, extra.draw_edges); 1578} 1579 1580HRESULT NativeThemeWin::PaintTextField(HDC hdc, 1581 int part_id, 1582 int state_id, 1583 int classic_state, 1584 RECT* rect, 1585 COLORREF color, 1586 bool fill_content_area, 1587 bool draw_edges) const { 1588 // TODO(ojan): http://b/1210017 Figure out how to give the ability to 1589 // exclude individual edges from being drawn. 1590 1591 HANDLE handle = GetThemeHandle(TEXTFIELD); 1592 // TODO(mpcomplete): can we detect if the color is specified by the user, 1593 // and if not, just use the system color? 1594 // CreateSolidBrush() accepts a RGB value but alpha must be 0. 1595 base::win::ScopedGDIObject<HBRUSH> bg_brush(CreateSolidBrush(color)); 1596 // DrawThemeBackgroundEx was introduced in XP SP2, so that it's possible 1597 // draw_theme_ex_ is NULL and draw_theme_ is non-null. 1598 if (!handle || (!draw_theme_ex_ && (!draw_theme_ || !draw_edges))) { 1599 // Draw it manually. 1600 if (draw_edges) 1601 DrawEdge(hdc, rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); 1602 1603 if (fill_content_area) { 1604 FillRect(hdc, rect, (classic_state & DFCS_INACTIVE) ? 1605 reinterpret_cast<HBRUSH>(COLOR_BTNFACE + 1) : bg_brush); 1606 } 1607 return S_OK; 1608 } 1609 1610 static const DTBGOPTS omit_border_options = { 1611 sizeof(DTBGOPTS), 1612 DTBG_OMITBORDER, 1613 { 0, 0, 0, 0 } 1614 }; 1615 HRESULT hr = draw_theme_ex_ ? 1616 draw_theme_ex_(handle, hdc, part_id, state_id, rect, 1617 draw_edges ? NULL : &omit_border_options) : 1618 draw_theme_(handle, hdc, part_id, state_id, rect, NULL); 1619 1620 // TODO(maruel): Need to be fixed if get_theme_content_rect_ is NULL. 1621 if (fill_content_area && get_theme_content_rect_) { 1622 RECT content_rect; 1623 hr = get_theme_content_rect_(handle, hdc, part_id, state_id, rect, 1624 &content_rect); 1625 FillRect(hdc, &content_rect, bg_brush); 1626 } 1627 return hr; 1628} 1629 1630HRESULT NativeThemeWin::PaintScaledTheme(HANDLE theme, 1631 HDC hdc, 1632 int part_id, 1633 int state_id, 1634 const gfx::Rect& rect) const { 1635 // Correct the scaling and positioning of sub-components such as scrollbar 1636 // arrows and thumb grippers in the event that the world transform applies 1637 // scaling (e.g. in high-DPI mode). 1638 XFORM save_transform; 1639 if (GetWorldTransform(hdc, &save_transform)) { 1640 float scale = save_transform.eM11; 1641 if (scale != 1 && save_transform.eM12 == 0) { 1642 ModifyWorldTransform(hdc, NULL, MWT_IDENTITY); 1643 gfx::Rect scaled_rect(gfx::ToEnclosedRect(gfx::ScaleRect(rect, scale))); 1644 scaled_rect.Offset(save_transform.eDx, save_transform.eDy); 1645 RECT bounds = scaled_rect.ToRECT(); 1646 HRESULT result = draw_theme_(theme, hdc, part_id, state_id, &bounds, 1647 NULL); 1648 SetWorldTransform(hdc, &save_transform); 1649 return result; 1650 } 1651 } 1652 RECT bounds = rect.ToRECT(); 1653 return draw_theme_(theme, hdc, part_id, state_id, &bounds, NULL); 1654} 1655 1656// static 1657NativeThemeWin::ThemeName NativeThemeWin::GetThemeName(Part part) { 1658 switch (part) { 1659 case kCheckbox: 1660 case kPushButton: 1661 case kRadio: 1662 return BUTTON; 1663 case kInnerSpinButton: 1664 return SPIN; 1665 case kMenuList: 1666 case kMenuCheck: 1667 case kMenuPopupArrow: 1668 case kMenuPopupGutter: 1669 case kMenuPopupSeparator: 1670 return MENU; 1671 case kProgressBar: 1672 return PROGRESS; 1673 case kScrollbarDownArrow: 1674 case kScrollbarLeftArrow: 1675 case kScrollbarRightArrow: 1676 case kScrollbarUpArrow: 1677 case kScrollbarHorizontalThumb: 1678 case kScrollbarVerticalThumb: 1679 case kScrollbarHorizontalTrack: 1680 case kScrollbarVerticalTrack: 1681 return SCROLLBAR; 1682 case kSliderTrack: 1683 case kSliderThumb: 1684 return TRACKBAR; 1685 case kTextField: 1686 return TEXTFIELD; 1687 case kWindowResizeGripper: 1688 return STATUS; 1689 case kComboboxArrow: 1690 case kMenuCheckBackground: 1691 case kMenuPopupBackground: 1692 case kMenuItemBackground: 1693 case kScrollbarHorizontalGripper: 1694 case kScrollbarVerticalGripper: 1695 case kScrollbarCorner: 1696 case kTabPanelBackground: 1697 case kTrackbarThumb: 1698 case kTrackbarTrack: 1699 case kMaxPart: 1700 NOTREACHED(); 1701 } 1702 return LAST; 1703} 1704 1705// static 1706int NativeThemeWin::GetWindowsPart(Part part, 1707 State state, 1708 const ExtraParams& extra) { 1709 switch (part) { 1710 case kCheckbox: 1711 return BP_CHECKBOX; 1712 case kMenuCheck: 1713 return MENU_POPUPCHECK; 1714 case kMenuPopupArrow: 1715 return MENU_POPUPSUBMENU; 1716 case kMenuPopupGutter: 1717 return MENU_POPUPGUTTER; 1718 case kMenuPopupSeparator: 1719 return MENU_POPUPSEPARATOR; 1720 case kPushButton: 1721 return BP_PUSHBUTTON; 1722 case kRadio: 1723 return BP_RADIOBUTTON; 1724 case kScrollbarDownArrow: 1725 case kScrollbarLeftArrow: 1726 case kScrollbarRightArrow: 1727 case kScrollbarUpArrow: 1728 return SBP_ARROWBTN; 1729 case kScrollbarHorizontalThumb: 1730 return SBP_THUMBBTNHORZ; 1731 case kScrollbarVerticalThumb: 1732 return SBP_THUMBBTNVERT; 1733 case kWindowResizeGripper: 1734 return SP_GRIPPER; 1735 case kComboboxArrow: 1736 case kInnerSpinButton: 1737 case kMenuList: 1738 case kMenuCheckBackground: 1739 case kMenuPopupBackground: 1740 case kMenuItemBackground: 1741 case kProgressBar: 1742 case kScrollbarHorizontalTrack: 1743 case kScrollbarVerticalTrack: 1744 case kScrollbarHorizontalGripper: 1745 case kScrollbarVerticalGripper: 1746 case kScrollbarCorner: 1747 case kSliderTrack: 1748 case kSliderThumb: 1749 case kTabPanelBackground: 1750 case kTextField: 1751 case kTrackbarThumb: 1752 case kTrackbarTrack: 1753 case kMaxPart: 1754 NOTREACHED(); 1755 } 1756 return 0; 1757} 1758 1759int NativeThemeWin::GetWindowsState(Part part, 1760 State state, 1761 const ExtraParams& extra) { 1762 switch (part) { 1763 case kCheckbox: 1764 switch (state) { 1765 case kDisabled: 1766 return CBS_UNCHECKEDDISABLED; 1767 case kHovered: 1768 return CBS_UNCHECKEDHOT; 1769 case kNormal: 1770 return CBS_UNCHECKEDNORMAL; 1771 case kPressed: 1772 return CBS_UNCHECKEDPRESSED; 1773 case kNumStates: 1774 NOTREACHED(); 1775 return 0; 1776 } 1777 case kMenuCheck: 1778 switch (state) { 1779 case kDisabled: 1780 return extra.menu_check.is_radio ? 1781 MC_BULLETDISABLED : MC_CHECKMARKDISABLED; 1782 case kHovered: 1783 case kNormal: 1784 case kPressed: 1785 return extra.menu_check.is_radio ? 1786 MC_BULLETNORMAL : MC_CHECKMARKNORMAL; 1787 case kNumStates: 1788 NOTREACHED(); 1789 return 0; 1790 } 1791 case kMenuPopupArrow: 1792 case kMenuPopupGutter: 1793 case kMenuPopupSeparator: 1794 switch (state) { 1795 case kDisabled: 1796 return MBI_DISABLED; 1797 case kHovered: 1798 return MBI_HOT; 1799 case kNormal: 1800 return MBI_NORMAL; 1801 case kPressed: 1802 return MBI_PUSHED; 1803 case kNumStates: 1804 NOTREACHED(); 1805 return 0; 1806 } 1807 case kPushButton: 1808 switch (state) { 1809 case kDisabled: 1810 return PBS_DISABLED; 1811 case kHovered: 1812 return PBS_HOT; 1813 case kNormal: 1814 return PBS_NORMAL; 1815 case kPressed: 1816 return PBS_PRESSED; 1817 case kNumStates: 1818 NOTREACHED(); 1819 return 0; 1820 } 1821 case kRadio: 1822 switch (state) { 1823 case kDisabled: 1824 return RBS_UNCHECKEDDISABLED; 1825 case kHovered: 1826 return RBS_UNCHECKEDHOT; 1827 case kNormal: 1828 return RBS_UNCHECKEDNORMAL; 1829 case kPressed: 1830 return RBS_UNCHECKEDPRESSED; 1831 case kNumStates: 1832 NOTREACHED(); 1833 return 0; 1834 } 1835 case kScrollbarDownArrow: 1836 switch (state) { 1837 case kDisabled: 1838 return ABS_DOWNDISABLED; 1839 case kHovered: 1840 // Mimic ScrollbarThemeChromiumWin.cpp in WebKit. 1841 return base::win::GetVersion() < base::win::VERSION_VISTA ? 1842 ABS_DOWNHOT : ABS_DOWNHOVER; 1843 case kNormal: 1844 return ABS_DOWNNORMAL; 1845 case kPressed: 1846 return ABS_DOWNPRESSED; 1847 case kNumStates: 1848 NOTREACHED(); 1849 return 0; 1850 } 1851 case kScrollbarLeftArrow: 1852 switch (state) { 1853 case kDisabled: 1854 return ABS_LEFTDISABLED; 1855 case kHovered: 1856 // Mimic ScrollbarThemeChromiumWin.cpp in WebKit. 1857 return base::win::GetVersion() < base::win::VERSION_VISTA ? 1858 ABS_LEFTHOT : ABS_LEFTHOVER; 1859 case kNormal: 1860 return ABS_LEFTNORMAL; 1861 case kPressed: 1862 return ABS_LEFTPRESSED; 1863 case kNumStates: 1864 NOTREACHED(); 1865 return 0; 1866 } 1867 case kScrollbarRightArrow: 1868 switch (state) { 1869 case kDisabled: 1870 return ABS_RIGHTDISABLED; 1871 case kHovered: 1872 // Mimic ScrollbarThemeChromiumWin.cpp in WebKit. 1873 return base::win::GetVersion() < base::win::VERSION_VISTA ? 1874 ABS_RIGHTHOT : ABS_RIGHTHOVER; 1875 case kNormal: 1876 return ABS_RIGHTNORMAL; 1877 case kPressed: 1878 return ABS_RIGHTPRESSED; 1879 case kNumStates: 1880 NOTREACHED(); 1881 return 0; 1882 } 1883 break; 1884 case kScrollbarUpArrow: 1885 switch (state) { 1886 case kDisabled: 1887 return ABS_UPDISABLED; 1888 case kHovered: 1889 // Mimic ScrollbarThemeChromiumWin.cpp in WebKit. 1890 return base::win::GetVersion() < base::win::VERSION_VISTA ? 1891 ABS_UPHOT : ABS_UPHOVER; 1892 case kNormal: 1893 return ABS_UPNORMAL; 1894 case kPressed: 1895 return ABS_UPPRESSED; 1896 case kNumStates: 1897 NOTREACHED(); 1898 return 0; 1899 } 1900 break; 1901 case kScrollbarHorizontalThumb: 1902 case kScrollbarVerticalThumb: 1903 switch (state) { 1904 case kDisabled: 1905 return SCRBS_DISABLED; 1906 case kHovered: 1907 // Mimic WebKit's behaviour in ScrollbarThemeChromiumWin.cpp. 1908 return base::win::GetVersion() < base::win::VERSION_VISTA ? 1909 SCRBS_HOT : SCRBS_HOVER; 1910 case kNormal: 1911 return SCRBS_NORMAL; 1912 case kPressed: 1913 return SCRBS_PRESSED; 1914 case kNumStates: 1915 NOTREACHED(); 1916 return 0; 1917 } 1918 case kWindowResizeGripper: 1919 switch (state) { 1920 case kDisabled: 1921 case kHovered: 1922 case kNormal: 1923 case kPressed: 1924 return 1; // gripper has no windows state 1925 case kNumStates: 1926 NOTREACHED(); 1927 return 0; 1928 } 1929 case kComboboxArrow: 1930 case kInnerSpinButton: 1931 case kMenuList: 1932 case kMenuCheckBackground: 1933 case kMenuPopupBackground: 1934 case kMenuItemBackground: 1935 case kProgressBar: 1936 case kScrollbarHorizontalTrack: 1937 case kScrollbarVerticalTrack: 1938 case kScrollbarHorizontalGripper: 1939 case kScrollbarVerticalGripper: 1940 case kScrollbarCorner: 1941 case kSliderTrack: 1942 case kSliderThumb: 1943 case kTabPanelBackground: 1944 case kTextField: 1945 case kTrackbarThumb: 1946 case kTrackbarTrack: 1947 case kMaxPart: 1948 NOTREACHED(); 1949 } 1950 return 0; 1951} 1952 1953HRESULT NativeThemeWin::GetThemeInt(ThemeName theme, 1954 int part_id, 1955 int state_id, 1956 int prop_id, 1957 int *value) const { 1958 HANDLE handle = GetThemeHandle(theme); 1959 return (handle && get_theme_int_) ? 1960 get_theme_int_(handle, part_id, state_id, prop_id, value) : E_NOTIMPL; 1961} 1962 1963HRESULT NativeThemeWin::PaintFrameControl(HDC hdc, 1964 const gfx::Rect& rect, 1965 UINT type, 1966 UINT state, 1967 bool is_selected, 1968 State control_state) const { 1969 const int width = rect.width(); 1970 const int height = rect.height(); 1971 1972 // DrawFrameControl for menu arrow/check wants a monochrome bitmap. 1973 base::win::ScopedBitmap mask_bitmap(CreateBitmap(width, height, 1, 1, NULL)); 1974 1975 if (mask_bitmap == NULL) 1976 return E_OUTOFMEMORY; 1977 1978 base::win::ScopedCreateDC bitmap_dc(CreateCompatibleDC(NULL)); 1979 base::win::ScopedSelectObject select_bitmap(bitmap_dc.Get(), mask_bitmap); 1980 RECT local_rect = { 0, 0, width, height }; 1981 DrawFrameControl(bitmap_dc.Get(), &local_rect, type, state); 1982 1983 // We're going to use BitBlt with a b&w mask. This results in using the dest 1984 // dc's text color for the black bits in the mask, and the dest dc's 1985 // background color for the white bits in the mask. DrawFrameControl draws the 1986 // check in black, and the background in white. 1987 int bg_color_key = COLOR_MENU; 1988 int text_color_key = COLOR_MENUTEXT; 1989 switch (control_state) { 1990 case kDisabled: 1991 bg_color_key = is_selected ? COLOR_HIGHLIGHT : COLOR_MENU; 1992 text_color_key = COLOR_GRAYTEXT; 1993 break; 1994 case kHovered: 1995 bg_color_key = COLOR_HIGHLIGHT; 1996 text_color_key = COLOR_HIGHLIGHTTEXT; 1997 break; 1998 case kNormal: 1999 break; 2000 case kPressed: 2001 case kNumStates: 2002 NOTREACHED(); 2003 break; 2004 } 2005 COLORREF old_bg_color = SetBkColor(hdc, GetSysColor(bg_color_key)); 2006 COLORREF old_text_color = SetTextColor(hdc, GetSysColor(text_color_key)); 2007 BitBlt(hdc, rect.x(), rect.y(), width, height, bitmap_dc.Get(), 0, 0, 2008 SRCCOPY); 2009 SetBkColor(hdc, old_bg_color); 2010 SetTextColor(hdc, old_text_color); 2011 2012 return S_OK; 2013} 2014 2015HANDLE NativeThemeWin::GetThemeHandle(ThemeName theme_name) const { 2016 if (!open_theme_ || theme_name < 0 || theme_name >= LAST) 2017 return 0; 2018 2019 if (theme_handles_[theme_name]) 2020 return theme_handles_[theme_name]; 2021 2022 // Not found, try to load it. 2023 HANDLE handle = 0; 2024 switch (theme_name) { 2025 case BUTTON: 2026 handle = open_theme_(NULL, L"Button"); 2027 break; 2028 case LIST: 2029 handle = open_theme_(NULL, L"Listview"); 2030 break; 2031 case MENU: 2032 handle = open_theme_(NULL, L"Menu"); 2033 break; 2034 case MENULIST: 2035 handle = open_theme_(NULL, L"Combobox"); 2036 break; 2037 case SCROLLBAR: 2038 handle = open_theme_(NULL, L"Scrollbar"); 2039 break; 2040 case STATUS: 2041 handle = open_theme_(NULL, L"Status"); 2042 break; 2043 case TAB: 2044 handle = open_theme_(NULL, L"Tab"); 2045 break; 2046 case TEXTFIELD: 2047 handle = open_theme_(NULL, L"Edit"); 2048 break; 2049 case TRACKBAR: 2050 handle = open_theme_(NULL, L"Trackbar"); 2051 break; 2052 case WINDOW: 2053 handle = open_theme_(NULL, L"Window"); 2054 break; 2055 case PROGRESS: 2056 handle = open_theme_(NULL, L"Progress"); 2057 break; 2058 case SPIN: 2059 handle = open_theme_(NULL, L"Spin"); 2060 break; 2061 case LAST: 2062 NOTREACHED(); 2063 break; 2064 } 2065 theme_handles_[theme_name] = handle; 2066 return handle; 2067} 2068 2069} // namespace ui 2070