diff options
author | benrg@chromium.org <benrg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-28 19:59:52 +0000 |
---|---|---|
committer | benrg@chromium.org <benrg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-28 19:59:52 +0000 |
commit | 63500306b4fd634b340d227964449ec4fd13bda7 (patch) | |
tree | 6a07f715302e9eb54dd4d742c5a7158fd3219bc2 /ui/gfx | |
parent | b8777b72fece4ad14347a57696c0a635e77baa2e (diff) | |
download | chromium_src-63500306b4fd634b340d227964449ec4fd13bda7.zip chromium_src-63500306b4fd634b340d227964449ec4fd13bda7.tar.gz chromium_src-63500306b4fd634b340d227964449ec4fd13bda7.tar.bz2 |
Reorder methods in native_theme_{base,chromeos,win}.cc to match .h order.
Also moved some static constants and functions into the anonymous namespaces, and marked a couple of static locals as const (because they are, and non-const static locals make me nervous).
NativeThemeWin is kind of a mess. I kept the public overload of PaintTextField next to the private overload because I think it probably should be private. The file length decreased by one line because I removed a blank line.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/8679010
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@111754 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/gfx')
-rw-r--r-- | ui/gfx/native_theme_base.cc | 302 | ||||
-rw-r--r-- | ui/gfx/native_theme_chromeos.cc | 40 | ||||
-rw-r--r-- | ui/gfx/native_theme_win.cc | 1279 |
3 files changed, 810 insertions, 811 deletions
diff --git a/ui/gfx/native_theme_base.cc b/ui/gfx/native_theme_base.cc index 04e2b844..2c344b0 100644 --- a/ui/gfx/native_theme_base.cc +++ b/ui/gfx/native_theme_base.cc @@ -20,30 +20,23 @@ namespace { const SkColor kDefaultDialogBackgroundColor = SkColorSetRGB(200, 200, 200); const SkColor kInvalidColorIdColor = SkColorSetRGB(255, 0, 128); -} // namespace - -namespace gfx { - -unsigned int NativeThemeBase::button_length_ = 14; -unsigned int NativeThemeBase::scrollbar_width_ = 15; - // These are the default dimensions of radio buttons and checkboxes. -static const int kCheckboxAndRadioWidth = 13; -static const int kCheckboxAndRadioHeight = 13; +const int kCheckboxAndRadioWidth = 13; +const int kCheckboxAndRadioHeight = 13; // These sizes match the sizes in Chromium Win. -static const int kSliderThumbWidth = 11; -static const int kSliderThumbHeight = 21; +const int kSliderThumbWidth = 11; +const int kSliderThumbHeight = 21; -static const SkColor kSliderTrackBackgroundColor = +const SkColor kSliderTrackBackgroundColor = SkColorSetRGB(0xe3, 0xdd, 0xd8); -static const SkColor kSliderThumbLightGrey = SkColorSetRGB(0xf4, 0xf2, 0xef); -static const SkColor kSliderThumbDarkGrey = SkColorSetRGB(0xea, 0xe5, 0xe0); -static const SkColor kSliderThumbBorderDarkGrey = +const SkColor kSliderThumbLightGrey = SkColorSetRGB(0xf4, 0xf2, 0xef); +const SkColor kSliderThumbDarkGrey = SkColorSetRGB(0xea, 0xe5, 0xe0); +const SkColor kSliderThumbBorderDarkGrey = SkColorSetRGB(0x9d, 0x96, 0x8e); // Get lightness adjusted color. -static SkColor BrightenColor(const color_utils::HSL& hsl, SkAlpha alpha, +SkColor BrightenColor(const color_utils::HSL& hsl, SkAlpha alpha, double lightness_amount) { color_utils::HSL adjusted = hsl; adjusted.l += lightness_amount; @@ -55,11 +48,12 @@ static SkColor BrightenColor(const color_utils::HSL& hsl, SkAlpha alpha, return color_utils::HSLToSkColor(adjusted, alpha); } -NativeThemeBase::NativeThemeBase() { -} +} // namespace -NativeThemeBase::~NativeThemeBase() { -} +namespace gfx { + +unsigned int NativeThemeBase::button_length_ = 14; +unsigned int NativeThemeBase::scrollbar_width_ = 15; gfx::Size NativeThemeBase::GetPartSize(Part part, State state, @@ -131,6 +125,106 @@ gfx::Size NativeThemeBase::GetPartSize(Part part, return gfx::Size(); } +void NativeThemeBase::Paint(SkCanvas* canvas, + Part part, + State state, + const gfx::Rect& rect, + const ExtraParams& extra) const { + switch (part) { + // Please keep these in the order of NativeTheme::Part. + case kCheckbox: + PaintCheckbox(canvas, state, rect, extra.button); + break; + case kInnerSpinButton: + PaintInnerSpinButton(canvas, state, rect, extra.inner_spin); + break; + case kMenuList: + PaintMenuList(canvas, state, rect, extra.menu_list); + break; + case kMenuCheck: + case kMenuCheckBackground: + case kMenuPopupArrow: + NOTIMPLEMENTED(); + break; + case kMenuPopupBackground: + PaintMenuPopupBackground(canvas, state, rect, extra.menu_list); + break; + case kMenuPopupGutter: + case kMenuPopupSeparator: + NOTIMPLEMENTED(); + break; + case kMenuItemBackground: + PaintMenuItemBackground(canvas, state, rect, extra.menu_list); + break; + case kProgressBar: + PaintProgressBar(canvas, state, rect, extra.progress_bar); + break; + case kPushButton: + PaintButton(canvas, state, rect, extra.button); + break; + case kRadio: + PaintRadio(canvas, state, rect, extra.button); + break; + case kScrollbarDownArrow: + case kScrollbarUpArrow: + case kScrollbarLeftArrow: + case kScrollbarRightArrow: + PaintArrowButton(canvas, rect, part, state); + break; + case kScrollbarHorizontalThumb: + case kScrollbarVerticalThumb: + PaintScrollbarThumb(canvas, part, state, rect); + break; + case kScrollbarHorizontalTrack: + case kScrollbarVerticalTrack: + PaintScrollbarTrack(canvas, part, state, extra.scrollbar_track, rect); + break; + case kScrollbarHorizontalGripper: + case kScrollbarVerticalGripper: + NOTIMPLEMENTED(); + break; + case kSliderTrack: + PaintSliderTrack(canvas, state, rect, extra.slider); + break; + case kSliderThumb: + PaintSliderThumb(canvas, state, rect, extra.slider); + break; + case kTabPanelBackground: + NOTIMPLEMENTED(); + break; + case kTextField: + PaintTextField(canvas, state, rect, extra.text_field); + break; + case kTrackbarThumb: + case kTrackbarTrack: + case kWindowResizeGripper: + NOTIMPLEMENTED(); + break; + default: + NOTREACHED() << "Unknown theme part: " << part; + break; + } +} + +SkColor NativeThemeBase::GetSystemColor(ColorId color_id) const { + // This implementation returns hardcoded colors. It's used by NativeThemeAura + // and NativeThemeChromeos and overridden by NativeThemeGtk. + switch (color_id) { + case kColorId_DialogBackground: + return kDefaultDialogBackgroundColor; + default: + NOTREACHED() << "Invalid color_id: " << color_id; + break; + } + return kInvalidColorIdColor; +} + +NativeThemeBase::NativeThemeBase() { +} + +NativeThemeBase::~NativeThemeBase() { +} + void NativeThemeBase::PaintArrowButton( SkCanvas* canvas, const gfx::Rect& rect, Part direction, State state) const { @@ -257,100 +351,6 @@ void NativeThemeBase::PaintArrowButton( canvas->drawPath(path, paint); } -void NativeThemeBase::Paint(SkCanvas* canvas, - Part part, - State state, - const gfx::Rect& rect, - const ExtraParams& extra) const { - switch (part) { - // Please keep these in the order of NativeTheme::Part. - case kCheckbox: - PaintCheckbox(canvas, state, rect, extra.button); - break; - case kInnerSpinButton: - PaintInnerSpinButton(canvas, state, rect, extra.inner_spin); - break; - case kMenuList: - PaintMenuList(canvas, state, rect, extra.menu_list); - break; - case kMenuCheck: - case kMenuCheckBackground: - case kMenuPopupArrow: - NOTIMPLEMENTED(); - break; - case kMenuPopupBackground: - PaintMenuPopupBackground(canvas, state, rect, extra.menu_list); - break; - case kMenuPopupGutter: - case kMenuPopupSeparator: - NOTIMPLEMENTED(); - break; - case kMenuItemBackground: - PaintMenuItemBackground(canvas, state, rect, extra.menu_list); - break; - case kProgressBar: - PaintProgressBar(canvas, state, rect, extra.progress_bar); - break; - case kPushButton: - PaintButton(canvas, state, rect, extra.button); - break; - case kRadio: - PaintRadio(canvas, state, rect, extra.button); - break; - case kScrollbarDownArrow: - case kScrollbarUpArrow: - case kScrollbarLeftArrow: - case kScrollbarRightArrow: - PaintArrowButton(canvas, rect, part, state); - break; - case kScrollbarHorizontalThumb: - case kScrollbarVerticalThumb: - PaintScrollbarThumb(canvas, part, state, rect); - break; - case kScrollbarHorizontalTrack: - case kScrollbarVerticalTrack: - PaintScrollbarTrack(canvas, part, state, extra.scrollbar_track, rect); - break; - case kScrollbarHorizontalGripper: - case kScrollbarVerticalGripper: - NOTIMPLEMENTED(); - break; - case kSliderTrack: - PaintSliderTrack(canvas, state, rect, extra.slider); - break; - case kSliderThumb: - PaintSliderThumb(canvas, state, rect, extra.slider); - break; - case kTabPanelBackground: - NOTIMPLEMENTED(); - break; - case kTextField: - PaintTextField(canvas, state, rect, extra.text_field); - break; - case kTrackbarThumb: - case kTrackbarTrack: - case kWindowResizeGripper: - NOTIMPLEMENTED(); - break; - default: - NOTREACHED() << "Unknown theme part: " << part; - break; - } -} - -SkColor NativeThemeBase::GetSystemColor(ColorId color_id) const { - // This implementation returns hardcoded colors. It's used by NativeThemeAura - // and NativeThemeChromeos and overridden by NativeThemeGtk. - switch (color_id) { - case kColorId_DialogBackground: - return kDefaultDialogBackgroundColor; - default: - NOTREACHED() << "Invalid color_id: " << color_id; - break; - } - return kInvalidColorIdColor; -} - void NativeThemeBase::PaintScrollbarTrack(SkCanvas* canvas, Part part, State state, @@ -846,37 +846,6 @@ bool NativeThemeBase::IntersectsClipRectInt( SkIntToScalar(y + h)); } -void NativeThemeBase::DrawVertLine(SkCanvas* canvas, - int x, - int y1, - int y2, - const SkPaint& paint) const { - SkIRect skrect; - skrect.set(x, y1, x + 1, y2 + 1); - canvas->drawIRect(skrect, paint); -} - -void NativeThemeBase::DrawHorizLine(SkCanvas* canvas, - int x1, - int x2, - int y, - const SkPaint& paint) const { - SkIRect skrect; - skrect.set(x1, y, x2 + 1, y + 1); - canvas->drawIRect(skrect, paint); -} - -void NativeThemeBase::DrawBox(SkCanvas* canvas, - const gfx::Rect& rect, - const SkPaint& paint) const { - const int right = rect.x() + rect.width() - 1; - const int bottom = rect.y() + rect.height() - 1; - DrawHorizLine(canvas, rect.x(), right, rect.y(), paint); - DrawVertLine(canvas, right, rect.y(), bottom, paint); - DrawHorizLine(canvas, rect.x(), right, bottom, paint); - DrawVertLine(canvas, rect.x(), rect.y(), bottom, paint); -} - void NativeThemeBase::DrawBitmapInt( SkCanvas* canvas, const SkBitmap& bitmap, int src_x, int src_y, int src_w, int src_h, @@ -955,12 +924,6 @@ void NativeThemeBase::DrawTiledImage(SkCanvas* canvas, canvas->restore(); } -SkScalar NativeThemeBase::Clamp(SkScalar value, - SkScalar min, - SkScalar max) const { - return std::min(std::max(value, min), max); -} - SkColor NativeThemeBase::SaturateAndBrighten(SkScalar* hsv, SkScalar saturate_amount, SkScalar brighten_amount) const { @@ -971,6 +934,43 @@ SkColor NativeThemeBase::SaturateAndBrighten(SkScalar* hsv, return SkHSVToColor(color); } +void NativeThemeBase::DrawVertLine(SkCanvas* canvas, + int x, + int y1, + int y2, + const SkPaint& paint) const { + SkIRect skrect; + skrect.set(x, y1, x + 1, y2 + 1); + canvas->drawIRect(skrect, paint); +} + +void NativeThemeBase::DrawHorizLine(SkCanvas* canvas, + int x1, + int x2, + int y, + const SkPaint& paint) const { + SkIRect skrect; + skrect.set(x1, y, x2 + 1, y + 1); + canvas->drawIRect(skrect, paint); +} + +void NativeThemeBase::DrawBox(SkCanvas* canvas, + const gfx::Rect& rect, + const SkPaint& paint) const { + const int right = rect.x() + rect.width() - 1; + const int bottom = rect.y() + rect.height() - 1; + DrawHorizLine(canvas, rect.x(), right, rect.y(), paint); + DrawVertLine(canvas, right, rect.y(), bottom, paint); + DrawHorizLine(canvas, rect.x(), right, bottom, paint); + DrawVertLine(canvas, rect.x(), rect.y(), bottom, paint); +} + +SkScalar NativeThemeBase::Clamp(SkScalar value, + SkScalar min, + SkScalar max) const { + return std::min(std::max(value, min), max); +} + SkColor NativeThemeBase::OutlineColor(SkScalar* hsv1, SkScalar* hsv2) const { // GTK Theme engines have way too much control over the layout of // the scrollbar. We might be able to more closely approximate its diff --git a/ui/gfx/native_theme_chromeos.cc b/ui/gfx/native_theme_chromeos.cc index 3919d8f..0c08c25 100644 --- a/ui/gfx/native_theme_chromeos.cc +++ b/ui/gfx/native_theme_chromeos.cc @@ -351,6 +351,26 @@ void NativeThemeChromeos::PaintScrollbarTrack( } } +void NativeThemeChromeos::PaintArrowButton(SkCanvas* canvas, + const gfx::Rect& rect, Part part, State state) const { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + int resource_id = + (part == kScrollbarUpArrow || part == kScrollbarLeftArrow) ? + IDR_SCROLL_ARROW_UP : IDR_SCROLL_ARROW_DOWN; + if (state == kHovered) + resource_id++; + else if (state == kPressed) + resource_id += 2; + SkBitmap* bitmap; + if (part == kScrollbarUpArrow || part == kScrollbarDownArrow) + bitmap = rb.GetBitmapNamed(resource_id); + else + bitmap = GetHorizontalBitmapNamed(resource_id); + DrawBitmapInt(canvas, *bitmap, + 0, 0, bitmap->width(), bitmap->height(), + rect.x(), rect.y(), rect.width(), rect.height()); +} + void NativeThemeChromeos::PaintScrollbarThumb(SkCanvas* canvas, Part part, State state, const gfx::Rect& rect) const { ResourceBundle& rb = ResourceBundle::GetSharedInstance(); @@ -396,26 +416,6 @@ void NativeThemeChromeos::PaintScrollbarThumb(SkCanvas* canvas, } } -void NativeThemeChromeos::PaintArrowButton(SkCanvas* canvas, - const gfx::Rect& rect, Part part, State state) const { - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - int resource_id = - (part == kScrollbarUpArrow || part == kScrollbarLeftArrow) ? - IDR_SCROLL_ARROW_UP : IDR_SCROLL_ARROW_DOWN; - if (state == kHovered) - resource_id++; - else if (state == kPressed) - resource_id += 2; - SkBitmap* bitmap; - if (part == kScrollbarUpArrow || part == kScrollbarDownArrow) - bitmap = rb.GetBitmapNamed(resource_id); - else - bitmap = GetHorizontalBitmapNamed(resource_id); - DrawBitmapInt(canvas, *bitmap, - 0, 0, bitmap->width(), bitmap->height(), - rect.x(), rect.y(), rect.width(), rect.height()); -} - void NativeThemeChromeos::PaintCheckbox(SkCanvas* canvas, State state, const gfx::Rect& rect, const ButtonExtraParams& button) const { diff --git a/ui/gfx/native_theme_win.cc b/ui/gfx/native_theme_win.cc index e0c1d6e..b241cee 100644 --- a/ui/gfx/native_theme_win.cc +++ b/ui/gfx/native_theme_win.cc @@ -61,10 +61,106 @@ void SetCheckerboardShader(SkPaint* paint, const RECT& align_rect) { SkSafeUnref(paint->setShader(shader)); } +// <-a-> +// [ ***** ] +// ____ | | +// <-a-> <------b-----> +// a: object_width +// b: frame_width +// *: animating object +// +// - the animation goes from "[" to "]" repeatedly. +// - the animation offset is at first "|" +// +int ComputeAnimationProgress(int frame_width, + int object_width, + int pixels_per_second, + double animated_seconds) { + int animation_width = frame_width + object_width; + double interval = static_cast<double>(animation_width) / pixels_per_second; + double ratio = fmod(animated_seconds, interval) / interval; + return static_cast<int>(animation_width * ratio) - object_width; +} + +RECT InsetRect(const RECT* rect, int size) { + gfx::Rect result(*rect); + result.Inset(size, size); + return result.ToRECT(); +} + } // namespace namespace gfx { +bool NativeThemeWin::IsThemingActive() const { + if (is_theme_active_) + return !!is_theme_active_(); + return false; +} + +HRESULT NativeThemeWin::GetThemeColor(ThemeName theme, + int part_id, + int state_id, + int prop_id, + SkColor* color) const { + HANDLE handle = GetThemeHandle(theme); + if (handle && get_theme_color_) { + COLORREF color_ref; + if (get_theme_color_(handle, part_id, state_id, prop_id, &color_ref) == + S_OK) { + *color = skia::COLORREFToSkColor(color_ref); + return S_OK; + } + } + return E_NOTIMPL; +} + +SkColor NativeThemeWin::GetThemeColorWithDefault(ThemeName theme, + int part_id, + int state_id, + int prop_id, + int default_sys_color) const { + SkColor color; + if (GetThemeColor(theme, part_id, state_id, prop_id, &color) != S_OK) + color = skia::COLORREFToSkColor(GetSysColor(default_sys_color)); + return color; +} + +Size NativeThemeWin::GetThemeBorderSize(ThemeName theme) const { + // For simplicity use the wildcard state==0, part==0, since it works + // for the cases we currently depend on. + int border; + if (GetThemeInt(theme, 0, 0, TMT_BORDERSIZE, &border) == S_OK) + return Size(border, border); + else + return Size(GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE)); +} + +void NativeThemeWin::DisableTheming() const { + if (!set_theme_properties_) + return; + set_theme_properties_(0); +} + +void NativeThemeWin::CloseHandles() const { + if (!close_theme_) + return; + + for (int i = 0; i < LAST; ++i) { + if (theme_handles_[i]) { + close_theme_(theme_handles_[i]); + theme_handles_[i] = NULL; + } + } +} + +bool NativeThemeWin::IsClassicTheme(ThemeName name) const { + if (!theme_dll_) + return true; + + return !GetThemeHandle(name); +} + // static const NativeTheme* NativeTheme::instance() { return NativeThemeWin::instance(); @@ -156,77 +252,6 @@ gfx::Size NativeThemeWin::GetPartSize(Part part, return Size(size.cx, size.cy); } -void NativeThemeWin::PaintToNonPlatformCanvas(SkCanvas* canvas, - Part part, - State state, - const gfx::Rect& rect, - const ExtraParams& extra) const { - // TODO(asvitkine): This path is pretty inefficient - for each paint operation - // it creates a new offscreen bitmap Skia canvas. This can - // be sped up by doing it only once per part/state and - // keeping a cache of the resulting bitmaps. - - // Create an offscreen canvas that is backed by an HDC. - scoped_ptr<SkCanvas> offscreen_canvas( - skia::CreateBitmapCanvas(rect.width(), rect.height(), false)); - DCHECK(offscreen_canvas.get()); - DCHECK(skia::SupportsPlatformPaint(offscreen_canvas.get())); - - // Some of the Windows theme drawing operations do not write correct alpha - // values for fully-opaque pixels; instead the pixels get alpha 0. This is - // especially a problem on Windows XP or when using the Classic theme. - // - // To work-around this, mark all pixels with a placeholder value, to detect - // which pixels get touched by the paint operation. After paint, set any - // pixels that have alpha 0 to opaque and placeholders to fully-transparent. - const SkColor placeholder = SkColorSetARGB(1, 0, 0, 0); - offscreen_canvas->clear(placeholder); - - // Offset destination rects to have origin (0,0). - gfx::Rect adjusted_rect(rect.size()); - ExtraParams adjusted_extra(extra); - switch (part) { - case kProgressBar: - adjusted_extra.progress_bar.value_rect_x = 0; - adjusted_extra.progress_bar.value_rect_y = 0; - break; - case kScrollbarHorizontalTrack: - case kScrollbarVerticalTrack: - adjusted_extra.scrollbar_track.track_x = 0; - adjusted_extra.scrollbar_track.track_y = 0; - break; - default: break; - } - // Draw the theme controls using existing HDC-drawing code. - Paint(offscreen_canvas.get(), part, state, adjusted_rect, adjusted_extra); - - // Copy the pixels to a bitmap that has ref-counted pixel storage, which is - // necessary to have when drawing to a SkPicture. - const SkBitmap& bitmap = offscreen_canvas->getDevice()->accessBitmap(false); - SkBitmap ref_counted; - bitmap.copyTo(&ref_counted, SkBitmap::kARGB_8888_Config); - - // Post-process the pixels to fix up the alpha values (see big comment above). - const SkPMColor placeholder_value = SkPreMultiplyColor(placeholder); - const int pixel_count = rect.width() * rect.height(); - SkPMColor* pixels = bitmap.getAddr32(0, 0); - for (int i = 0; i < pixel_count; i++) { - if (pixels[i] == placeholder_value) { - // Pixel wasn't touched - make it fully transparent. - pixels[i] = SkPackARGB32(0, 0, 0, 0); - } else if (SkGetPackedA32(pixels[i]) == 0) { - // Pixel was touched but has incorrect alpha of 0, make it fully opaque. - pixels[i] = SkPackARGB32(0xFF, - SkGetPackedR32(pixels[i]), - SkGetPackedG32(pixels[i]), - SkGetPackedB32(pixels[i])); - } - } - - // Draw the offscreen bitmap to the destination canvas. - canvas->drawBitmap(ref_counted, rect.x(), rect.y()); -} - void NativeThemeWin::Paint(SkCanvas* canvas, Part part, State state, @@ -334,299 +359,89 @@ SkColor NativeThemeWin::GetSystemColor(ColorId color_id) const { return kInvalidColorIdColor; } -HRESULT NativeThemeWin::PaintScrollbarArrow( - HDC hdc, - Part part, - State state, - const gfx::Rect& rect, - const ScrollbarArrowExtraParams& extra) const { - static int state_id_matrix[4][kMaxState] = { - ABS_DOWNDISABLED, ABS_DOWNHOT, ABS_DOWNNORMAL, ABS_DOWNPRESSED, - ABS_LEFTDISABLED, ABS_LEFTHOT, ABS_LEFTNORMAL, ABS_LEFTPRESSED, - ABS_RIGHTDISABLED, ABS_RIGHTHOT, ABS_RIGHTNORMAL, ABS_RIGHTPRESSED, - ABS_UPDISABLED, ABS_UPHOT, ABS_UPNORMAL, ABS_UPPRESSED - }; - HANDLE handle = GetThemeHandle(SCROLLBAR); - RECT rect_win = rect.ToRECT(); - if (handle && draw_theme_) { - int index = part - kScrollbarDownArrow; - DCHECK(index >=0 && index < 4); - int state_id = state_id_matrix[index][state]; - - // Hovering means that the cursor is over the scroolbar, but not over the - // specific arrow itself. We don't want to show it "hot" mode, but only - // in "hover" mode. - if (state == kHovered && extra.is_hovering) { - switch (part) { - case kScrollbarDownArrow: - state_id = ABS_DOWNHOVER; - break; - case kScrollbarLeftArrow: - state_id = ABS_LEFTHOVER; - break; - case kScrollbarRightArrow: - state_id = ABS_RIGHTHOVER; - break; - case kScrollbarUpArrow: - state_id = ABS_UPHOVER; - break; - default: - NOTREACHED() << "Invalid part: " << part; - break; - } - } - - return draw_theme_(handle, hdc, SBP_ARROWBTN, state_id, &rect_win, NULL); - } - - int classic_state = DFCS_SCROLLDOWN; - switch (part) { - case kScrollbarDownArrow: - classic_state = DFCS_SCROLLDOWN; - break; - case kScrollbarLeftArrow: - classic_state = DFCS_SCROLLLEFT; - break; - case kScrollbarRightArrow: - classic_state = DFCS_SCROLLRIGHT; - break; - case kScrollbarUpArrow: - classic_state = DFCS_SCROLLUP; - break; - default: - NOTREACHED() << "Invalid part: " << part; - break; - } - switch (state) { - case kDisabled: - classic_state |= DFCS_INACTIVE; - break; - case kHovered: - classic_state |= DFCS_HOT; - break; - case kNormal: - break; - case kPressed: - classic_state |= DFCS_PUSHED; - break; - default: - NOTREACHED() << "Invalid state: " << state; - break; - } - DrawFrameControl(hdc, &rect_win, DFC_SCROLL, classic_state); - return S_OK; -} - -HRESULT NativeThemeWin::PaintScrollbarTrack( - SkCanvas* canvas, - HDC hdc, - Part part, - State state, - const gfx::Rect& rect, - const ScrollbarTrackExtraParams& extra) const { - HANDLE handle = GetThemeHandle(SCROLLBAR); - RECT rect_win = rect.ToRECT(); - int part_id; - int state_id; - - switch (part) { - case gfx::NativeTheme::kScrollbarHorizontalTrack: - part_id = extra.is_upper ? SBP_UPPERTRACKHORZ : SBP_LOWERTRACKHORZ; - break; - case gfx::NativeTheme::kScrollbarVerticalTrack: - part_id = extra.is_upper ? SBP_UPPERTRACKVERT : SBP_LOWERTRACKVERT; - break; - default: - NOTREACHED() << "Invalid part: " << part; - break; - } - - switch (state) { - case kDisabled: - state_id = SCRBS_DISABLED; - break; - case kHovered: - state_id = SCRBS_HOVER; - break; - case kNormal: - state_id = SCRBS_NORMAL; - break; - case kPressed: - state_id = SCRBS_PRESSED; - break; - default: - NOTREACHED() << "Invalid state: " << state; - break; - } - - if (handle && draw_theme_) - return draw_theme_(handle, hdc, part_id, state_id, &rect_win, NULL); +void NativeThemeWin::PaintToNonPlatformCanvas(SkCanvas* canvas, + Part part, + State state, + const gfx::Rect& rect, + const ExtraParams& extra) const { + // TODO(asvitkine): This path is pretty inefficient - for each paint operation + // it creates a new offscreen bitmap Skia canvas. This can + // be sped up by doing it only once per part/state and + // keeping a cache of the resulting bitmaps. - // Draw it manually. - const DWORD colorScrollbar = GetSysColor(COLOR_SCROLLBAR); - const DWORD color3DFace = GetSysColor(COLOR_3DFACE); - if ((colorScrollbar != color3DFace) && - (colorScrollbar != GetSysColor(COLOR_WINDOW))) { - FillRect(hdc, &rect_win, reinterpret_cast<HBRUSH>(COLOR_SCROLLBAR + 1)); - } else { - SkPaint paint; - RECT align_rect = gfx::Rect(extra.track_x, extra.track_y, extra.track_width, - extra.track_height).ToRECT(); - SetCheckerboardShader(&paint, align_rect); - canvas->drawIRect(skia::RECTToSkIRect(rect_win), paint); - } - if (extra.classic_state & DFCS_PUSHED) - InvertRect(hdc, &rect_win); - return S_OK; -} + // Create an offscreen canvas that is backed by an HDC. + scoped_ptr<SkCanvas> offscreen_canvas( + skia::CreateBitmapCanvas(rect.width(), rect.height(), false)); + DCHECK(offscreen_canvas.get()); + DCHECK(skia::SupportsPlatformPaint(offscreen_canvas.get())); -HRESULT NativeThemeWin::PaintScrollbarThumb( - HDC hdc, - Part part, - State state, - const gfx::Rect& rect, - const ScrollbarThumbExtraParams& extra) const { - HANDLE handle = GetThemeHandle(SCROLLBAR); - RECT rect_win = rect.ToRECT(); - int part_id; - int state_id; + // Some of the Windows theme drawing operations do not write correct alpha + // values for fully-opaque pixels; instead the pixels get alpha 0. This is + // especially a problem on Windows XP or when using the Classic theme. + // + // To work-around this, mark all pixels with a placeholder value, to detect + // which pixels get touched by the paint operation. After paint, set any + // pixels that have alpha 0 to opaque and placeholders to fully-transparent. + const SkColor placeholder = SkColorSetARGB(1, 0, 0, 0); + offscreen_canvas->clear(placeholder); + // Offset destination rects to have origin (0,0). + gfx::Rect adjusted_rect(rect.size()); + ExtraParams adjusted_extra(extra); switch (part) { - case gfx::NativeTheme::kScrollbarHorizontalThumb: - part_id = SBP_THUMBBTNHORZ; - break; - case gfx::NativeTheme::kScrollbarVerticalThumb: - part_id = SBP_THUMBBTNVERT; - break; - case gfx::NativeTheme::kScrollbarHorizontalGripper: - part_id = SBP_GRIPPERHORZ; - break; - case gfx::NativeTheme::kScrollbarVerticalGripper: - part_id = SBP_GRIPPERVERT; - break; - default: - NOTREACHED() << "Invalid part: " << part; - break; - } - - switch (state) { - case kDisabled: - state_id = SCRBS_DISABLED; - break; - case kHovered: - state_id = extra.is_hovering ? SCRBS_HOVER : SCRBS_HOT; - break; - case kNormal: - state_id = SCRBS_NORMAL; - break; - case kPressed: - state_id = SCRBS_PRESSED; - break; - default: - NOTREACHED() << "Invalid state: " << state; - break; - } - - if (handle && draw_theme_) - return draw_theme_(handle, hdc, part_id, state_id, &rect_win, NULL); - - // Draw it manually. - if ((part_id == SBP_THUMBBTNHORZ) || (part_id == SBP_THUMBBTNVERT)) - DrawEdge(hdc, &rect_win, EDGE_RAISED, BF_RECT | BF_MIDDLE); - // Classic mode doesn't have a gripper. - return S_OK; -} - -HRESULT NativeThemeWin::PaintPushButton(HDC hdc, - Part part, - State state, - const gfx::Rect& rect, - const ButtonExtraParams& extra) const { - int state_id; - switch (state) { - case kDisabled: - state_id = PBS_DISABLED; - break; - case kHovered: - state_id = PBS_HOT; - break; - case kNormal: - state_id = extra.is_default ? PBS_DEFAULTED : PBS_NORMAL; - break; - case kPressed: - state_id = PBS_PRESSED; + case kProgressBar: + adjusted_extra.progress_bar.value_rect_x = 0; + adjusted_extra.progress_bar.value_rect_y = 0; break; - default: - NOTREACHED() << "Invalid state: " << state; + case kScrollbarHorizontalTrack: + case kScrollbarVerticalTrack: + adjusted_extra.scrollbar_track.track_x = 0; + adjusted_extra.scrollbar_track.track_y = 0; break; + default: break; } + // Draw the theme controls using existing HDC-drawing code. + Paint(offscreen_canvas.get(), part, state, adjusted_rect, adjusted_extra); - RECT rect_win = rect.ToRECT(); - return PaintButton(hdc, state, extra, BP_PUSHBUTTON, state_id, &rect_win); -} + // Copy the pixels to a bitmap that has ref-counted pixel storage, which is + // necessary to have when drawing to a SkPicture. + const SkBitmap& bitmap = offscreen_canvas->getDevice()->accessBitmap(false); + SkBitmap ref_counted; + bitmap.copyTo(&ref_counted, SkBitmap::kARGB_8888_Config); -HRESULT NativeThemeWin::PaintRadioButton(HDC hdc, - Part part, - State state, - const gfx::Rect& rect, - const ButtonExtraParams& extra) const { - int state_id; - switch (state) { - case kDisabled: - state_id = extra.checked ? RBS_CHECKEDDISABLED : RBS_UNCHECKEDDISABLED; - break; - case kHovered: - state_id = extra.checked ? RBS_CHECKEDHOT : RBS_UNCHECKEDHOT; - break; - case kNormal: - state_id = extra.checked ? RBS_CHECKEDNORMAL : RBS_UNCHECKEDNORMAL; - break; - case kPressed: - state_id = extra.checked ? RBS_CHECKEDPRESSED : RBS_UNCHECKEDPRESSED; - break; - default: - NOTREACHED() << "Invalid state: " << state; - break; + // Post-process the pixels to fix up the alpha values (see big comment above). + const SkPMColor placeholder_value = SkPreMultiplyColor(placeholder); + const int pixel_count = rect.width() * rect.height(); + SkPMColor* pixels = bitmap.getAddr32(0, 0); + for (int i = 0; i < pixel_count; i++) { + if (pixels[i] == placeholder_value) { + // Pixel wasn't touched - make it fully transparent. + pixels[i] = SkPackARGB32(0, 0, 0, 0); + } else if (SkGetPackedA32(pixels[i]) == 0) { + // Pixel was touched but has incorrect alpha of 0, make it fully opaque. + pixels[i] = SkPackARGB32(0xFF, + SkGetPackedR32(pixels[i]), + SkGetPackedG32(pixels[i]), + SkGetPackedB32(pixels[i])); + } } - RECT rect_win = rect.ToRECT(); - return PaintButton(hdc, state, extra, BP_RADIOBUTTON, state_id, &rect_win); + // Draw the offscreen bitmap to the destination canvas. + canvas->drawBitmap(ref_counted, rect.x(), rect.y()); } -HRESULT NativeThemeWin::PaintCheckbox(HDC hdc, - Part part, - State state, - const gfx::Rect& rect, - const ButtonExtraParams& extra) const { - int state_id; - switch (state) { - case kDisabled: - state_id = extra.checked ? CBS_CHECKEDDISABLED : - extra.indeterminate ? CBS_MIXEDDISABLED : - CBS_UNCHECKEDDISABLED; - break; - case kHovered: - state_id = extra.checked ? CBS_CHECKEDHOT : - extra.indeterminate ? CBS_MIXEDHOT : - CBS_UNCHECKEDHOT; - break; - case kNormal: - state_id = extra.checked ? CBS_CHECKEDNORMAL : - extra.indeterminate ? CBS_MIXEDNORMAL : - CBS_UNCHECKEDNORMAL; - break; - case kPressed: - state_id = extra.checked ? CBS_CHECKEDPRESSED : - extra.indeterminate ? CBS_MIXEDPRESSED : - CBS_UNCHECKEDPRESSED; - break; - default: - NOTREACHED() << "Invalid state: " << state; - break; - } +HRESULT NativeThemeWin::GetThemePartSize(ThemeName theme_name, + HDC hdc, + int part_id, + int state_id, + RECT* rect, + int ts, + SIZE* size) const { + HANDLE handle = GetThemeHandle(theme_name); + if (handle && get_theme_part_size_) + return get_theme_part_size_(handle, hdc, part_id, state_id, rect, ts, size); - RECT rect_win = rect.ToRECT(); - return PaintButton(hdc, state, extra, BP_CHECKBOX, state_id, &rect_win); + return E_NOTIMPL; } HRESULT NativeThemeWin::PaintButton(HDC hdc, @@ -706,6 +521,37 @@ HRESULT NativeThemeWin::PaintButton(HDC hdc, return S_OK; } +HRESULT NativeThemeWin::PaintMenuSeparator( + HDC hdc, + const gfx::Rect& rect, + const MenuSeparatorExtraParams& extra) const { + RECT rect_win = rect.ToRECT(); + if (!extra.has_gutter) + rect_win.top = rect.y() + rect.height() / 3 + 1; + + HANDLE handle = GetThemeHandle(MENU); + if (handle && draw_theme_) { + // Delta is needed for non-classic to move separator up slightly. + --rect_win.top; + --rect_win.bottom; + return draw_theme_(handle, hdc, MENU_POPUPSEPARATOR, MPI_NORMAL, &rect_win, + NULL); + } + + DrawEdge(hdc, &rect_win, EDGE_ETCHED, BF_TOP); + return S_OK; +} + +HRESULT NativeThemeWin::PaintMenuGutter(HDC hdc, + const gfx::Rect& rect) const { + RECT rect_win = rect.ToRECT(); + HANDLE handle = GetThemeHandle(MENU); + if (handle && draw_theme_) + return draw_theme_(handle, hdc, MENU_POPUPGUTTER, MPI_NORMAL, &rect_win, + NULL); + return E_NOTIMPL; +} + HRESULT NativeThemeWin::PaintMenuArrow(HDC hdc, State state, const gfx::Rect& rect, @@ -774,19 +620,6 @@ HRESULT NativeThemeWin::PaintMenuBackground(HDC hdc, return S_OK; } -HRESULT NativeThemeWin::PaintMenuCheckBackground(HDC hdc, - State state, - const gfx::Rect& rect) const { - HANDLE handle = GetThemeHandle(MENU); - int state_id = state == kDisabled ? MCB_DISABLED : MCB_NORMAL; - RECT rect_win = rect.ToRECT(); - if (handle && draw_theme_) - return draw_theme_(handle, hdc, MENU_POPUPCHECKBACKGROUND, state_id, - &rect_win, NULL); - // Nothing to do for background. - return S_OK; -} - HRESULT NativeThemeWin::PaintMenuCheck( HDC hdc, State state, @@ -809,14 +642,17 @@ HRESULT NativeThemeWin::PaintMenuCheck( extra.is_selected, state); } -HRESULT NativeThemeWin::PaintMenuGutter(HDC hdc, - const gfx::Rect& rect) const { - RECT rect_win = rect.ToRECT(); +HRESULT NativeThemeWin::PaintMenuCheckBackground(HDC hdc, + State state, + const gfx::Rect& rect) const { HANDLE handle = GetThemeHandle(MENU); + int state_id = state == kDisabled ? MCB_DISABLED : MCB_NORMAL; + RECT rect_win = rect.ToRECT(); if (handle && draw_theme_) - return draw_theme_(handle, hdc, MENU_POPUPGUTTER, MPI_NORMAL, &rect_win, - NULL); - return E_NOTIMPL; + return draw_theme_(handle, hdc, MENU_POPUPCHECKBACKGROUND, state_id, + &rect_win, NULL); + // Nothing to do for background. + return S_OK; } HRESULT NativeThemeWin::PaintMenuItemBackground( @@ -850,6 +686,98 @@ HRESULT NativeThemeWin::PaintMenuItemBackground( return S_OK; } +HRESULT NativeThemeWin::PaintPushButton(HDC hdc, + Part part, + State state, + const gfx::Rect& rect, + const ButtonExtraParams& extra) const { + int state_id; + switch (state) { + case kDisabled: + state_id = PBS_DISABLED; + break; + case kHovered: + state_id = PBS_HOT; + break; + case kNormal: + state_id = extra.is_default ? PBS_DEFAULTED : PBS_NORMAL; + break; + case kPressed: + state_id = PBS_PRESSED; + break; + default: + NOTREACHED() << "Invalid state: " << state; + break; + } + + RECT rect_win = rect.ToRECT(); + return PaintButton(hdc, state, extra, BP_PUSHBUTTON, state_id, &rect_win); +} + +HRESULT NativeThemeWin::PaintRadioButton(HDC hdc, + Part part, + State state, + const gfx::Rect& rect, + const ButtonExtraParams& extra) const { + int state_id; + switch (state) { + case kDisabled: + state_id = extra.checked ? RBS_CHECKEDDISABLED : RBS_UNCHECKEDDISABLED; + break; + case kHovered: + state_id = extra.checked ? RBS_CHECKEDHOT : RBS_UNCHECKEDHOT; + break; + case kNormal: + state_id = extra.checked ? RBS_CHECKEDNORMAL : RBS_UNCHECKEDNORMAL; + break; + case kPressed: + state_id = extra.checked ? RBS_CHECKEDPRESSED : RBS_UNCHECKEDPRESSED; + break; + default: + NOTREACHED() << "Invalid state: " << state; + break; + } + + RECT rect_win = rect.ToRECT(); + return PaintButton(hdc, state, extra, BP_RADIOBUTTON, state_id, &rect_win); +} + +HRESULT NativeThemeWin::PaintCheckbox(HDC hdc, + Part part, + State state, + const gfx::Rect& rect, + const ButtonExtraParams& extra) const { + int state_id; + switch (state) { + case kDisabled: + state_id = extra.checked ? CBS_CHECKEDDISABLED : + extra.indeterminate ? CBS_MIXEDDISABLED : + CBS_UNCHECKEDDISABLED; + break; + case kHovered: + state_id = extra.checked ? CBS_CHECKEDHOT : + extra.indeterminate ? CBS_MIXEDHOT : + CBS_UNCHECKEDHOT; + break; + case kNormal: + state_id = extra.checked ? CBS_CHECKEDNORMAL : + extra.indeterminate ? CBS_MIXEDNORMAL : + CBS_UNCHECKEDNORMAL; + break; + case kPressed: + state_id = extra.checked ? CBS_CHECKEDPRESSED : + extra.indeterminate ? CBS_MIXEDPRESSED : + CBS_UNCHECKEDPRESSED; + break; + default: + NOTREACHED() << "Invalid state: " << state; + break; + } + + RECT rect_win = rect.ToRECT(); + return PaintButton(hdc, state, extra, BP_CHECKBOX, state_id, &rect_win); +} + HRESULT NativeThemeWin::PaintMenuList(HDC hdc, State state, const gfx::Rect& rect, @@ -885,87 +813,240 @@ HRESULT NativeThemeWin::PaintMenuList(HDC hdc, return S_OK; } -HRESULT NativeThemeWin::PaintMenuSeparator( +HRESULT NativeThemeWin::PaintScrollbarArrow( HDC hdc, + Part part, + State state, const gfx::Rect& rect, - const MenuSeparatorExtraParams& extra) const { + const ScrollbarArrowExtraParams& extra) const { + static const int state_id_matrix[4][kMaxState] = { + ABS_DOWNDISABLED, ABS_DOWNHOT, ABS_DOWNNORMAL, ABS_DOWNPRESSED, + ABS_LEFTDISABLED, ABS_LEFTHOT, ABS_LEFTNORMAL, ABS_LEFTPRESSED, + ABS_RIGHTDISABLED, ABS_RIGHTHOT, ABS_RIGHTNORMAL, ABS_RIGHTPRESSED, + ABS_UPDISABLED, ABS_UPHOT, ABS_UPNORMAL, ABS_UPPRESSED + }; + HANDLE handle = GetThemeHandle(SCROLLBAR); RECT rect_win = rect.ToRECT(); - if (!extra.has_gutter) - rect_win.top = rect.y() + rect.height() / 3 + 1; - - HANDLE handle = GetThemeHandle(MENU); if (handle && draw_theme_) { - // Delta is needed for non-classic to move separator up slightly. - --rect_win.top; - --rect_win.bottom; - return draw_theme_(handle, hdc, MENU_POPUPSEPARATOR, MPI_NORMAL, &rect_win, - NULL); + int index = part - kScrollbarDownArrow; + DCHECK(index >=0 && index < 4); + int state_id = state_id_matrix[index][state]; + + // Hovering means that the cursor is over the scroolbar, but not over the + // specific arrow itself. We don't want to show it "hot" mode, but only + // in "hover" mode. + if (state == kHovered && extra.is_hovering) { + switch (part) { + case kScrollbarDownArrow: + state_id = ABS_DOWNHOVER; + break; + case kScrollbarLeftArrow: + state_id = ABS_LEFTHOVER; + break; + case kScrollbarRightArrow: + state_id = ABS_RIGHTHOVER; + break; + case kScrollbarUpArrow: + state_id = ABS_UPHOVER; + break; + default: + NOTREACHED() << "Invalid part: " << part; + break; + } + } + + return draw_theme_(handle, hdc, SBP_ARROWBTN, state_id, &rect_win, NULL); } - DrawEdge(hdc, &rect_win, EDGE_ETCHED, BF_TOP); + int classic_state = DFCS_SCROLLDOWN; + switch (part) { + case kScrollbarDownArrow: + classic_state = DFCS_SCROLLDOWN; + break; + case kScrollbarLeftArrow: + classic_state = DFCS_SCROLLLEFT; + break; + case kScrollbarRightArrow: + classic_state = DFCS_SCROLLRIGHT; + break; + case kScrollbarUpArrow: + classic_state = DFCS_SCROLLUP; + break; + default: + NOTREACHED() << "Invalid part: " << part; + break; + } + switch (state) { + case kDisabled: + classic_state |= DFCS_INACTIVE; + break; + case kHovered: + classic_state |= DFCS_HOT; + break; + case kNormal: + break; + case kPressed: + classic_state |= DFCS_PUSHED; + break; + default: + NOTREACHED() << "Invalid state: " << state; + break; + } + DrawFrameControl(hdc, &rect_win, DFC_SCROLL, classic_state); return S_OK; } -HRESULT NativeThemeWin::PaintSpinButton( +HRESULT NativeThemeWin::PaintScrollbarThumb( HDC hdc, Part part, State state, const gfx::Rect& rect, - const InnerSpinButtonExtraParams& extra) const { - HANDLE handle = GetThemeHandle(SPIN); + const ScrollbarThumbExtraParams& extra) const { + HANDLE handle = GetThemeHandle(SCROLLBAR); RECT rect_win = rect.ToRECT(); - int part_id = extra.spin_up ? SPNP_UP : SPNP_DOWN; + int part_id; int state_id; + + switch (part) { + case gfx::NativeTheme::kScrollbarHorizontalThumb: + part_id = SBP_THUMBBTNHORZ; + break; + case gfx::NativeTheme::kScrollbarVerticalThumb: + part_id = SBP_THUMBBTNVERT; + break; + case gfx::NativeTheme::kScrollbarHorizontalGripper: + part_id = SBP_GRIPPERHORZ; + break; + case gfx::NativeTheme::kScrollbarVerticalGripper: + part_id = SBP_GRIPPERVERT; + break; + default: + NOTREACHED() << "Invalid part: " << part; + break; + } + switch (state) { case kDisabled: - state_id = extra.spin_up ? UPS_DISABLED : DNS_DISABLED; + state_id = SCRBS_DISABLED; break; case kHovered: - state_id = extra.spin_up ? UPS_HOT : DNS_HOT; + state_id = extra.is_hovering ? SCRBS_HOVER : SCRBS_HOT; break; case kNormal: - state_id = extra.spin_up ? UPS_NORMAL : DNS_NORMAL; + state_id = SCRBS_NORMAL; break; case kPressed: - state_id = extra.spin_up ? UPS_PRESSED : DNS_PRESSED; + state_id = SCRBS_PRESSED; break; default: - NOTREACHED() << "Invalid state " << state; + NOTREACHED() << "Invalid state: " << state; break; } if (handle && draw_theme_) return draw_theme_(handle, hdc, part_id, state_id, &rect_win, NULL); - DrawFrameControl(hdc, &rect_win, DFC_SCROLL, extra.classic_state); + + // Draw it manually. + if ((part_id == SBP_THUMBBTNHORZ) || (part_id == SBP_THUMBBTNVERT)) + DrawEdge(hdc, &rect_win, EDGE_RAISED, BF_RECT | BF_MIDDLE); + // Classic mode doesn't have a gripper. return S_OK; } -HRESULT NativeThemeWin::PaintWindowResizeGripper(HDC hdc, - const gfx::Rect& rect) const { - HANDLE handle = GetThemeHandle(STATUS); +HRESULT NativeThemeWin::PaintScrollbarTrack( + SkCanvas* canvas, + HDC hdc, + Part part, + State state, + const gfx::Rect& rect, + const ScrollbarTrackExtraParams& extra) const { + HANDLE handle = GetThemeHandle(SCROLLBAR); RECT rect_win = rect.ToRECT(); - if (handle && draw_theme_) { - // Paint the status bar gripper. There doesn't seem to be a - // standard gripper in Windows for the space between - // scrollbars. This is pretty close, but it's supposed to be - // painted over a status bar. - return draw_theme_(handle, hdc, SP_GRIPPER, 0, &rect_win, NULL); + int part_id; + int state_id; + + switch (part) { + case gfx::NativeTheme::kScrollbarHorizontalTrack: + part_id = extra.is_upper ? SBP_UPPERTRACKHORZ : SBP_LOWERTRACKHORZ; + break; + case gfx::NativeTheme::kScrollbarVerticalTrack: + part_id = extra.is_upper ? SBP_UPPERTRACKVERT : SBP_LOWERTRACKVERT; + break; + default: + NOTREACHED() << "Invalid part: " << part; + break; } - // Draw a windows classic scrollbar gripper. - DrawFrameControl(hdc, &rect_win, DFC_SCROLL, DFCS_SCROLLSIZEGRIP); + switch (state) { + case kDisabled: + state_id = SCRBS_DISABLED; + break; + case kHovered: + state_id = SCRBS_HOVER; + break; + case kNormal: + state_id = SCRBS_NORMAL; + break; + case kPressed: + state_id = SCRBS_PRESSED; + break; + default: + NOTREACHED() << "Invalid state: " << state; + break; + } + + if (handle && draw_theme_) + return draw_theme_(handle, hdc, part_id, state_id, &rect_win, NULL); + + // Draw it manually. + const DWORD colorScrollbar = GetSysColor(COLOR_SCROLLBAR); + const DWORD color3DFace = GetSysColor(COLOR_3DFACE); + if ((colorScrollbar != color3DFace) && + (colorScrollbar != GetSysColor(COLOR_WINDOW))) { + FillRect(hdc, &rect_win, reinterpret_cast<HBRUSH>(COLOR_SCROLLBAR + 1)); + } else { + SkPaint paint; + RECT align_rect = gfx::Rect(extra.track_x, extra.track_y, extra.track_width, + extra.track_height).ToRECT(); + SetCheckerboardShader(&paint, align_rect); + canvas->drawIRect(skia::RECTToSkIRect(rect_win), paint); + } + if (extra.classic_state & DFCS_PUSHED) + InvertRect(hdc, &rect_win); return S_OK; } -HRESULT NativeThemeWin::PaintTabPanelBackground(HDC hdc, - const gfx::Rect& rect) const { - HANDLE handle = GetThemeHandle(TAB); +HRESULT NativeThemeWin::PaintSpinButton( + HDC hdc, + Part part, + State state, + const gfx::Rect& rect, + const InnerSpinButtonExtraParams& extra) const { + HANDLE handle = GetThemeHandle(SPIN); RECT rect_win = rect.ToRECT(); - if (handle && draw_theme_) - return draw_theme_(handle, hdc, TABP_BODY, 0, &rect_win, NULL); + int part_id = extra.spin_up ? SPNP_UP : SPNP_DOWN; + int state_id; + switch (state) { + case kDisabled: + state_id = extra.spin_up ? UPS_DISABLED : DNS_DISABLED; + break; + case kHovered: + state_id = extra.spin_up ? UPS_HOT : DNS_HOT; + break; + case kNormal: + state_id = extra.spin_up ? UPS_NORMAL : DNS_NORMAL; + break; + case kPressed: + state_id = extra.spin_up ? UPS_PRESSED : DNS_PRESSED; + break; + default: + NOTREACHED() << "Invalid state " << state; + break; + } - // Classic just renders a flat color background. - FillRect(hdc, &rect_win, reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1)); + if (handle && draw_theme_) + return draw_theme_(handle, hdc, part_id, state_id, &rect_win, NULL); + DrawFrameControl(hdc, &rect_win, DFC_SCROLL, extra.classic_state); return S_OK; } @@ -1076,33 +1157,6 @@ HRESULT NativeThemeWin::PaintTrackbar( return S_OK; } -// <-a-> -// [ ***** ] -// ____ | | -// <-a-> <------b-----> -// a: object_width -// b: frame_width -// *: animating object -// -// - the animation goes from "[" to "]" repeatedly. -// - the animation offset is at first "|" -// -static int ComputeAnimationProgress(int frame_width, - int object_width, - int pixels_per_second, - double animated_seconds) { - int animation_width = frame_width + object_width; - double interval = static_cast<double>(animation_width) / pixels_per_second; - double ratio = fmod(animated_seconds, interval) / interval; - return static_cast<int>(animation_width * ratio) - object_width; -} - -static RECT InsetRect(const RECT* rect, int size) { - gfx::Rect result(*rect); - result.Inset(size, size); - return result.ToRECT(); -} - HRESULT NativeThemeWin::PaintProgressBar( HDC hdc, const gfx::Rect& rect, @@ -1200,6 +1254,35 @@ HRESULT NativeThemeWin::PaintProgressBar( return S_OK; } +HRESULT NativeThemeWin::PaintWindowResizeGripper(HDC hdc, + const gfx::Rect& rect) const { + HANDLE handle = GetThemeHandle(STATUS); + RECT rect_win = rect.ToRECT(); + if (handle && draw_theme_) { + // Paint the status bar gripper. There doesn't seem to be a + // standard gripper in Windows for the space between + // scrollbars. This is pretty close, but it's supposed to be + // painted over a status bar. + return draw_theme_(handle, hdc, SP_GRIPPER, 0, &rect_win, NULL); + } + + // Draw a windows classic scrollbar gripper. + DrawFrameControl(hdc, &rect_win, DFC_SCROLL, DFCS_SCROLLSIZEGRIP); + return S_OK; +} + +HRESULT NativeThemeWin::PaintTabPanelBackground(HDC hdc, + const gfx::Rect& rect) const { + HANDLE handle = GetThemeHandle(TAB); + RECT rect_win = rect.ToRECT(); + if (handle && draw_theme_) + return draw_theme_(handle, hdc, TABP_BODY, 0, &rect_win, NULL); + + // Classic just renders a flat color background. + FillRect(hdc, &rect_win, reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1)); + return S_OK; +} + HRESULT NativeThemeWin::PaintTextField( HDC hdc, Part part, @@ -1260,12 +1343,12 @@ HRESULT NativeThemeWin::PaintTextField(HDC hdc, // draw_theme_ex_ is NULL and draw_theme_ is non-null. if (handle && (draw_theme_ex_ || (draw_theme_ && draw_edges))) { if (draw_theme_ex_) { - static DTBGOPTS omit_border_options = { + static const DTBGOPTS omit_border_options = { sizeof(DTBGOPTS), DTBG_OMITBORDER, { 0, 0, 0, 0 } }; - DTBGOPTS* draw_opts = draw_edges ? NULL : &omit_border_options; + const DTBGOPTS* draw_opts = draw_edges ? NULL : &omit_border_options; hr = draw_theme_ex_(handle, hdc, part_id, state_id, rect, draw_opts); } else { hr = draw_theme_(handle, hdc, part_id, state_id, rect, NULL); @@ -1293,208 +1376,6 @@ HRESULT NativeThemeWin::PaintTextField(HDC hdc, return hr; } -bool NativeThemeWin::IsThemingActive() const { - if (is_theme_active_) - return !!is_theme_active_(); - return false; -} - -HRESULT NativeThemeWin::GetThemePartSize(ThemeName theme_name, - HDC hdc, - int part_id, - int state_id, - RECT* rect, - int ts, - SIZE* size) const { - HANDLE handle = GetThemeHandle(theme_name); - if (handle && get_theme_part_size_) - return get_theme_part_size_(handle, hdc, part_id, state_id, rect, ts, size); - - return E_NOTIMPL; -} - -HRESULT NativeThemeWin::GetThemeColor(ThemeName theme, - int part_id, - int state_id, - int prop_id, - SkColor* color) const { - HANDLE handle = GetThemeHandle(theme); - if (handle && get_theme_color_) { - COLORREF color_ref; - if (get_theme_color_(handle, part_id, state_id, prop_id, &color_ref) == - S_OK) { - *color = skia::COLORREFToSkColor(color_ref); - return S_OK; - } - } - return E_NOTIMPL; -} - -SkColor NativeThemeWin::GetThemeColorWithDefault(ThemeName theme, - int part_id, - int state_id, - int prop_id, - int default_sys_color) const { - SkColor color; - if (GetThemeColor(theme, part_id, state_id, prop_id, &color) != S_OK) - color = skia::COLORREFToSkColor(GetSysColor(default_sys_color)); - return color; -} - -HRESULT NativeThemeWin::GetThemeInt(ThemeName theme, - int part_id, - int state_id, - int prop_id, - int *value) const { - HANDLE handle = GetThemeHandle(theme); - if (handle && get_theme_int_) - return get_theme_int_(handle, part_id, state_id, prop_id, value); - return E_NOTIMPL; -} - -Size NativeThemeWin::GetThemeBorderSize(ThemeName theme) const { - // For simplicity use the wildcard state==0, part==0, since it works - // for the cases we currently depend on. - int border; - if (GetThemeInt(theme, 0, 0, TMT_BORDERSIZE, &border) == S_OK) - return Size(border, border); - else - return Size(GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE)); -} - - -void NativeThemeWin::DisableTheming() const { - if (!set_theme_properties_) - return; - set_theme_properties_(0); -} - -HRESULT NativeThemeWin::PaintFrameControl(HDC hdc, - const gfx::Rect& rect, - UINT type, - UINT state, - bool is_selected, - State control_state) const { - const int width = rect.width(); - const int height = rect.height(); - - // DrawFrameControl for menu arrow/check wants a monochrome bitmap. - base::win::ScopedBitmap mask_bitmap(CreateBitmap(width, height, 1, 1, NULL)); - - if (mask_bitmap == NULL) - return E_OUTOFMEMORY; - - base::win::ScopedCreateDC bitmap_dc(CreateCompatibleDC(NULL)); - base::win::ScopedSelectObject select_bitmap(bitmap_dc, mask_bitmap); - RECT local_rect = { 0, 0, width, height }; - DrawFrameControl(bitmap_dc, &local_rect, type, state); - - // We're going to use BitBlt with a b&w mask. This results in using the dest - // dc's text color for the black bits in the mask, and the dest dc's - // background color for the white bits in the mask. DrawFrameControl draws the - // check in black, and the background in white. - int bg_color_key; - int text_color_key; - switch (control_state) { - case gfx::NativeTheme::kHovered: - bg_color_key = COLOR_HIGHLIGHT; - text_color_key = COLOR_HIGHLIGHTTEXT; - break; - case gfx::NativeTheme::kNormal: - bg_color_key = COLOR_MENU; - text_color_key = COLOR_MENUTEXT; - break; - case gfx::NativeTheme::kDisabled: - bg_color_key = is_selected ? COLOR_HIGHLIGHT : COLOR_MENU; - text_color_key = COLOR_GRAYTEXT; - break; - default: - NOTREACHED(); - bg_color_key = COLOR_MENU; - text_color_key = COLOR_MENUTEXT; - break; - } - COLORREF old_bg_color = SetBkColor(hdc, GetSysColor(bg_color_key)); - COLORREF old_text_color = SetTextColor(hdc, GetSysColor(text_color_key)); - BitBlt(hdc, rect.x(), rect.y(), width, height, bitmap_dc, 0, 0, SRCCOPY); - SetBkColor(hdc, old_bg_color); - SetTextColor(hdc, old_text_color); - - return S_OK; -} - -void NativeThemeWin::CloseHandles() const { - if (!close_theme_) - return; - - for (int i = 0; i < LAST; ++i) { - if (theme_handles_[i]) { - close_theme_(theme_handles_[i]); - theme_handles_[i] = NULL; - } - } -} - -bool NativeThemeWin::IsClassicTheme(ThemeName name) const { - if (!theme_dll_) - return true; - - return !GetThemeHandle(name); -} - -HANDLE NativeThemeWin::GetThemeHandle(ThemeName theme_name) const { - if (!open_theme_ || theme_name < 0 || theme_name >= LAST) - return 0; - - if (theme_handles_[theme_name]) - return theme_handles_[theme_name]; - - // Not found, try to load it. - HANDLE handle = 0; - switch (theme_name) { - case BUTTON: - handle = open_theme_(NULL, L"Button"); - break; - case LIST: - handle = open_theme_(NULL, L"Listview"); - break; - case MENU: - handle = open_theme_(NULL, L"Menu"); - break; - case MENULIST: - handle = open_theme_(NULL, L"Combobox"); - break; - case SCROLLBAR: - handle = open_theme_(NULL, L"Scrollbar"); - break; - case STATUS: - handle = open_theme_(NULL, L"Status"); - break; - case TAB: - handle = open_theme_(NULL, L"Tab"); - break; - case TEXTFIELD: - handle = open_theme_(NULL, L"Edit"); - break; - case TRACKBAR: - handle = open_theme_(NULL, L"Trackbar"); - break; - case WINDOW: - handle = open_theme_(NULL, L"Window"); - break; - case PROGRESS: - handle = open_theme_(NULL, L"Progress"); - break; - case SPIN: - handle = open_theme_(NULL, L"Spin"); - break; - default: - NOTREACHED(); - } - theme_handles_[theme_name] = handle; - return handle; -} - // static NativeThemeWin::ThemeName NativeThemeWin::GetThemeName(Part part) { ThemeName name; @@ -1701,4 +1582,122 @@ int NativeThemeWin::GetWindowsState(Part part, return state_id; } +HRESULT NativeThemeWin::GetThemeInt(ThemeName theme, + int part_id, + int state_id, + int prop_id, + int *value) const { + HANDLE handle = GetThemeHandle(theme); + if (handle && get_theme_int_) + return get_theme_int_(handle, part_id, state_id, prop_id, value); + return E_NOTIMPL; +} + +HRESULT NativeThemeWin::PaintFrameControl(HDC hdc, + const gfx::Rect& rect, + UINT type, + UINT state, + bool is_selected, + State control_state) const { + const int width = rect.width(); + const int height = rect.height(); + + // DrawFrameControl for menu arrow/check wants a monochrome bitmap. + base::win::ScopedBitmap mask_bitmap(CreateBitmap(width, height, 1, 1, NULL)); + + if (mask_bitmap == NULL) + return E_OUTOFMEMORY; + + base::win::ScopedCreateDC bitmap_dc(CreateCompatibleDC(NULL)); + base::win::ScopedSelectObject select_bitmap(bitmap_dc, mask_bitmap); + RECT local_rect = { 0, 0, width, height }; + DrawFrameControl(bitmap_dc, &local_rect, type, state); + + // We're going to use BitBlt with a b&w mask. This results in using the dest + // dc's text color for the black bits in the mask, and the dest dc's + // background color for the white bits in the mask. DrawFrameControl draws the + // check in black, and the background in white. + int bg_color_key; + int text_color_key; + switch (control_state) { + case gfx::NativeTheme::kHovered: + bg_color_key = COLOR_HIGHLIGHT; + text_color_key = COLOR_HIGHLIGHTTEXT; + break; + case gfx::NativeTheme::kNormal: + bg_color_key = COLOR_MENU; + text_color_key = COLOR_MENUTEXT; + break; + case gfx::NativeTheme::kDisabled: + bg_color_key = is_selected ? COLOR_HIGHLIGHT : COLOR_MENU; + text_color_key = COLOR_GRAYTEXT; + break; + default: + NOTREACHED(); + bg_color_key = COLOR_MENU; + text_color_key = COLOR_MENUTEXT; + break; + } + COLORREF old_bg_color = SetBkColor(hdc, GetSysColor(bg_color_key)); + COLORREF old_text_color = SetTextColor(hdc, GetSysColor(text_color_key)); + BitBlt(hdc, rect.x(), rect.y(), width, height, bitmap_dc, 0, 0, SRCCOPY); + SetBkColor(hdc, old_bg_color); + SetTextColor(hdc, old_text_color); + + return S_OK; +} + +HANDLE NativeThemeWin::GetThemeHandle(ThemeName theme_name) const { + if (!open_theme_ || theme_name < 0 || theme_name >= LAST) + return 0; + + if (theme_handles_[theme_name]) + return theme_handles_[theme_name]; + + // Not found, try to load it. + HANDLE handle = 0; + switch (theme_name) { + case BUTTON: + handle = open_theme_(NULL, L"Button"); + break; + case LIST: + handle = open_theme_(NULL, L"Listview"); + break; + case MENU: + handle = open_theme_(NULL, L"Menu"); + break; + case MENULIST: + handle = open_theme_(NULL, L"Combobox"); + break; + case SCROLLBAR: + handle = open_theme_(NULL, L"Scrollbar"); + break; + case STATUS: + handle = open_theme_(NULL, L"Status"); + break; + case TAB: + handle = open_theme_(NULL, L"Tab"); + break; + case TEXTFIELD: + handle = open_theme_(NULL, L"Edit"); + break; + case TRACKBAR: + handle = open_theme_(NULL, L"Trackbar"); + break; + case WINDOW: + handle = open_theme_(NULL, L"Window"); + break; + case PROGRESS: + handle = open_theme_(NULL, L"Progress"); + break; + case SPIN: + handle = open_theme_(NULL, L"Spin"); + break; + default: + NOTREACHED(); + } + theme_handles_[theme_name] = handle; + return handle; +} + } // namespace gfx |