OLD | NEW |
(Empty) | |
| 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 |
| 37 namespace { |
| 38 |
| 39 // TODO: Obtain the correct colors using GetSysColor. |
| 40 // Theme colors returned by GetSystemColor(). |
| 41 const SkColor kInvalidColorIdColor = SkColorSetRGB(255, 0, 128); |
| 42 // Dialogs: |
| 43 const SkColor kDialogBackgroundColor = SkColorSetRGB(251, 251, 251); |
| 44 // FocusableBorder: |
| 45 const SkColor kFocusedBorderColor = SkColorSetRGB(0x4d, 0x90, 0xfe); |
| 46 const SkColor kUnfocusedBorderColor = SkColorSetRGB(0xd9, 0xd9, 0xd9); |
| 47 // Button: |
| 48 const SkColor kButtonBackgroundColor = SkColorSetRGB(0xde, 0xde, 0xde); |
| 49 const SkColor kButtonHighlightColor = SkColorSetARGB(200, 255, 255, 255); |
| 50 const SkColor kButtonHoverColor = SkColorSetRGB(6, 45, 117); |
| 51 const SkColor kButtonHoverBackgroundColor = SkColorSetRGB(0xEA, 0xEA, 0xEA); |
| 52 // MenuItem: |
| 53 const SkColor kEnabledMenuItemForegroundColor = SkColorSetRGB(6, 45, 117); |
| 54 const SkColor kDisabledMenuItemForegroundColor = SkColorSetRGB(161, 161, 146); |
| 55 const SkColor kFocusedMenuItemBackgroundColor = SkColorSetRGB(246, 249, 253); |
| 56 const SkColor kMenuSeparatorColor = SkColorSetARGB(50, 0, 0, 0); |
| 57 // Table: |
| 58 const SkColor kTreeSelectionBackgroundUnfocused = SkColorSetRGB(240, 240, 240); |
| 59 |
| 60 // Windows system color IDs cached and updated by the native theme. |
| 61 const 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 |
| 74 void 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 // |
| 114 int 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 |
| 124 RECT 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 |
| 132 namespace ui { |
| 133 |
| 134 bool NativeThemeWin::IsThemingActive() const { |
| 135 return is_theme_active_ && is_theme_active_(); |
| 136 } |
| 137 |
| 138 bool 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 |
| 150 HRESULT 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 |
| 165 SkColor 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 |
| 175 gfx::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 |
| 184 void NativeThemeWin::DisableTheming() const { |
| 185 if (set_theme_properties_) |
| 186 set_theme_properties_(0); |
| 187 } |
| 188 |
| 189 void 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 |
| 201 bool NativeThemeWin::IsClassicTheme(ThemeName name) const { |
| 202 return !theme_dll_ || !GetThemeHandle(name); |
| 203 } |
| 204 |
| 205 // static |
| 206 NativeThemeWin* NativeThemeWin::instance() { |
| 207 CR_DEFINE_STATIC_LOCAL(NativeThemeWin, s_native_theme, ()); |
| 208 return &s_native_theme; |
| 209 } |
| 210 |
| 211 gfx::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 |
| 254 void 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); |
| 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 |
| 317 NativeThemeWin::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 |
| 360 NativeThemeWin::~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 |
| 369 void NativeThemeWin::OnSysColorChange() { |
| 370 UpdateSystemColors(); |
| 371 is_using_high_contrast_valid_ = false; |
| 372 NotifyObservers(); |
| 373 } |
| 374 |
| 375 void 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 |
| 382 void 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); |
| 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 |
| 471 SkColor 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 |
| 649 void 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 |
| 724 HRESULT 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 |
| 737 HRESULT 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 |
| 825 HRESULT NativeThemeWin::PaintMenuSeparator( |
| 826 HDC hdc, |
| 827 const gfx::Rect& rect) const { |
| 828 RECT rect_win = rect.ToRECT(); |
| 829 |
| 830 HANDLE handle = GetThemeHandle(MENU); |
| 831 if (handle && draw_theme_) { |
| 832 // Delta is needed for non-classic to move separator up slightly. |
| 833 --rect_win.top; |
| 834 --rect_win.bottom; |
| 835 return draw_theme_(handle, hdc, MENU_POPUPSEPARATOR, MPI_NORMAL, &rect_win, |
| 836 NULL); |
| 837 } |
| 838 |
| 839 DrawEdge(hdc, &rect_win, EDGE_ETCHED, BF_TOP); |
| 840 return S_OK; |
| 841 } |
| 842 |
| 843 HRESULT NativeThemeWin::PaintMenuGutter(HDC hdc, |
| 844 const gfx::Rect& rect) const { |
| 845 RECT rect_win = rect.ToRECT(); |
| 846 HANDLE handle = GetThemeHandle(MENU); |
| 847 return (handle && draw_theme_) ? |
| 848 draw_theme_(handle, hdc, MENU_POPUPGUTTER, MPI_NORMAL, &rect_win, NULL) : |
| 849 E_NOTIMPL; |
| 850 } |
| 851 |
| 852 HRESULT NativeThemeWin::PaintMenuArrow( |
| 853 HDC hdc, |
| 854 State state, |
| 855 const gfx::Rect& rect, |
| 856 const MenuArrowExtraParams& extra) const { |
| 857 int state_id = MSM_NORMAL; |
| 858 if (state == kDisabled) |
| 859 state_id = MSM_DISABLED; |
| 860 |
| 861 HANDLE handle = GetThemeHandle(MENU); |
| 862 RECT rect_win = rect.ToRECT(); |
| 863 if (handle && draw_theme_) { |
| 864 if (extra.pointing_right) { |
| 865 return draw_theme_(handle, hdc, MENU_POPUPSUBMENU, state_id, &rect_win, |
| 866 NULL); |
| 867 } |
| 868 // There is no way to tell the uxtheme API to draw a left pointing arrow; it |
| 869 // doesn't have a flag equivalent to DFCS_MENUARROWRIGHT. But they are |
| 870 // needed for RTL locales on Vista. So use a memory DC and mirror the |
| 871 // region with GDI's StretchBlt. |
| 872 gfx::Rect r(rect); |
| 873 base::win::ScopedCreateDC mem_dc(CreateCompatibleDC(hdc)); |
| 874 base::win::ScopedBitmap mem_bitmap(CreateCompatibleBitmap(hdc, r.width(), |
| 875 r.height())); |
| 876 base::win::ScopedSelectObject select_bitmap(mem_dc.Get(), mem_bitmap); |
| 877 // Copy and horizontally mirror the background from hdc into mem_dc. Use |
| 878 // a negative-width source rect, starting at the rightmost pixel. |
| 879 StretchBlt(mem_dc.Get(), 0, 0, r.width(), r.height(), |
| 880 hdc, r.right()-1, r.y(), -r.width(), r.height(), SRCCOPY); |
| 881 // Draw the arrow. |
| 882 RECT theme_rect = {0, 0, r.width(), r.height()}; |
| 883 HRESULT result = draw_theme_(handle, mem_dc.Get(), MENU_POPUPSUBMENU, |
| 884 state_id, &theme_rect, NULL); |
| 885 // Copy and mirror the result back into mem_dc. |
| 886 StretchBlt(hdc, r.x(), r.y(), r.width(), r.height(), |
| 887 mem_dc.Get(), r.width()-1, 0, -r.width(), r.height(), SRCCOPY); |
| 888 return result; |
| 889 } |
| 890 |
| 891 // For some reason, Windows uses the name DFCS_MENUARROWRIGHT to indicate a |
| 892 // left pointing arrow. This makes the following statement counterintuitive. |
| 893 UINT pfc_state = extra.pointing_right ? DFCS_MENUARROW : DFCS_MENUARROWRIGHT; |
| 894 return PaintFrameControl(hdc, rect, DFC_MENU, pfc_state, extra.is_selected, |
| 895 state); |
| 896 } |
| 897 |
| 898 HRESULT NativeThemeWin::PaintMenuBackground(HDC hdc, |
| 899 const gfx::Rect& rect) const { |
| 900 HANDLE handle = GetThemeHandle(MENU); |
| 901 RECT rect_win = rect.ToRECT(); |
| 902 if (handle && draw_theme_) { |
| 903 HRESULT result = draw_theme_(handle, hdc, MENU_POPUPBACKGROUND, 0, |
| 904 &rect_win, NULL); |
| 905 FrameRect(hdc, &rect_win, GetSysColorBrush(COLOR_3DSHADOW)); |
| 906 return result; |
| 907 } |
| 908 |
| 909 FillRect(hdc, &rect_win, GetSysColorBrush(COLOR_MENU)); |
| 910 DrawEdge(hdc, &rect_win, EDGE_RAISED, BF_RECT); |
| 911 return S_OK; |
| 912 } |
| 913 |
| 914 HRESULT NativeThemeWin::PaintMenuCheck( |
| 915 HDC hdc, |
| 916 State state, |
| 917 const gfx::Rect& rect, |
| 918 const MenuCheckExtraParams& extra) const { |
| 919 HANDLE handle = GetThemeHandle(MENU); |
| 920 if (handle && draw_theme_) { |
| 921 const int state_id = extra.is_radio ? |
| 922 ((state == kDisabled) ? MC_BULLETDISABLED : MC_BULLETNORMAL) : |
| 923 ((state == kDisabled) ? MC_CHECKMARKDISABLED : MC_CHECKMARKNORMAL); |
| 924 RECT rect_win = rect.ToRECT(); |
| 925 return draw_theme_(handle, hdc, MENU_POPUPCHECK, state_id, &rect_win, NULL); |
| 926 } |
| 927 |
| 928 return PaintFrameControl(hdc, rect, DFC_MENU, |
| 929 extra.is_radio ? DFCS_MENUBULLET : DFCS_MENUCHECK, |
| 930 extra.is_selected, state); |
| 931 } |
| 932 |
| 933 HRESULT NativeThemeWin::PaintMenuCheckBackground(HDC hdc, |
| 934 State state, |
| 935 const gfx::Rect& rect) const { |
| 936 HANDLE handle = GetThemeHandle(MENU); |
| 937 if (!handle || !draw_theme_) |
| 938 return S_OK; // Nothing to do for background. |
| 939 |
| 940 int state_id = state == kDisabled ? MCB_DISABLED : MCB_NORMAL; |
| 941 RECT rect_win = rect.ToRECT(); |
| 942 return draw_theme_(handle, hdc, MENU_POPUPCHECKBACKGROUND, state_id, |
| 943 &rect_win, NULL); |
| 944 } |
| 945 |
| 946 HRESULT NativeThemeWin::PaintMenuItemBackground( |
| 947 HDC hdc, |
| 948 State state, |
| 949 const gfx::Rect& rect, |
| 950 const MenuItemExtraParams& extra) const { |
| 951 HANDLE handle = GetThemeHandle(MENU); |
| 952 RECT rect_win = rect.ToRECT(); |
| 953 int state_id = MPI_NORMAL; |
| 954 switch (state) { |
| 955 case kDisabled: |
| 956 state_id = extra.is_selected ? MPI_DISABLEDHOT : MPI_DISABLED; |
| 957 break; |
| 958 case kHovered: |
| 959 state_id = MPI_HOT; |
| 960 break; |
| 961 case kNormal: |
| 962 break; |
| 963 case kPressed: |
| 964 case kNumStates: |
| 965 NOTREACHED(); |
| 966 break; |
| 967 } |
| 968 |
| 969 if (handle && draw_theme_) |
| 970 return draw_theme_(handle, hdc, MENU_POPUPITEM, state_id, &rect_win, NULL); |
| 971 |
| 972 if (extra.is_selected) |
| 973 FillRect(hdc, &rect_win, GetSysColorBrush(COLOR_HIGHLIGHT)); |
| 974 return S_OK; |
| 975 } |
| 976 |
| 977 HRESULT NativeThemeWin::PaintPushButton(HDC hdc, |
| 978 Part part, |
| 979 State state, |
| 980 const gfx::Rect& rect, |
| 981 const ButtonExtraParams& extra) const { |
| 982 int state_id = extra.is_default ? PBS_DEFAULTED : PBS_NORMAL; |
| 983 switch (state) { |
| 984 case kDisabled: |
| 985 state_id = PBS_DISABLED; |
| 986 break; |
| 987 case kHovered: |
| 988 state_id = PBS_HOT; |
| 989 break; |
| 990 case kNormal: |
| 991 break; |
| 992 case kPressed: |
| 993 state_id = PBS_PRESSED; |
| 994 break; |
| 995 case kNumStates: |
| 996 NOTREACHED(); |
| 997 break; |
| 998 } |
| 999 |
| 1000 RECT rect_win = rect.ToRECT(); |
| 1001 return PaintButton(hdc, state, extra, BP_PUSHBUTTON, state_id, &rect_win); |
| 1002 } |
| 1003 |
| 1004 HRESULT NativeThemeWin::PaintRadioButton(HDC hdc, |
| 1005 Part part, |
| 1006 State state, |
| 1007 const gfx::Rect& rect, |
| 1008 const ButtonExtraParams& extra) const { |
| 1009 int state_id = extra.checked ? RBS_CHECKEDNORMAL : RBS_UNCHECKEDNORMAL; |
| 1010 switch (state) { |
| 1011 case kDisabled: |
| 1012 state_id = extra.checked ? RBS_CHECKEDDISABLED : RBS_UNCHECKEDDISABLED; |
| 1013 break; |
| 1014 case kHovered: |
| 1015 state_id = extra.checked ? RBS_CHECKEDHOT : RBS_UNCHECKEDHOT; |
| 1016 break; |
| 1017 case kNormal: |
| 1018 break; |
| 1019 case kPressed: |
| 1020 state_id = extra.checked ? RBS_CHECKEDPRESSED : RBS_UNCHECKEDPRESSED; |
| 1021 break; |
| 1022 case kNumStates: |
| 1023 NOTREACHED(); |
| 1024 break; |
| 1025 } |
| 1026 |
| 1027 RECT rect_win = rect.ToRECT(); |
| 1028 return PaintButton(hdc, state, extra, BP_RADIOBUTTON, state_id, &rect_win); |
| 1029 } |
| 1030 |
| 1031 HRESULT NativeThemeWin::PaintCheckbox(HDC hdc, |
| 1032 Part part, |
| 1033 State state, |
| 1034 const gfx::Rect& rect, |
| 1035 const ButtonExtraParams& extra) const { |
| 1036 int state_id = extra.checked ? |
| 1037 CBS_CHECKEDNORMAL : |
| 1038 (extra.indeterminate ? CBS_MIXEDNORMAL : CBS_UNCHECKEDNORMAL); |
| 1039 switch (state) { |
| 1040 case kDisabled: |
| 1041 state_id = extra.checked ? |
| 1042 CBS_CHECKEDDISABLED : |
| 1043 (extra.indeterminate ? CBS_MIXEDDISABLED : CBS_UNCHECKEDDISABLED); |
| 1044 break; |
| 1045 case kHovered: |
| 1046 state_id = extra.checked ? |
| 1047 CBS_CHECKEDHOT : |
| 1048 (extra.indeterminate ? CBS_MIXEDHOT : CBS_UNCHECKEDHOT); |
| 1049 break; |
| 1050 case kNormal: |
| 1051 break; |
| 1052 case kPressed: |
| 1053 state_id = extra.checked ? |
| 1054 CBS_CHECKEDPRESSED : |
| 1055 (extra.indeterminate ? CBS_MIXEDPRESSED : CBS_UNCHECKEDPRESSED); |
| 1056 break; |
| 1057 case kNumStates: |
| 1058 NOTREACHED(); |
| 1059 break; |
| 1060 } |
| 1061 |
| 1062 RECT rect_win = rect.ToRECT(); |
| 1063 return PaintButton(hdc, state, extra, BP_CHECKBOX, state_id, &rect_win); |
| 1064 } |
| 1065 |
| 1066 HRESULT NativeThemeWin::PaintMenuList(HDC hdc, |
| 1067 State state, |
| 1068 const gfx::Rect& rect, |
| 1069 const MenuListExtraParams& extra) const { |
| 1070 HANDLE handle = GetThemeHandle(MENULIST); |
| 1071 RECT rect_win = rect.ToRECT(); |
| 1072 int state_id = CBXS_NORMAL; |
| 1073 switch (state) { |
| 1074 case kDisabled: |
| 1075 state_id = CBXS_DISABLED; |
| 1076 break; |
| 1077 case kHovered: |
| 1078 state_id = CBXS_HOT; |
| 1079 break; |
| 1080 case kNormal: |
| 1081 break; |
| 1082 case kPressed: |
| 1083 state_id = CBXS_PRESSED; |
| 1084 break; |
| 1085 case kNumStates: |
| 1086 NOTREACHED(); |
| 1087 break; |
| 1088 } |
| 1089 |
| 1090 if (handle && draw_theme_) |
| 1091 return draw_theme_(handle, hdc, CP_DROPDOWNBUTTON, state_id, &rect_win, |
| 1092 NULL); |
| 1093 |
| 1094 // Draw it manually. |
| 1095 DrawFrameControl(hdc, &rect_win, DFC_SCROLL, |
| 1096 DFCS_SCROLLCOMBOBOX | extra.classic_state); |
| 1097 return S_OK; |
| 1098 } |
| 1099 |
| 1100 HRESULT NativeThemeWin::PaintScrollbarArrow( |
| 1101 HDC hdc, |
| 1102 Part part, |
| 1103 State state, |
| 1104 const gfx::Rect& rect, |
| 1105 const ScrollbarArrowExtraParams& extra) const { |
| 1106 static const int state_id_matrix[4][kNumStates] = { |
| 1107 ABS_DOWNDISABLED, ABS_DOWNHOT, ABS_DOWNNORMAL, ABS_DOWNPRESSED, |
| 1108 ABS_LEFTDISABLED, ABS_LEFTHOT, ABS_LEFTNORMAL, ABS_LEFTPRESSED, |
| 1109 ABS_RIGHTDISABLED, ABS_RIGHTHOT, ABS_RIGHTNORMAL, ABS_RIGHTPRESSED, |
| 1110 ABS_UPDISABLED, ABS_UPHOT, ABS_UPNORMAL, ABS_UPPRESSED |
| 1111 }; |
| 1112 HANDLE handle = GetThemeHandle(SCROLLBAR); |
| 1113 RECT rect_win = rect.ToRECT(); |
| 1114 if (handle && draw_theme_) { |
| 1115 int index = part - kScrollbarDownArrow; |
| 1116 DCHECK_GE(index, 0); |
| 1117 DCHECK_LT(static_cast<size_t>(index), arraysize(state_id_matrix)); |
| 1118 int state_id = state_id_matrix[index][state]; |
| 1119 |
| 1120 // Hovering means that the cursor is over the scroolbar, but not over the |
| 1121 // specific arrow itself. We don't want to show it "hot" mode, but only |
| 1122 // in "hover" mode. |
| 1123 if (state == kHovered && extra.is_hovering) { |
| 1124 switch (part) { |
| 1125 case kScrollbarDownArrow: |
| 1126 state_id = ABS_DOWNHOVER; |
| 1127 break; |
| 1128 case kScrollbarLeftArrow: |
| 1129 state_id = ABS_LEFTHOVER; |
| 1130 break; |
| 1131 case kScrollbarRightArrow: |
| 1132 state_id = ABS_RIGHTHOVER; |
| 1133 break; |
| 1134 case kScrollbarUpArrow: |
| 1135 state_id = ABS_UPHOVER; |
| 1136 break; |
| 1137 default: |
| 1138 NOTREACHED(); |
| 1139 break; |
| 1140 } |
| 1141 } |
| 1142 return PaintScaledTheme(handle, hdc, SBP_ARROWBTN, state_id, rect); |
| 1143 } |
| 1144 |
| 1145 int classic_state = DFCS_SCROLLDOWN; |
| 1146 switch (part) { |
| 1147 case kScrollbarDownArrow: |
| 1148 break; |
| 1149 case kScrollbarLeftArrow: |
| 1150 classic_state = DFCS_SCROLLLEFT; |
| 1151 break; |
| 1152 case kScrollbarRightArrow: |
| 1153 classic_state = DFCS_SCROLLRIGHT; |
| 1154 break; |
| 1155 case kScrollbarUpArrow: |
| 1156 classic_state = DFCS_SCROLLUP; |
| 1157 break; |
| 1158 default: |
| 1159 NOTREACHED(); |
| 1160 break; |
| 1161 } |
| 1162 switch (state) { |
| 1163 case kDisabled: |
| 1164 classic_state |= DFCS_INACTIVE; |
| 1165 break; |
| 1166 case kHovered: |
| 1167 classic_state |= DFCS_HOT; |
| 1168 break; |
| 1169 case kNormal: |
| 1170 break; |
| 1171 case kPressed: |
| 1172 classic_state |= DFCS_PUSHED; |
| 1173 break; |
| 1174 case kNumStates: |
| 1175 NOTREACHED(); |
| 1176 break; |
| 1177 } |
| 1178 DrawFrameControl(hdc, &rect_win, DFC_SCROLL, classic_state); |
| 1179 return S_OK; |
| 1180 } |
| 1181 |
| 1182 HRESULT NativeThemeWin::PaintScrollbarThumb( |
| 1183 HDC hdc, |
| 1184 Part part, |
| 1185 State state, |
| 1186 const gfx::Rect& rect, |
| 1187 const ScrollbarThumbExtraParams& extra) const { |
| 1188 HANDLE handle = GetThemeHandle(SCROLLBAR); |
| 1189 RECT rect_win = rect.ToRECT(); |
| 1190 |
| 1191 int part_id = SBP_THUMBBTNVERT; |
| 1192 switch (part) { |
| 1193 case kScrollbarHorizontalThumb: |
| 1194 part_id = SBP_THUMBBTNHORZ; |
| 1195 break; |
| 1196 case kScrollbarVerticalThumb: |
| 1197 break; |
| 1198 case kScrollbarHorizontalGripper: |
| 1199 part_id = SBP_GRIPPERHORZ; |
| 1200 break; |
| 1201 case kScrollbarVerticalGripper: |
| 1202 part_id = SBP_GRIPPERVERT; |
| 1203 break; |
| 1204 default: |
| 1205 NOTREACHED(); |
| 1206 break; |
| 1207 } |
| 1208 |
| 1209 int state_id = SCRBS_NORMAL; |
| 1210 switch (state) { |
| 1211 case kDisabled: |
| 1212 state_id = SCRBS_DISABLED; |
| 1213 break; |
| 1214 case kHovered: |
| 1215 state_id = extra.is_hovering ? SCRBS_HOVER : SCRBS_HOT; |
| 1216 break; |
| 1217 case kNormal: |
| 1218 break; |
| 1219 case kPressed: |
| 1220 state_id = SCRBS_PRESSED; |
| 1221 break; |
| 1222 case kNumStates: |
| 1223 NOTREACHED(); |
| 1224 break; |
| 1225 } |
| 1226 |
| 1227 if (handle && draw_theme_) |
| 1228 return PaintScaledTheme(handle, hdc, part_id, state_id, rect); |
| 1229 |
| 1230 // Draw it manually. |
| 1231 if ((part_id == SBP_THUMBBTNHORZ) || (part_id == SBP_THUMBBTNVERT)) |
| 1232 DrawEdge(hdc, &rect_win, EDGE_RAISED, BF_RECT | BF_MIDDLE); |
| 1233 // Classic mode doesn't have a gripper. |
| 1234 return S_OK; |
| 1235 } |
| 1236 |
| 1237 HRESULT NativeThemeWin::PaintScrollbarTrack( |
| 1238 SkCanvas* canvas, |
| 1239 HDC hdc, |
| 1240 Part part, |
| 1241 State state, |
| 1242 const gfx::Rect& rect, |
| 1243 const ScrollbarTrackExtraParams& extra) const { |
| 1244 HANDLE handle = GetThemeHandle(SCROLLBAR); |
| 1245 RECT rect_win = rect.ToRECT(); |
| 1246 |
| 1247 const int part_id = extra.is_upper ? |
| 1248 ((part == kScrollbarHorizontalTrack) ? |
| 1249 SBP_UPPERTRACKHORZ : SBP_UPPERTRACKVERT) : |
| 1250 ((part == kScrollbarHorizontalTrack) ? |
| 1251 SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT); |
| 1252 |
| 1253 int state_id = SCRBS_NORMAL; |
| 1254 switch (state) { |
| 1255 case kDisabled: |
| 1256 state_id = SCRBS_DISABLED; |
| 1257 break; |
| 1258 case kHovered: |
| 1259 state_id = SCRBS_HOVER; |
| 1260 break; |
| 1261 case kNormal: |
| 1262 break; |
| 1263 case kPressed: |
| 1264 state_id = SCRBS_PRESSED; |
| 1265 break; |
| 1266 case kNumStates: |
| 1267 NOTREACHED(); |
| 1268 break; |
| 1269 } |
| 1270 |
| 1271 if (handle && draw_theme_) |
| 1272 return draw_theme_(handle, hdc, part_id, state_id, &rect_win, NULL); |
| 1273 |
| 1274 // Draw it manually. |
| 1275 if ((system_colors_[COLOR_SCROLLBAR] != system_colors_[COLOR_3DFACE]) && |
| 1276 (system_colors_[COLOR_SCROLLBAR] != system_colors_[COLOR_WINDOW])) { |
| 1277 FillRect(hdc, &rect_win, reinterpret_cast<HBRUSH>(COLOR_SCROLLBAR + 1)); |
| 1278 } else { |
| 1279 SkPaint paint; |
| 1280 RECT align_rect = gfx::Rect(extra.track_x, extra.track_y, extra.track_width, |
| 1281 extra.track_height).ToRECT(); |
| 1282 SetCheckerboardShader(&paint, align_rect); |
| 1283 canvas->drawIRect(skia::RECTToSkIRect(rect_win), paint); |
| 1284 } |
| 1285 if (extra.classic_state & DFCS_PUSHED) |
| 1286 InvertRect(hdc, &rect_win); |
| 1287 return S_OK; |
| 1288 } |
| 1289 |
| 1290 HRESULT NativeThemeWin::PaintSpinButton( |
| 1291 HDC hdc, |
| 1292 Part part, |
| 1293 State state, |
| 1294 const gfx::Rect& rect, |
| 1295 const InnerSpinButtonExtraParams& extra) const { |
| 1296 HANDLE handle = GetThemeHandle(SPIN); |
| 1297 RECT rect_win = rect.ToRECT(); |
| 1298 int part_id = extra.spin_up ? SPNP_UP : SPNP_DOWN; |
| 1299 int state_id = extra.spin_up ? UPS_NORMAL : DNS_NORMAL; |
| 1300 switch (state) { |
| 1301 case kDisabled: |
| 1302 state_id = extra.spin_up ? UPS_DISABLED : DNS_DISABLED; |
| 1303 break; |
| 1304 case kHovered: |
| 1305 state_id = extra.spin_up ? UPS_HOT : DNS_HOT; |
| 1306 break; |
| 1307 case kNormal: |
| 1308 break; |
| 1309 case kPressed: |
| 1310 state_id = extra.spin_up ? UPS_PRESSED : DNS_PRESSED; |
| 1311 break; |
| 1312 case kNumStates: |
| 1313 NOTREACHED(); |
| 1314 break; |
| 1315 } |
| 1316 |
| 1317 if (handle && draw_theme_) |
| 1318 return draw_theme_(handle, hdc, part_id, state_id, &rect_win, NULL); |
| 1319 DrawFrameControl(hdc, &rect_win, DFC_SCROLL, extra.classic_state); |
| 1320 return S_OK; |
| 1321 } |
| 1322 |
| 1323 HRESULT NativeThemeWin::PaintTrackbar( |
| 1324 SkCanvas* canvas, |
| 1325 HDC hdc, |
| 1326 Part part, |
| 1327 State state, |
| 1328 const gfx::Rect& rect, |
| 1329 const TrackbarExtraParams& extra) const { |
| 1330 const int part_id = extra.vertical ? |
| 1331 ((part == kTrackbarTrack) ? TKP_TRACKVERT : TKP_THUMBVERT) : |
| 1332 ((part == kTrackbarTrack) ? TKP_TRACK : TKP_THUMBBOTTOM); |
| 1333 |
| 1334 int state_id = TUS_NORMAL; |
| 1335 switch (state) { |
| 1336 case kDisabled: |
| 1337 state_id = TUS_DISABLED; |
| 1338 break; |
| 1339 case kHovered: |
| 1340 state_id = TUS_HOT; |
| 1341 break; |
| 1342 case kNormal: |
| 1343 break; |
| 1344 case kPressed: |
| 1345 state_id = TUS_PRESSED; |
| 1346 break; |
| 1347 case kNumStates: |
| 1348 NOTREACHED(); |
| 1349 break; |
| 1350 } |
| 1351 |
| 1352 // Make the channel be 4 px thick in the center of the supplied rect. (4 px |
| 1353 // matches what XP does in various menus; GetThemePartSize() doesn't seem to |
| 1354 // return good values here.) |
| 1355 RECT rect_win = rect.ToRECT(); |
| 1356 RECT channel_rect = rect.ToRECT(); |
| 1357 const int channel_thickness = 4; |
| 1358 if (part_id == TKP_TRACK) { |
| 1359 channel_rect.top += |
| 1360 ((channel_rect.bottom - channel_rect.top - channel_thickness) / 2); |
| 1361 channel_rect.bottom = channel_rect.top + channel_thickness; |
| 1362 } else if (part_id == TKP_TRACKVERT) { |
| 1363 channel_rect.left += |
| 1364 ((channel_rect.right - channel_rect.left - channel_thickness) / 2); |
| 1365 channel_rect.right = channel_rect.left + channel_thickness; |
| 1366 } // else this isn't actually a channel, so |channel_rect| == |rect|. |
| 1367 |
| 1368 HANDLE handle = GetThemeHandle(TRACKBAR); |
| 1369 if (handle && draw_theme_) |
| 1370 return draw_theme_(handle, hdc, part_id, state_id, &channel_rect, NULL); |
| 1371 |
| 1372 // Classic mode, draw it manually. |
| 1373 if ((part_id == TKP_TRACK) || (part_id == TKP_TRACKVERT)) { |
| 1374 DrawEdge(hdc, &channel_rect, EDGE_SUNKEN, BF_RECT); |
| 1375 } else if (part_id == TKP_THUMBVERT) { |
| 1376 DrawEdge(hdc, &rect_win, EDGE_RAISED, BF_RECT | BF_SOFT | BF_MIDDLE); |
| 1377 } else { |
| 1378 // Split rect into top and bottom pieces. |
| 1379 RECT top_section = rect.ToRECT(); |
| 1380 RECT bottom_section = rect.ToRECT(); |
| 1381 top_section.bottom -= ((bottom_section.right - bottom_section.left) / 2); |
| 1382 bottom_section.top = top_section.bottom; |
| 1383 DrawEdge(hdc, &top_section, EDGE_RAISED, |
| 1384 BF_LEFT | BF_TOP | BF_RIGHT | BF_SOFT | BF_MIDDLE | BF_ADJUST); |
| 1385 |
| 1386 // Split triangular piece into two diagonals. |
| 1387 RECT& left_half = bottom_section; |
| 1388 RECT right_half = bottom_section; |
| 1389 right_half.left += ((bottom_section.right - bottom_section.left) / 2); |
| 1390 left_half.right = right_half.left; |
| 1391 DrawEdge(hdc, &left_half, EDGE_RAISED, |
| 1392 BF_DIAGONAL_ENDTOPLEFT | BF_SOFT | BF_MIDDLE | BF_ADJUST); |
| 1393 DrawEdge(hdc, &right_half, EDGE_RAISED, |
| 1394 BF_DIAGONAL_ENDBOTTOMLEFT | BF_SOFT | BF_MIDDLE | BF_ADJUST); |
| 1395 |
| 1396 // If the button is pressed, draw hatching. |
| 1397 if (extra.classic_state & DFCS_PUSHED) { |
| 1398 SkPaint paint; |
| 1399 SetCheckerboardShader(&paint, rect_win); |
| 1400 |
| 1401 // Fill all three pieces with the pattern. |
| 1402 canvas->drawIRect(skia::RECTToSkIRect(top_section), paint); |
| 1403 |
| 1404 SkScalar left_triangle_top = SkIntToScalar(left_half.top); |
| 1405 SkScalar left_triangle_right = SkIntToScalar(left_half.right); |
| 1406 SkPath left_triangle; |
| 1407 left_triangle.moveTo(SkIntToScalar(left_half.left), left_triangle_top); |
| 1408 left_triangle.lineTo(left_triangle_right, left_triangle_top); |
| 1409 left_triangle.lineTo(left_triangle_right, |
| 1410 SkIntToScalar(left_half.bottom)); |
| 1411 left_triangle.close(); |
| 1412 canvas->drawPath(left_triangle, paint); |
| 1413 |
| 1414 SkScalar right_triangle_left = SkIntToScalar(right_half.left); |
| 1415 SkScalar right_triangle_top = SkIntToScalar(right_half.top); |
| 1416 SkPath right_triangle; |
| 1417 right_triangle.moveTo(right_triangle_left, right_triangle_top); |
| 1418 right_triangle.lineTo(SkIntToScalar(right_half.right), |
| 1419 right_triangle_top); |
| 1420 right_triangle.lineTo(right_triangle_left, |
| 1421 SkIntToScalar(right_half.bottom)); |
| 1422 right_triangle.close(); |
| 1423 canvas->drawPath(right_triangle, paint); |
| 1424 } |
| 1425 } |
| 1426 return S_OK; |
| 1427 } |
| 1428 |
| 1429 HRESULT NativeThemeWin::PaintProgressBar( |
| 1430 HDC hdc, |
| 1431 const gfx::Rect& rect, |
| 1432 const ProgressBarExtraParams& extra) const { |
| 1433 // There is no documentation about the animation speed, frame-rate, nor |
| 1434 // size of moving overlay of the indeterminate progress bar. |
| 1435 // So we just observed real-world programs and guessed following parameters. |
| 1436 const int kDeterminateOverlayPixelsPerSecond = 300; |
| 1437 const int kDeterminateOverlayWidth = 120; |
| 1438 const int kIndeterminateOverlayPixelsPerSecond = 175; |
| 1439 const int kVistaIndeterminateOverlayWidth = 120; |
| 1440 const int kXPIndeterminateOverlayWidth = 55; |
| 1441 // The thickness of the bar frame inside |value_rect| |
| 1442 const int kXPBarPadding = 3; |
| 1443 |
| 1444 RECT bar_rect = rect.ToRECT(); |
| 1445 RECT value_rect = gfx::Rect(extra.value_rect_x, |
| 1446 extra.value_rect_y, |
| 1447 extra.value_rect_width, |
| 1448 extra.value_rect_height).ToRECT(); |
| 1449 |
| 1450 HANDLE handle = GetThemeHandle(PROGRESS); |
| 1451 if (!handle || !draw_theme_ || !draw_theme_ex_) { |
| 1452 FillRect(hdc, &bar_rect, GetSysColorBrush(COLOR_BTNFACE)); |
| 1453 FillRect(hdc, &value_rect, GetSysColorBrush(COLOR_BTNSHADOW)); |
| 1454 DrawEdge(hdc, &bar_rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); |
| 1455 return S_OK; |
| 1456 } |
| 1457 |
| 1458 draw_theme_(handle, hdc, PP_BAR, 0, &bar_rect, NULL); |
| 1459 |
| 1460 bool pre_vista = base::win::GetVersion() < base::win::VERSION_VISTA; |
| 1461 int bar_width = bar_rect.right - bar_rect.left; |
| 1462 if (!extra.determinate) { |
| 1463 // The glossy overlay for the indeterminate progress bar has a small pause |
| 1464 // after each animation. We emulate this by adding an invisible margin the |
| 1465 // animation has to traverse. |
| 1466 int width_with_margin = bar_width + kIndeterminateOverlayPixelsPerSecond; |
| 1467 int overlay_width = pre_vista ? |
| 1468 kXPIndeterminateOverlayWidth : kVistaIndeterminateOverlayWidth; |
| 1469 RECT overlay_rect = bar_rect; |
| 1470 overlay_rect.left += ComputeAnimationProgress( |
| 1471 width_with_margin, overlay_width, kIndeterminateOverlayPixelsPerSecond, |
| 1472 extra.animated_seconds); |
| 1473 overlay_rect.right = overlay_rect.left + overlay_width; |
| 1474 if (pre_vista) { |
| 1475 RECT shrunk_rect = InsetRect(&overlay_rect, kXPBarPadding); |
| 1476 RECT shrunk_bar_rect = InsetRect(&bar_rect, kXPBarPadding); |
| 1477 draw_theme_(handle, hdc, PP_CHUNK, 0, &shrunk_rect, &shrunk_bar_rect); |
| 1478 } else { |
| 1479 draw_theme_(handle, hdc, PP_MOVEOVERLAY, 0, &overlay_rect, &bar_rect); |
| 1480 } |
| 1481 return S_OK; |
| 1482 } |
| 1483 |
| 1484 // We care about the direction here because PP_CHUNK painting is asymmetric. |
| 1485 // TODO(morrita): This RTL guess can be wrong. We should pass in the |
| 1486 // direction from WebKit. |
| 1487 const DTBGOPTS value_draw_options = { |
| 1488 sizeof(DTBGOPTS), |
| 1489 (bar_rect.right == value_rect.right && bar_rect.left != value_rect.left) ? |
| 1490 DTBG_MIRRORDC : 0, |
| 1491 bar_rect |
| 1492 }; |
| 1493 if (pre_vista) { |
| 1494 // On XP, the progress bar is chunk-style and has no glossy effect. We need |
| 1495 // to shrink the destination rect to fit the part inside the bar with an |
| 1496 // appropriate margin. |
| 1497 RECT shrunk_value_rect = InsetRect(&value_rect, kXPBarPadding); |
| 1498 draw_theme_ex_(handle, hdc, PP_CHUNK, 0, &shrunk_value_rect, |
| 1499 &value_draw_options); |
| 1500 } else { |
| 1501 // On Vista or later, the progress bar part has a single-block value part |
| 1502 // and a glossy effect. The value part has exactly same height as the bar |
| 1503 // part, so we don't need to shrink the rect. |
| 1504 draw_theme_ex_(handle, hdc, PP_FILL, 0, &value_rect, &value_draw_options); |
| 1505 |
| 1506 RECT overlay_rect = value_rect; |
| 1507 overlay_rect.left += ComputeAnimationProgress( |
| 1508 bar_width, kDeterminateOverlayWidth, kDeterminateOverlayPixelsPerSecond, |
| 1509 extra.animated_seconds); |
| 1510 overlay_rect.right = overlay_rect.left + kDeterminateOverlayWidth; |
| 1511 draw_theme_(handle, hdc, PP_MOVEOVERLAY, 0, &overlay_rect, &value_rect); |
| 1512 } |
| 1513 return S_OK; |
| 1514 } |
| 1515 |
| 1516 HRESULT NativeThemeWin::PaintWindowResizeGripper(HDC hdc, |
| 1517 const gfx::Rect& rect) const { |
| 1518 HANDLE handle = GetThemeHandle(STATUS); |
| 1519 RECT rect_win = rect.ToRECT(); |
| 1520 if (handle && draw_theme_) { |
| 1521 // Paint the status bar gripper. There doesn't seem to be a standard |
| 1522 // gripper in Windows for the space between scrollbars. This is pretty |
| 1523 // close, but it's supposed to be painted over a status bar. |
| 1524 return draw_theme_(handle, hdc, SP_GRIPPER, 0, &rect_win, NULL); |
| 1525 } |
| 1526 |
| 1527 // Draw a windows classic scrollbar gripper. |
| 1528 DrawFrameControl(hdc, &rect_win, DFC_SCROLL, DFCS_SCROLLSIZEGRIP); |
| 1529 return S_OK; |
| 1530 } |
| 1531 |
| 1532 HRESULT NativeThemeWin::PaintTabPanelBackground(HDC hdc, |
| 1533 const gfx::Rect& rect) const { |
| 1534 HANDLE handle = GetThemeHandle(TAB); |
| 1535 RECT rect_win = rect.ToRECT(); |
| 1536 if (handle && draw_theme_) |
| 1537 return draw_theme_(handle, hdc, TABP_BODY, 0, &rect_win, NULL); |
| 1538 |
| 1539 // Classic just renders a flat color background. |
| 1540 FillRect(hdc, &rect_win, reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1)); |
| 1541 return S_OK; |
| 1542 } |
| 1543 |
| 1544 HRESULT NativeThemeWin::PaintTextField( |
| 1545 HDC hdc, |
| 1546 Part part, |
| 1547 State state, |
| 1548 const gfx::Rect& rect, |
| 1549 const TextFieldExtraParams& extra) const { |
| 1550 int state_id = ETS_NORMAL; |
| 1551 switch (state) { |
| 1552 case kDisabled: |
| 1553 state_id = ETS_DISABLED; |
| 1554 break; |
| 1555 case kHovered: |
| 1556 state_id = ETS_HOT; |
| 1557 break; |
| 1558 case kNormal: |
| 1559 if (extra.is_read_only) |
| 1560 state_id = ETS_READONLY; |
| 1561 else if (extra.is_focused) |
| 1562 state_id = ETS_FOCUSED; |
| 1563 break; |
| 1564 case kPressed: |
| 1565 state_id = ETS_SELECTED; |
| 1566 break; |
| 1567 case kNumStates: |
| 1568 NOTREACHED(); |
| 1569 break; |
| 1570 } |
| 1571 |
| 1572 RECT rect_win = rect.ToRECT(); |
| 1573 return PaintTextField(hdc, EP_EDITTEXT, state_id, extra.classic_state, |
| 1574 &rect_win, |
| 1575 skia::SkColorToCOLORREF(extra.background_color), |
| 1576 extra.fill_content_area, extra.draw_edges); |
| 1577 } |
| 1578 |
| 1579 HRESULT NativeThemeWin::PaintTextField(HDC hdc, |
| 1580 int part_id, |
| 1581 int state_id, |
| 1582 int classic_state, |
| 1583 RECT* rect, |
| 1584 COLORREF color, |
| 1585 bool fill_content_area, |
| 1586 bool draw_edges) const { |
| 1587 // TODO(ojan): http://b/1210017 Figure out how to give the ability to |
| 1588 // exclude individual edges from being drawn. |
| 1589 |
| 1590 HANDLE handle = GetThemeHandle(TEXTFIELD); |
| 1591 // TODO(mpcomplete): can we detect if the color is specified by the user, |
| 1592 // and if not, just use the system color? |
| 1593 // CreateSolidBrush() accepts a RGB value but alpha must be 0. |
| 1594 base::win::ScopedGDIObject<HBRUSH> bg_brush(CreateSolidBrush(color)); |
| 1595 // DrawThemeBackgroundEx was introduced in XP SP2, so that it's possible |
| 1596 // draw_theme_ex_ is NULL and draw_theme_ is non-null. |
| 1597 if (!handle || (!draw_theme_ex_ && (!draw_theme_ || !draw_edges))) { |
| 1598 // Draw it manually. |
| 1599 if (draw_edges) |
| 1600 DrawEdge(hdc, rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); |
| 1601 |
| 1602 if (fill_content_area) { |
| 1603 FillRect(hdc, rect, (classic_state & DFCS_INACTIVE) ? |
| 1604 reinterpret_cast<HBRUSH>(COLOR_BTNFACE + 1) : bg_brush); |
| 1605 } |
| 1606 return S_OK; |
| 1607 } |
| 1608 |
| 1609 static const DTBGOPTS omit_border_options = { |
| 1610 sizeof(DTBGOPTS), |
| 1611 DTBG_OMITBORDER, |
| 1612 { 0, 0, 0, 0 } |
| 1613 }; |
| 1614 HRESULT hr = draw_theme_ex_ ? |
| 1615 draw_theme_ex_(handle, hdc, part_id, state_id, rect, |
| 1616 draw_edges ? NULL : &omit_border_options) : |
| 1617 draw_theme_(handle, hdc, part_id, state_id, rect, NULL); |
| 1618 |
| 1619 // TODO(maruel): Need to be fixed if get_theme_content_rect_ is NULL. |
| 1620 if (fill_content_area && get_theme_content_rect_) { |
| 1621 RECT content_rect; |
| 1622 hr = get_theme_content_rect_(handle, hdc, part_id, state_id, rect, |
| 1623 &content_rect); |
| 1624 FillRect(hdc, &content_rect, bg_brush); |
| 1625 } |
| 1626 return hr; |
| 1627 } |
| 1628 |
| 1629 HRESULT NativeThemeWin::PaintScaledTheme(HANDLE theme, |
| 1630 HDC hdc, |
| 1631 int part_id, |
| 1632 int state_id, |
| 1633 const gfx::Rect& rect) const { |
| 1634 // Correct the scaling and positioning of sub-components such as scrollbar |
| 1635 // arrows and thumb grippers in the event that the world transform applies |
| 1636 // scaling (e.g. in high-DPI mode). |
| 1637 XFORM save_transform; |
| 1638 if (GetWorldTransform(hdc, &save_transform)) { |
| 1639 float scale = save_transform.eM11; |
| 1640 if (scale != 1 && save_transform.eM12 == 0) { |
| 1641 ModifyWorldTransform(hdc, NULL, MWT_IDENTITY); |
| 1642 gfx::Rect scaled_rect(gfx::ToEnclosedRect(gfx::ScaleRect(rect, scale))); |
| 1643 scaled_rect.Offset(save_transform.eDx, save_transform.eDy); |
| 1644 RECT bounds = scaled_rect.ToRECT(); |
| 1645 HRESULT result = draw_theme_(theme, hdc, part_id, state_id, &bounds, |
| 1646 NULL); |
| 1647 SetWorldTransform(hdc, &save_transform); |
| 1648 return result; |
| 1649 } |
| 1650 } |
| 1651 RECT bounds = rect.ToRECT(); |
| 1652 return draw_theme_(theme, hdc, part_id, state_id, &bounds, NULL); |
| 1653 } |
| 1654 |
| 1655 // static |
| 1656 NativeThemeWin::ThemeName NativeThemeWin::GetThemeName(Part part) { |
| 1657 switch (part) { |
| 1658 case kCheckbox: |
| 1659 case kPushButton: |
| 1660 case kRadio: |
| 1661 return BUTTON; |
| 1662 case kInnerSpinButton: |
| 1663 return SPIN; |
| 1664 case kMenuList: |
| 1665 case kMenuCheck: |
| 1666 case kMenuPopupArrow: |
| 1667 case kMenuPopupGutter: |
| 1668 case kMenuPopupSeparator: |
| 1669 return MENU; |
| 1670 case kProgressBar: |
| 1671 return PROGRESS; |
| 1672 case kScrollbarDownArrow: |
| 1673 case kScrollbarLeftArrow: |
| 1674 case kScrollbarRightArrow: |
| 1675 case kScrollbarUpArrow: |
| 1676 case kScrollbarHorizontalThumb: |
| 1677 case kScrollbarVerticalThumb: |
| 1678 case kScrollbarHorizontalTrack: |
| 1679 case kScrollbarVerticalTrack: |
| 1680 return SCROLLBAR; |
| 1681 case kSliderTrack: |
| 1682 case kSliderThumb: |
| 1683 return TRACKBAR; |
| 1684 case kTextField: |
| 1685 return TEXTFIELD; |
| 1686 case kWindowResizeGripper: |
| 1687 return STATUS; |
| 1688 case kComboboxArrow: |
| 1689 case kMenuCheckBackground: |
| 1690 case kMenuPopupBackground: |
| 1691 case kMenuItemBackground: |
| 1692 case kScrollbarHorizontalGripper: |
| 1693 case kScrollbarVerticalGripper: |
| 1694 case kScrollbarCorner: |
| 1695 case kTabPanelBackground: |
| 1696 case kTrackbarThumb: |
| 1697 case kTrackbarTrack: |
| 1698 case kMaxPart: |
| 1699 NOTREACHED(); |
| 1700 } |
| 1701 return LAST; |
| 1702 } |
| 1703 |
| 1704 // static |
| 1705 int NativeThemeWin::GetWindowsPart(Part part, |
| 1706 State state, |
| 1707 const ExtraParams& extra) { |
| 1708 switch (part) { |
| 1709 case kCheckbox: |
| 1710 return BP_CHECKBOX; |
| 1711 case kMenuCheck: |
| 1712 return MENU_POPUPCHECK; |
| 1713 case kMenuPopupArrow: |
| 1714 return MENU_POPUPSUBMENU; |
| 1715 case kMenuPopupGutter: |
| 1716 return MENU_POPUPGUTTER; |
| 1717 case kMenuPopupSeparator: |
| 1718 return MENU_POPUPSEPARATOR; |
| 1719 case kPushButton: |
| 1720 return BP_PUSHBUTTON; |
| 1721 case kRadio: |
| 1722 return BP_RADIOBUTTON; |
| 1723 case kScrollbarDownArrow: |
| 1724 case kScrollbarLeftArrow: |
| 1725 case kScrollbarRightArrow: |
| 1726 case kScrollbarUpArrow: |
| 1727 return SBP_ARROWBTN; |
| 1728 case kScrollbarHorizontalThumb: |
| 1729 return SBP_THUMBBTNHORZ; |
| 1730 case kScrollbarVerticalThumb: |
| 1731 return SBP_THUMBBTNVERT; |
| 1732 case kWindowResizeGripper: |
| 1733 return SP_GRIPPER; |
| 1734 case kComboboxArrow: |
| 1735 case kInnerSpinButton: |
| 1736 case kMenuList: |
| 1737 case kMenuCheckBackground: |
| 1738 case kMenuPopupBackground: |
| 1739 case kMenuItemBackground: |
| 1740 case kProgressBar: |
| 1741 case kScrollbarHorizontalTrack: |
| 1742 case kScrollbarVerticalTrack: |
| 1743 case kScrollbarHorizontalGripper: |
| 1744 case kScrollbarVerticalGripper: |
| 1745 case kScrollbarCorner: |
| 1746 case kSliderTrack: |
| 1747 case kSliderThumb: |
| 1748 case kTabPanelBackground: |
| 1749 case kTextField: |
| 1750 case kTrackbarThumb: |
| 1751 case kTrackbarTrack: |
| 1752 case kMaxPart: |
| 1753 NOTREACHED(); |
| 1754 } |
| 1755 return 0; |
| 1756 } |
| 1757 |
| 1758 int NativeThemeWin::GetWindowsState(Part part, |
| 1759 State state, |
| 1760 const ExtraParams& extra) { |
| 1761 switch (part) { |
| 1762 case kCheckbox: |
| 1763 switch (state) { |
| 1764 case kDisabled: |
| 1765 return CBS_UNCHECKEDDISABLED; |
| 1766 case kHovered: |
| 1767 return CBS_UNCHECKEDHOT; |
| 1768 case kNormal: |
| 1769 return CBS_UNCHECKEDNORMAL; |
| 1770 case kPressed: |
| 1771 return CBS_UNCHECKEDPRESSED; |
| 1772 case kNumStates: |
| 1773 NOTREACHED(); |
| 1774 return 0; |
| 1775 } |
| 1776 case kMenuCheck: |
| 1777 switch (state) { |
| 1778 case kDisabled: |
| 1779 return extra.menu_check.is_radio ? |
| 1780 MC_BULLETDISABLED : MC_CHECKMARKDISABLED; |
| 1781 case kHovered: |
| 1782 case kNormal: |
| 1783 case kPressed: |
| 1784 return extra.menu_check.is_radio ? |
| 1785 MC_BULLETNORMAL : MC_CHECKMARKNORMAL; |
| 1786 case kNumStates: |
| 1787 NOTREACHED(); |
| 1788 return 0; |
| 1789 } |
| 1790 case kMenuPopupArrow: |
| 1791 case kMenuPopupGutter: |
| 1792 case kMenuPopupSeparator: |
| 1793 switch (state) { |
| 1794 case kDisabled: |
| 1795 return MBI_DISABLED; |
| 1796 case kHovered: |
| 1797 return MBI_HOT; |
| 1798 case kNormal: |
| 1799 return MBI_NORMAL; |
| 1800 case kPressed: |
| 1801 return MBI_PUSHED; |
| 1802 case kNumStates: |
| 1803 NOTREACHED(); |
| 1804 return 0; |
| 1805 } |
| 1806 case kPushButton: |
| 1807 switch (state) { |
| 1808 case kDisabled: |
| 1809 return PBS_DISABLED; |
| 1810 case kHovered: |
| 1811 return PBS_HOT; |
| 1812 case kNormal: |
| 1813 return PBS_NORMAL; |
| 1814 case kPressed: |
| 1815 return PBS_PRESSED; |
| 1816 case kNumStates: |
| 1817 NOTREACHED(); |
| 1818 return 0; |
| 1819 } |
| 1820 case kRadio: |
| 1821 switch (state) { |
| 1822 case kDisabled: |
| 1823 return RBS_UNCHECKEDDISABLED; |
| 1824 case kHovered: |
| 1825 return RBS_UNCHECKEDHOT; |
| 1826 case kNormal: |
| 1827 return RBS_UNCHECKEDNORMAL; |
| 1828 case kPressed: |
| 1829 return RBS_UNCHECKEDPRESSED; |
| 1830 case kNumStates: |
| 1831 NOTREACHED(); |
| 1832 return 0; |
| 1833 } |
| 1834 case kScrollbarDownArrow: |
| 1835 switch (state) { |
| 1836 case kDisabled: |
| 1837 return ABS_DOWNDISABLED; |
| 1838 case kHovered: |
| 1839 // Mimic ScrollbarThemeChromiumWin.cpp in WebKit. |
| 1840 return base::win::GetVersion() < base::win::VERSION_VISTA ? |
| 1841 ABS_DOWNHOT : ABS_DOWNHOVER; |
| 1842 case kNormal: |
| 1843 return ABS_DOWNNORMAL; |
| 1844 case kPressed: |
| 1845 return ABS_DOWNPRESSED; |
| 1846 case kNumStates: |
| 1847 NOTREACHED(); |
| 1848 return 0; |
| 1849 } |
| 1850 case kScrollbarLeftArrow: |
| 1851 switch (state) { |
| 1852 case kDisabled: |
| 1853 return ABS_LEFTDISABLED; |
| 1854 case kHovered: |
| 1855 // Mimic ScrollbarThemeChromiumWin.cpp in WebKit. |
| 1856 return base::win::GetVersion() < base::win::VERSION_VISTA ? |
| 1857 ABS_LEFTHOT : ABS_LEFTHOVER; |
| 1858 case kNormal: |
| 1859 return ABS_LEFTNORMAL; |
| 1860 case kPressed: |
| 1861 return ABS_LEFTPRESSED; |
| 1862 case kNumStates: |
| 1863 NOTREACHED(); |
| 1864 return 0; |
| 1865 } |
| 1866 case kScrollbarRightArrow: |
| 1867 switch (state) { |
| 1868 case kDisabled: |
| 1869 return ABS_RIGHTDISABLED; |
| 1870 case kHovered: |
| 1871 // Mimic ScrollbarThemeChromiumWin.cpp in WebKit. |
| 1872 return base::win::GetVersion() < base::win::VERSION_VISTA ? |
| 1873 ABS_RIGHTHOT : ABS_RIGHTHOVER; |
| 1874 case kNormal: |
| 1875 return ABS_RIGHTNORMAL; |
| 1876 case kPressed: |
| 1877 return ABS_RIGHTPRESSED; |
| 1878 case kNumStates: |
| 1879 NOTREACHED(); |
| 1880 return 0; |
| 1881 } |
| 1882 break; |
| 1883 case kScrollbarUpArrow: |
| 1884 switch (state) { |
| 1885 case kDisabled: |
| 1886 return ABS_UPDISABLED; |
| 1887 case kHovered: |
| 1888 // Mimic ScrollbarThemeChromiumWin.cpp in WebKit. |
| 1889 return base::win::GetVersion() < base::win::VERSION_VISTA ? |
| 1890 ABS_UPHOT : ABS_UPHOVER; |
| 1891 case kNormal: |
| 1892 return ABS_UPNORMAL; |
| 1893 case kPressed: |
| 1894 return ABS_UPPRESSED; |
| 1895 case kNumStates: |
| 1896 NOTREACHED(); |
| 1897 return 0; |
| 1898 } |
| 1899 break; |
| 1900 case kScrollbarHorizontalThumb: |
| 1901 case kScrollbarVerticalThumb: |
| 1902 switch (state) { |
| 1903 case kDisabled: |
| 1904 return SCRBS_DISABLED; |
| 1905 case kHovered: |
| 1906 // Mimic WebKit's behaviour in ScrollbarThemeChromiumWin.cpp. |
| 1907 return base::win::GetVersion() < base::win::VERSION_VISTA ? |
| 1908 SCRBS_HOT : SCRBS_HOVER; |
| 1909 case kNormal: |
| 1910 return SCRBS_NORMAL; |
| 1911 case kPressed: |
| 1912 return SCRBS_PRESSED; |
| 1913 case kNumStates: |
| 1914 NOTREACHED(); |
| 1915 return 0; |
| 1916 } |
| 1917 case kWindowResizeGripper: |
| 1918 switch (state) { |
| 1919 case kDisabled: |
| 1920 case kHovered: |
| 1921 case kNormal: |
| 1922 case kPressed: |
| 1923 return 1; // gripper has no windows state |
| 1924 case kNumStates: |
| 1925 NOTREACHED(); |
| 1926 return 0; |
| 1927 } |
| 1928 case kComboboxArrow: |
| 1929 case kInnerSpinButton: |
| 1930 case kMenuList: |
| 1931 case kMenuCheckBackground: |
| 1932 case kMenuPopupBackground: |
| 1933 case kMenuItemBackground: |
| 1934 case kProgressBar: |
| 1935 case kScrollbarHorizontalTrack: |
| 1936 case kScrollbarVerticalTrack: |
| 1937 case kScrollbarHorizontalGripper: |
| 1938 case kScrollbarVerticalGripper: |
| 1939 case kScrollbarCorner: |
| 1940 case kSliderTrack: |
| 1941 case kSliderThumb: |
| 1942 case kTabPanelBackground: |
| 1943 case kTextField: |
| 1944 case kTrackbarThumb: |
| 1945 case kTrackbarTrack: |
| 1946 case kMaxPart: |
| 1947 NOTREACHED(); |
| 1948 } |
| 1949 return 0; |
| 1950 } |
| 1951 |
| 1952 HRESULT NativeThemeWin::GetThemeInt(ThemeName theme, |
| 1953 int part_id, |
| 1954 int state_id, |
| 1955 int prop_id, |
| 1956 int *value) const { |
| 1957 HANDLE handle = GetThemeHandle(theme); |
| 1958 return (handle && get_theme_int_) ? |
| 1959 get_theme_int_(handle, part_id, state_id, prop_id, value) : E_NOTIMPL; |
| 1960 } |
| 1961 |
| 1962 HRESULT NativeThemeWin::PaintFrameControl(HDC hdc, |
| 1963 const gfx::Rect& rect, |
| 1964 UINT type, |
| 1965 UINT state, |
| 1966 bool is_selected, |
| 1967 State control_state) const { |
| 1968 const int width = rect.width(); |
| 1969 const int height = rect.height(); |
| 1970 |
| 1971 // DrawFrameControl for menu arrow/check wants a monochrome bitmap. |
| 1972 base::win::ScopedBitmap mask_bitmap(CreateBitmap(width, height, 1, 1, NULL)); |
| 1973 |
| 1974 if (mask_bitmap == NULL) |
| 1975 return E_OUTOFMEMORY; |
| 1976 |
| 1977 base::win::ScopedCreateDC bitmap_dc(CreateCompatibleDC(NULL)); |
| 1978 base::win::ScopedSelectObject select_bitmap(bitmap_dc.Get(), mask_bitmap); |
| 1979 RECT local_rect = { 0, 0, width, height }; |
| 1980 DrawFrameControl(bitmap_dc.Get(), &local_rect, type, state); |
| 1981 |
| 1982 // We're going to use BitBlt with a b&w mask. This results in using the dest |
| 1983 // dc's text color for the black bits in the mask, and the dest dc's |
| 1984 // background color for the white bits in the mask. DrawFrameControl draws the |
| 1985 // check in black, and the background in white. |
| 1986 int bg_color_key = COLOR_MENU; |
| 1987 int text_color_key = COLOR_MENUTEXT; |
| 1988 switch (control_state) { |
| 1989 case kDisabled: |
| 1990 bg_color_key = is_selected ? COLOR_HIGHLIGHT : COLOR_MENU; |
| 1991 text_color_key = COLOR_GRAYTEXT; |
| 1992 break; |
| 1993 case kHovered: |
| 1994 bg_color_key = COLOR_HIGHLIGHT; |
| 1995 text_color_key = COLOR_HIGHLIGHTTEXT; |
| 1996 break; |
| 1997 case kNormal: |
| 1998 break; |
| 1999 case kPressed: |
| 2000 case kNumStates: |
| 2001 NOTREACHED(); |
| 2002 break; |
| 2003 } |
| 2004 COLORREF old_bg_color = SetBkColor(hdc, GetSysColor(bg_color_key)); |
| 2005 COLORREF old_text_color = SetTextColor(hdc, GetSysColor(text_color_key)); |
| 2006 BitBlt(hdc, rect.x(), rect.y(), width, height, bitmap_dc.Get(), 0, 0, |
| 2007 SRCCOPY); |
| 2008 SetBkColor(hdc, old_bg_color); |
| 2009 SetTextColor(hdc, old_text_color); |
| 2010 |
| 2011 return S_OK; |
| 2012 } |
| 2013 |
| 2014 HANDLE NativeThemeWin::GetThemeHandle(ThemeName theme_name) const { |
| 2015 if (!open_theme_ || theme_name < 0 || theme_name >= LAST) |
| 2016 return 0; |
| 2017 |
| 2018 if (theme_handles_[theme_name]) |
| 2019 return theme_handles_[theme_name]; |
| 2020 |
| 2021 // Not found, try to load it. |
| 2022 HANDLE handle = 0; |
| 2023 switch (theme_name) { |
| 2024 case BUTTON: |
| 2025 handle = open_theme_(NULL, L"Button"); |
| 2026 break; |
| 2027 case LIST: |
| 2028 handle = open_theme_(NULL, L"Listview"); |
| 2029 break; |
| 2030 case MENU: |
| 2031 handle = open_theme_(NULL, L"Menu"); |
| 2032 break; |
| 2033 case MENULIST: |
| 2034 handle = open_theme_(NULL, L"Combobox"); |
| 2035 break; |
| 2036 case SCROLLBAR: |
| 2037 handle = open_theme_(NULL, L"Scrollbar"); |
| 2038 break; |
| 2039 case STATUS: |
| 2040 handle = open_theme_(NULL, L"Status"); |
| 2041 break; |
| 2042 case TAB: |
| 2043 handle = open_theme_(NULL, L"Tab"); |
| 2044 break; |
| 2045 case TEXTFIELD: |
| 2046 handle = open_theme_(NULL, L"Edit"); |
| 2047 break; |
| 2048 case TRACKBAR: |
| 2049 handle = open_theme_(NULL, L"Trackbar"); |
| 2050 break; |
| 2051 case WINDOW: |
| 2052 handle = open_theme_(NULL, L"Window"); |
| 2053 break; |
| 2054 case PROGRESS: |
| 2055 handle = open_theme_(NULL, L"Progress"); |
| 2056 break; |
| 2057 case SPIN: |
| 2058 handle = open_theme_(NULL, L"Spin"); |
| 2059 break; |
| 2060 case LAST: |
| 2061 NOTREACHED(); |
| 2062 break; |
| 2063 } |
| 2064 theme_handles_[theme_name] = handle; |
| 2065 return handle; |
| 2066 } |
| 2067 |
| 2068 } // namespace ui |
OLD | NEW |