| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/gfx/native_theme.h" | 5 #include "base/gfx/native_theme.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 #include <uxtheme.h> | 8 #include <uxtheme.h> |
| 9 #include <vsstyle.h> | 9 #include <vsstyle.h> |
| 10 #include <vssym32.h> | 10 #include <vssym32.h> |
| 11 | 11 |
| 12 #include "base/gfx/gdi_util.h" | 12 #include "base/gfx/gdi_util.h" |
| 13 #include "base/gfx/rect.h" | 13 #include "base/gfx/rect.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/scoped_handle.h" | 15 #include "base/scoped_handle.h" |
| 16 #include "skia/ext/platform_canvas.h" | 16 #include "skia/ext/platform_canvas.h" |
| 17 #include "skia/ext/skia_utils_win.h" | 17 #include "skia/ext/skia_utils_win.h" |
| 18 #include "skia/include/SkShader.h" | 18 #include "skia/include/SkShader.h" |
| 19 | 19 |
| 20 namespace { |
| 21 |
| 22 void SetCheckerboardShader(SkPaint* paint, const RECT& align_rect) { |
| 23 // Create a 2x2 checkerboard pattern using the 3D face and highlight colors. |
| 24 SkColor face = skia::COLORREFToSkColor(GetSysColor(COLOR_3DFACE)); |
| 25 SkColor highlight = skia::COLORREFToSkColor(GetSysColor(COLOR_3DHILIGHT)); |
| 26 SkColor buffer[] = { face, highlight, highlight, face }; |
| 27 // Confusing bit: we first create a temporary bitmap with our desired pattern, |
| 28 // then copy it to another bitmap. The temporary bitmap doesn't take |
| 29 // ownership of the pixel data, and so will point to garbage when this |
| 30 // function returns. The copy will copy the pixel data into a place owned by |
| 31 // the bitmap, which is in turn owned by the shader, etc., so it will live |
| 32 // until we're done using it. |
| 33 SkBitmap temp_bitmap; |
| 34 temp_bitmap.setConfig(SkBitmap::kARGB_8888_Config, 2, 2); |
| 35 temp_bitmap.setPixels(buffer); |
| 36 SkBitmap bitmap; |
| 37 temp_bitmap.copyTo(&bitmap, temp_bitmap.config()); |
| 38 SkShader* shader = SkShader::CreateBitmapShader(bitmap, |
| 39 SkShader::kRepeat_TileMode, |
| 40 SkShader::kRepeat_TileMode); |
| 41 |
| 42 // Align the pattern with the upper corner of |align_rect|. |
| 43 SkMatrix matrix; |
| 44 matrix.setTranslate(SkIntToScalar(align_rect.left), |
| 45 SkIntToScalar(align_rect.top)); |
| 46 shader->setLocalMatrix(matrix); |
| 47 paint->setShader(shader)->safeUnref(); |
| 48 } |
| 49 |
| 50 } // namespace |
| 51 |
| 20 namespace gfx { | 52 namespace gfx { |
| 21 | 53 |
| 22 /* static */ | 54 /* static */ |
| 23 const NativeTheme* NativeTheme::instance() { | 55 const NativeTheme* NativeTheme::instance() { |
| 24 // The global NativeTheme instance. | 56 // The global NativeTheme instance. |
| 25 static const NativeTheme s_native_theme; | 57 static const NativeTheme s_native_theme; |
| 26 return &s_native_theme; | 58 return &s_native_theme; |
| 27 } | 59 } |
| 28 | 60 |
| 29 NativeTheme::NativeTheme() | 61 NativeTheme::NativeTheme() |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 303 if (handle && draw_theme_) | 335 if (handle && draw_theme_) |
| 304 return draw_theme_(handle, hdc, part_id, state_id, target_rect, NULL); | 336 return draw_theme_(handle, hdc, part_id, state_id, target_rect, NULL); |
| 305 | 337 |
| 306 // Draw it manually. | 338 // Draw it manually. |
| 307 const DWORD colorScrollbar = GetSysColor(COLOR_SCROLLBAR); | 339 const DWORD colorScrollbar = GetSysColor(COLOR_SCROLLBAR); |
| 308 const DWORD color3DFace = GetSysColor(COLOR_3DFACE); | 340 const DWORD color3DFace = GetSysColor(COLOR_3DFACE); |
| 309 if ((colorScrollbar != color3DFace) && | 341 if ((colorScrollbar != color3DFace) && |
| 310 (colorScrollbar != GetSysColor(COLOR_WINDOW))) { | 342 (colorScrollbar != GetSysColor(COLOR_WINDOW))) { |
| 311 FillRect(hdc, target_rect, reinterpret_cast<HBRUSH>(COLOR_SCROLLBAR + 1)); | 343 FillRect(hdc, target_rect, reinterpret_cast<HBRUSH>(COLOR_SCROLLBAR + 1)); |
| 312 } else { | 344 } else { |
| 313 // Create a 2x2 checkerboard pattern using the 3D face and highlight | |
| 314 // colors. | |
| 315 SkColor face = skia::COLORREFToSkColor(color3DFace); | |
| 316 SkColor highlight = skia::COLORREFToSkColor(GetSysColor(COLOR_3DHILIGHT)); | |
| 317 SkColor buffer[] = { face, highlight, highlight, face }; | |
| 318 SkBitmap bitmap; | |
| 319 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 2, 2); | |
| 320 bitmap.setPixels(buffer); | |
| 321 SkShader* shader = SkShader::CreateBitmapShader(bitmap, | |
| 322 SkShader::kRepeat_TileMode, | |
| 323 SkShader::kRepeat_TileMode); | |
| 324 | |
| 325 // Draw that pattern into the target rect, setting the origin to the top | |
| 326 // left corner of the scrollbar track (so the checked rect below the thumb | |
| 327 // aligns properly with the portion above the thumb). | |
| 328 SkMatrix matrix; | |
| 329 matrix.setTranslate(SkIntToScalar(align_rect->left), | |
| 330 SkIntToScalar(align_rect->top)); | |
| 331 shader->setLocalMatrix(matrix); | |
| 332 SkPaint paint; | 345 SkPaint paint; |
| 333 paint.setShader(shader)->unref(); | 346 SetCheckerboardShader(&paint, *align_rect); |
| 334 canvas->drawIRect(skia::RECTToSkIRect(*target_rect), paint); | 347 canvas->drawIRect(skia::RECTToSkIRect(*target_rect), paint); |
| 335 } | 348 } |
| 336 if (classic_state & DFCS_PUSHED) | 349 if (classic_state & DFCS_PUSHED) |
| 337 InvertRect(hdc, target_rect); | 350 InvertRect(hdc, target_rect); |
| 338 return S_OK; | 351 return S_OK; |
| 339 } | 352 } |
| 340 | 353 |
| 341 HRESULT NativeTheme::PaintScrollbarThumb(HDC hdc, | 354 HRESULT NativeTheme::PaintScrollbarThumb(HDC hdc, |
| 342 int part_id, | 355 int part_id, |
| 343 int state_id, | 356 int state_id, |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 376 HRESULT NativeTheme::PaintTabPanelBackground(HDC hdc, RECT* rect) const { | 389 HRESULT NativeTheme::PaintTabPanelBackground(HDC hdc, RECT* rect) const { |
| 377 HANDLE handle = GetThemeHandle(TAB); | 390 HANDLE handle = GetThemeHandle(TAB); |
| 378 if (handle && draw_theme_) | 391 if (handle && draw_theme_) |
| 379 return draw_theme_(handle, hdc, TABP_BODY, 0, rect, NULL); | 392 return draw_theme_(handle, hdc, TABP_BODY, 0, rect, NULL); |
| 380 | 393 |
| 381 // Classic just renders a flat color background. | 394 // Classic just renders a flat color background. |
| 382 FillRect(hdc, rect, reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1)); | 395 FillRect(hdc, rect, reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1)); |
| 383 return S_OK; | 396 return S_OK; |
| 384 } | 397 } |
| 385 | 398 |
| 399 HRESULT NativeTheme::PaintTrackbar(HDC hdc, |
| 400 int part_id, |
| 401 int state_id, |
| 402 int classic_state, |
| 403 RECT* rect, |
| 404 skia::PlatformCanvasWin* canvas) const { |
| 405 // Make the channel be 4 px thick in the center of the supplied rect. (4 px |
| 406 // matches what XP does in various menus; GetThemePartSize() doesn't seem to |
| 407 // return good values here.) |
| 408 RECT channel_rect = *rect; |
| 409 const int channel_thickness = 4; |
| 410 if (part_id == TKP_TRACK) { |
| 411 channel_rect.top += |
| 412 ((channel_rect.bottom - channel_rect.top - channel_thickness) / 2); |
| 413 channel_rect.bottom = channel_rect.top + channel_thickness; |
| 414 } else if (part_id == TKP_TRACKVERT) { |
| 415 channel_rect.left += |
| 416 ((channel_rect.right - channel_rect.left - channel_thickness) / 2); |
| 417 channel_rect.right = channel_rect.left + channel_thickness; |
| 418 } // else this isn't actually a channel, so |channel_rect| == |rect|. |
| 419 |
| 420 HANDLE handle = GetThemeHandle(TRACKBAR); |
| 421 if (handle && draw_theme_) |
| 422 return draw_theme_(handle, hdc, part_id, state_id, &channel_rect, NULL); |
| 423 |
| 424 // Classic mode, draw it manually. |
| 425 if ((part_id == TKP_TRACK) || (part_id == TKP_TRACKVERT)) { |
| 426 DrawEdge(hdc, &channel_rect, EDGE_SUNKEN, BF_RECT); |
| 427 } else if (part_id == TKP_THUMBVERT) { |
| 428 DrawEdge(hdc, rect, EDGE_RAISED, BF_RECT | BF_SOFT | BF_MIDDLE); |
| 429 } else { |
| 430 // Split rect into top and bottom pieces. |
| 431 RECT top_section = *rect; |
| 432 RECT bottom_section = *rect; |
| 433 top_section.bottom -= ((bottom_section.right - bottom_section.left) / 2); |
| 434 bottom_section.top = top_section.bottom; |
| 435 DrawEdge(hdc, &top_section, EDGE_RAISED, |
| 436 BF_LEFT | BF_TOP | BF_RIGHT | BF_SOFT | BF_MIDDLE | BF_ADJUST); |
| 437 |
| 438 // Split triangular piece into two diagonals. |
| 439 RECT& left_half = bottom_section; |
| 440 RECT right_half = bottom_section; |
| 441 right_half.left += ((bottom_section.right - bottom_section.left) / 2); |
| 442 left_half.right = right_half.left; |
| 443 DrawEdge(hdc, &left_half, EDGE_RAISED, |
| 444 BF_DIAGONAL_ENDTOPLEFT | BF_SOFT | BF_MIDDLE | BF_ADJUST); |
| 445 DrawEdge(hdc, &right_half, EDGE_RAISED, |
| 446 BF_DIAGONAL_ENDBOTTOMLEFT | BF_SOFT | BF_MIDDLE | BF_ADJUST); |
| 447 |
| 448 // If the button is pressed, draw hatching. |
| 449 if (classic_state & DFCS_PUSHED) { |
| 450 SkPaint paint; |
| 451 SetCheckerboardShader(&paint, *rect); |
| 452 |
| 453 // Fill all three pieces with the pattern. |
| 454 canvas->drawIRect(skia::RECTToSkIRect(top_section), paint); |
| 455 |
| 456 SkScalar left_triangle_top = SkIntToScalar(left_half.top); |
| 457 SkScalar left_triangle_right = SkIntToScalar(left_half.right); |
| 458 SkPath left_triangle; |
| 459 left_triangle.moveTo(SkIntToScalar(left_half.left), left_triangle_top); |
| 460 left_triangle.lineTo(left_triangle_right, left_triangle_top); |
| 461 left_triangle.lineTo(left_triangle_right, |
| 462 SkIntToScalar(left_half.bottom)); |
| 463 left_triangle.close(); |
| 464 canvas->drawPath(left_triangle, paint); |
| 465 |
| 466 SkScalar right_triangle_left = SkIntToScalar(right_half.left); |
| 467 SkScalar right_triangle_top = SkIntToScalar(right_half.top); |
| 468 SkPath right_triangle; |
| 469 right_triangle.moveTo(right_triangle_left, right_triangle_top); |
| 470 right_triangle.lineTo(SkIntToScalar(right_half.right), |
| 471 right_triangle_top); |
| 472 right_triangle.lineTo(right_triangle_left, |
| 473 SkIntToScalar(right_half.bottom)); |
| 474 right_triangle.close(); |
| 475 canvas->drawPath(right_triangle, paint); |
| 476 } |
| 477 } |
| 478 return S_OK; |
| 479 } |
| 480 |
| 386 HRESULT NativeTheme::PaintTextField(HDC hdc, | 481 HRESULT NativeTheme::PaintTextField(HDC hdc, |
| 387 int part_id, | 482 int part_id, |
| 388 int state_id, | 483 int state_id, |
| 389 int classic_state, | 484 int classic_state, |
| 390 RECT* rect, | 485 RECT* rect, |
| 391 COLORREF color, | 486 COLORREF color, |
| 392 bool fill_content_area, | 487 bool fill_content_area, |
| 393 bool draw_edges) const { | 488 bool draw_edges) const { |
| 394 // TODO(ojan): http://b/1210017 Figure out how to give the ability to | 489 // TODO(ojan): http://b/1210017 Figure out how to give the ability to |
| 395 // exclude individual edges from being drawn. | 490 // exclude individual edges from being drawn. |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 592 break; | 687 break; |
| 593 case STATUS: | 688 case STATUS: |
| 594 handle = open_theme_(NULL, L"Status"); | 689 handle = open_theme_(NULL, L"Status"); |
| 595 break; | 690 break; |
| 596 case TAB: | 691 case TAB: |
| 597 handle = open_theme_(NULL, L"Tab"); | 692 handle = open_theme_(NULL, L"Tab"); |
| 598 break; | 693 break; |
| 599 case TEXTFIELD: | 694 case TEXTFIELD: |
| 600 handle = open_theme_(NULL, L"Edit"); | 695 handle = open_theme_(NULL, L"Edit"); |
| 601 break; | 696 break; |
| 697 case TRACKBAR: |
| 698 handle = open_theme_(NULL, L"Trackbar"); |
| 699 break; |
| 602 case WINDOW: | 700 case WINDOW: |
| 603 handle = open_theme_(NULL, L"Window"); | 701 handle = open_theme_(NULL, L"Window"); |
| 604 break; | 702 break; |
| 605 default: | 703 default: |
| 606 NOTREACHED(); | 704 NOTREACHED(); |
| 607 } | 705 } |
| 608 theme_handles_[theme_name] = handle; | 706 theme_handles_[theme_name] = handle; |
| 609 return handle; | 707 return handle; |
| 610 } | 708 } |
| 611 | 709 |
| 612 } // namespace gfx | 710 } // namespace gfx |
| OLD | NEW |