| // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // This file implements a simple generic version of the WebKitThemeEngine, |
| // Since WebThemeEngine is unfortunately defined in terms of the Windows |
| // Theme parameters and values, we need to translate all the values into |
| // generic equivalents that we can more easily understand. This file does |
| // that translation (acting as a Facade design pattern) and then uses |
| // TestShellWebTheme::Control for the actual rendering of the widgets. |
| // |
| |
| #include "webkit/tools/test_shell/test_shell_webthemeengine.h" |
| |
| // Although all this code is generic, we include these headers |
| // to pull in the Windows #defines for the parts and states of |
| // the controls. |
| #include <vsstyle.h> |
| #include <windows.h> |
| |
| #include "base/logging.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebCanvas.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h" |
| #include "webkit/tools/test_shell/test_shell_webthemecontrol.h" |
| #include "third_party/skia/include/core/SkRect.h" |
| |
| // We define this for clarity, although there really should be a DFCS_NORMAL |
| // in winuser.h. |
| namespace { |
| const int kDFCSNormal = 0x0000; |
| } |
| |
| using WebKit::WebCanvas; |
| using WebKit::WebColor; |
| using WebKit::WebRect; |
| |
| namespace TestShellWebTheme { |
| |
| SkIRect webRectToSkIRect(const WebRect& web_rect) { |
| SkIRect irect; |
| irect.set(web_rect.x, web_rect.y, web_rect.x + web_rect.width, |
| web_rect.y + web_rect.height); |
| return irect; |
| } |
| |
| void drawControl(WebCanvas* canvas, const WebRect& rect, Control::Type ctype, |
| Control::State cstate) { |
| Control control(canvas, webRectToSkIRect(rect), ctype, cstate); |
| control.draw(); |
| } |
| |
| void drawTextField(WebCanvas* canvas, const WebRect& rect, |
| Control::Type ctype, Control::State cstate, |
| bool draw_edges, bool fill_content_area, WebColor color) { |
| Control control(canvas, webRectToSkIRect(rect), ctype, cstate); |
| control.drawTextField(draw_edges, fill_content_area, color); |
| } |
| |
| void drawProgressBar(WebCanvas* canvas, |
| Control::Type ctype, Control::State cstate, |
| const WebRect& bar_rect, const WebRect& fill_rect) { |
| Control control(canvas, webRectToSkIRect(bar_rect), ctype, cstate); |
| control.drawProgressBar(webRectToSkIRect(fill_rect)); |
| } |
| |
| void Engine::paintButton(WebCanvas* canvas, int part, int state, |
| int classic_state, const WebRect& rect) { |
| Control::Type ctype = Control::kUnknown_Type; |
| Control::State cstate = Control::kUnknown_State; |
| |
| if (part == BP_CHECKBOX) { |
| switch (state) { |
| case CBS_UNCHECKEDNORMAL: |
| CHECK_EQ(classic_state, kDFCSNormal); |
| ctype = Control::kUncheckedBox_Type; |
| cstate = Control::kNormal_State; |
| break; |
| case CBS_UNCHECKEDHOT: |
| CHECK_EQ(classic_state, DFCS_BUTTONCHECK | DFCS_HOT); |
| ctype = Control::kUncheckedBox_Type; |
| cstate = Control::kHot_State; |
| break; |
| case CBS_UNCHECKEDPRESSED: |
| CHECK_EQ(classic_state, DFCS_BUTTONCHECK | DFCS_PUSHED); |
| ctype = Control::kUncheckedBox_Type; |
| cstate = Control::kPressed_State; |
| break; |
| case CBS_UNCHECKEDDISABLED: |
| CHECK_EQ(classic_state, DFCS_BUTTONCHECK | DFCS_INACTIVE); |
| ctype = Control::kUncheckedBox_Type; |
| cstate = Control::kDisabled_State; |
| break; |
| case CBS_CHECKEDNORMAL: |
| CHECK_EQ(classic_state, DFCS_BUTTONCHECK | DFCS_CHECKED); |
| ctype = Control::kCheckedBox_Type; |
| cstate = Control::kNormal_State; |
| break; |
| case CBS_CHECKEDHOT: |
| CHECK_EQ(classic_state, DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_HOT); |
| ctype = Control::kCheckedBox_Type; |
| cstate = Control::kHot_State; |
| break; |
| case CBS_CHECKEDPRESSED: |
| CHECK_EQ(classic_state, DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_PUSHED); |
| ctype = Control::kCheckedBox_Type; |
| cstate = Control::kPressed_State; |
| break; |
| case CBS_CHECKEDDISABLED: |
| CHECK_EQ(classic_state, |
| DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_INACTIVE); |
| ctype = Control::kCheckedBox_Type; |
| cstate = Control::kDisabled_State; |
| break; |
| case CBS_MIXEDNORMAL: |
| // Classic theme can't represent mixed state checkbox. We assume |
| // it's equivalent to unchecked. |
| CHECK_EQ(classic_state, DFCS_BUTTONCHECK); |
| ctype = Control::kIndeterminateCheckBox_Type; |
| cstate = Control::kNormal_State; |
| break; |
| case CBS_MIXEDHOT: |
| CHECK_EQ(classic_state, DFCS_BUTTONCHECK | DFCS_HOT); |
| ctype = Control::kIndeterminateCheckBox_Type; |
| cstate = Control::kHot_State; |
| break; |
| case CBS_MIXEDPRESSED: |
| CHECK_EQ(classic_state, DFCS_BUTTONCHECK | DFCS_PUSHED); |
| ctype = Control::kIndeterminateCheckBox_Type; |
| cstate = Control::kPressed_State; |
| break; |
| case CBS_MIXEDDISABLED: |
| CHECK_EQ(classic_state, DFCS_BUTTONCHECK | DFCS_INACTIVE); |
| ctype = Control::kIndeterminateCheckBox_Type; |
| cstate = Control::kDisabled_State; |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| } else if (BP_RADIOBUTTON == part) { |
| switch (state) { |
| case RBS_UNCHECKEDNORMAL: |
| CHECK_EQ(classic_state, DFCS_BUTTONRADIO); |
| ctype = Control::kUncheckedRadio_Type; |
| cstate = Control::kNormal_State; |
| break; |
| case RBS_UNCHECKEDHOT: |
| CHECK_EQ(classic_state, DFCS_BUTTONRADIO | DFCS_HOT); |
| ctype = Control::kUncheckedRadio_Type; |
| cstate = Control::kHot_State; |
| break; |
| case RBS_UNCHECKEDPRESSED: |
| CHECK_EQ(classic_state, DFCS_BUTTONRADIO | DFCS_PUSHED); |
| ctype = Control::kUncheckedRadio_Type; |
| cstate = Control::kPressed_State; |
| break; |
| case RBS_UNCHECKEDDISABLED: |
| CHECK_EQ(classic_state, DFCS_BUTTONRADIO | DFCS_INACTIVE); |
| ctype = Control::kUncheckedRadio_Type; |
| cstate = Control::kDisabled_State; |
| break; |
| case RBS_CHECKEDNORMAL: |
| CHECK_EQ(classic_state, DFCS_BUTTONRADIO | DFCS_CHECKED); |
| ctype = Control::kCheckedRadio_Type; |
| cstate = Control::kNormal_State; |
| break; |
| case RBS_CHECKEDHOT: |
| CHECK_EQ(classic_state, DFCS_BUTTONRADIO | DFCS_CHECKED | DFCS_HOT); |
| ctype = Control::kCheckedRadio_Type; |
| cstate = Control::kHot_State; |
| break; |
| case RBS_CHECKEDPRESSED: |
| CHECK_EQ(classic_state, DFCS_BUTTONRADIO | DFCS_CHECKED | DFCS_PUSHED); |
| ctype = Control::kCheckedRadio_Type; |
| cstate = Control::kPressed_State; |
| break; |
| case RBS_CHECKEDDISABLED: |
| CHECK_EQ(classic_state, |
| DFCS_BUTTONRADIO | DFCS_CHECKED | DFCS_INACTIVE); |
| ctype = Control::kCheckedRadio_Type; |
| cstate = Control::kDisabled_State; |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| } else if (BP_PUSHBUTTON == part) { |
| switch (state) { |
| case PBS_NORMAL: |
| CHECK_EQ(classic_state, DFCS_BUTTONPUSH); |
| ctype = Control::kPushButton_Type; |
| cstate = Control::kNormal_State; |
| break; |
| case PBS_HOT: |
| CHECK_EQ(classic_state, DFCS_BUTTONPUSH | DFCS_HOT); |
| ctype = Control::kPushButton_Type; |
| cstate = Control::kHot_State; |
| break; |
| case PBS_PRESSED: |
| CHECK_EQ(classic_state, DFCS_BUTTONPUSH | DFCS_PUSHED); |
| ctype = Control::kPushButton_Type; |
| cstate = Control::kPressed_State; |
| break; |
| case PBS_DISABLED: |
| CHECK_EQ(classic_state, DFCS_BUTTONPUSH | DFCS_INACTIVE); |
| ctype = Control::kPushButton_Type; |
| cstate = Control::kDisabled_State; |
| break; |
| case PBS_DEFAULTED: |
| CHECK_EQ(classic_state, DFCS_BUTTONPUSH); |
| ctype = Control::kPushButton_Type; |
| cstate = Control::kFocused_State; |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| } else { |
| NOTREACHED(); |
| } |
| |
| drawControl(canvas, rect, ctype, cstate); |
| } |
| |
| |
| void Engine::paintMenuList(WebCanvas* canvas, int part, int state, |
| int classic_state, const WebRect& rect) { |
| Control::Type ctype = Control::kUnknown_Type; |
| Control::State cstate = Control::kUnknown_State; |
| |
| if (CP_DROPDOWNBUTTON == part) { |
| ctype = Control::kDropDownButton_Type; |
| switch (state) { |
| case CBXS_NORMAL: |
| CHECK_EQ(classic_state, DFCS_MENUARROW); |
| cstate = Control::kNormal_State; |
| break; |
| case CBXS_HOT: |
| CHECK_EQ(classic_state, DFCS_MENUARROW | DFCS_HOT); |
| cstate = Control::kHover_State; |
| break; |
| case CBXS_PRESSED: |
| CHECK_EQ(classic_state, DFCS_MENUARROW | DFCS_PUSHED); |
| cstate = Control::kPressed_State; |
| break; |
| case CBXS_DISABLED: |
| CHECK_EQ(classic_state, DFCS_MENUARROW | DFCS_INACTIVE); |
| cstate = Control::kDisabled_State; |
| break; |
| default: |
| CHECK(false); |
| break; |
| } |
| } else { |
| CHECK(false); |
| } |
| |
| drawControl(canvas, rect, ctype, cstate); |
| } |
| |
| void Engine::paintScrollbarArrow(WebCanvas* canvas, int state, |
| int classic_state, const WebRect& rect) { |
| Control::Type ctype = Control::kUnknown_Type; |
| Control::State cstate = Control::kUnknown_State; |
| |
| switch (state) { |
| case ABS_UPNORMAL: |
| CHECK_EQ(classic_state, DFCS_SCROLLUP); |
| ctype = Control::kUpArrow_Type; |
| cstate = Control::kNormal_State; |
| break; |
| case ABS_DOWNNORMAL: |
| CHECK_EQ(classic_state, DFCS_SCROLLDOWN); |
| ctype = Control::kDownArrow_Type; |
| cstate = Control::kNormal_State; |
| break; |
| case ABS_LEFTNORMAL: |
| CHECK_EQ(classic_state, DFCS_SCROLLLEFT); |
| ctype = Control::kLeftArrow_Type; |
| cstate = Control::kNormal_State; |
| break; |
| case ABS_RIGHTNORMAL: |
| CHECK_EQ(classic_state, DFCS_SCROLLRIGHT); |
| ctype = Control::kRightArrow_Type; |
| cstate = Control::kNormal_State; |
| break; |
| case ABS_UPHOT: |
| CHECK_EQ(classic_state, DFCS_SCROLLUP | DFCS_HOT); |
| ctype = Control::kUpArrow_Type; |
| cstate = Control::kHot_State; |
| break; |
| case ABS_DOWNHOT: |
| CHECK_EQ(classic_state, DFCS_SCROLLDOWN | DFCS_HOT); |
| ctype = Control::kDownArrow_Type; |
| cstate = Control::kHot_State; |
| break; |
| case ABS_LEFTHOT: |
| CHECK_EQ(classic_state, DFCS_SCROLLLEFT | DFCS_HOT); |
| ctype = Control::kLeftArrow_Type; |
| cstate = Control::kHot_State; |
| break; |
| case ABS_RIGHTHOT: |
| CHECK_EQ(classic_state, DFCS_SCROLLRIGHT | DFCS_HOT); |
| ctype = Control::kRightArrow_Type; |
| cstate = Control::kHot_State; |
| break; |
| case ABS_UPHOVER: |
| CHECK_EQ(classic_state, DFCS_SCROLLUP); |
| ctype = Control::kUpArrow_Type; |
| cstate = Control::kHover_State; |
| break; |
| case ABS_DOWNHOVER: |
| CHECK_EQ(classic_state, DFCS_SCROLLDOWN); |
| ctype = Control::kDownArrow_Type; |
| cstate = Control::kHover_State; |
| break; |
| case ABS_LEFTHOVER: |
| CHECK_EQ(classic_state, DFCS_SCROLLLEFT); |
| ctype = Control::kLeftArrow_Type; |
| cstate = Control::kHover_State; |
| break; |
| case ABS_RIGHTHOVER: |
| CHECK_EQ(classic_state, DFCS_SCROLLRIGHT); |
| ctype = Control::kRightArrow_Type; |
| cstate = Control::kHover_State; |
| break; |
| case ABS_UPPRESSED: |
| CHECK_EQ(classic_state, DFCS_SCROLLUP | DFCS_PUSHED | DFCS_FLAT); |
| ctype = Control::kUpArrow_Type; |
| cstate = Control::kPressed_State; |
| break; |
| case ABS_DOWNPRESSED: |
| CHECK_EQ(classic_state, DFCS_SCROLLDOWN | DFCS_PUSHED | DFCS_FLAT); |
| ctype = Control::kDownArrow_Type; |
| cstate = Control::kPressed_State; |
| break; |
| case ABS_LEFTPRESSED: |
| CHECK_EQ(classic_state, DFCS_SCROLLLEFT | DFCS_PUSHED | DFCS_FLAT); |
| ctype = Control::kLeftArrow_Type; |
| cstate = Control::kPressed_State; |
| break; |
| case ABS_RIGHTPRESSED: |
| CHECK_EQ(classic_state, DFCS_SCROLLRIGHT | DFCS_PUSHED | DFCS_FLAT); |
| ctype = Control::kRightArrow_Type; |
| cstate = Control::kPressed_State; |
| break; |
| case ABS_UPDISABLED: |
| CHECK_EQ(classic_state, DFCS_SCROLLUP | DFCS_INACTIVE); |
| ctype = Control::kUpArrow_Type; |
| cstate = Control::kDisabled_State; |
| break; |
| case ABS_DOWNDISABLED: |
| CHECK_EQ(classic_state, DFCS_SCROLLDOWN | DFCS_INACTIVE); |
| ctype = Control::kDownArrow_Type; |
| cstate = Control::kDisabled_State; |
| break; |
| case ABS_LEFTDISABLED: |
| CHECK_EQ(classic_state, DFCS_SCROLLLEFT | DFCS_INACTIVE); |
| ctype = Control::kLeftArrow_Type; |
| cstate = Control::kDisabled_State; |
| break; |
| case ABS_RIGHTDISABLED: |
| CHECK_EQ(classic_state, DFCS_SCROLLRIGHT | DFCS_INACTIVE); |
| ctype = Control::kRightArrow_Type; |
| cstate = Control::kDisabled_State; |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| |
| drawControl(canvas, rect, ctype, cstate); |
| } |
| |
| void Engine::paintScrollbarThumb(WebCanvas* canvas, int part, int state, |
| int classic_state, const WebRect& rect) { |
| Control::Type ctype = Control::kUnknown_Type; |
| Control::State cstate = Control::kUnknown_State; |
| |
| switch (part) { |
| case SBP_THUMBBTNHORZ: |
| ctype = Control::kHorizontalScrollThumb_Type; |
| break; |
| case SBP_THUMBBTNVERT: |
| ctype = Control::kVerticalScrollThumb_Type; |
| break; |
| case SBP_GRIPPERHORZ: |
| ctype = Control::kHorizontalScrollGrip_Type; |
| break; |
| case SBP_GRIPPERVERT: |
| ctype = Control::kVerticalScrollGrip_Type; |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| |
| switch (state) { |
| case SCRBS_NORMAL: |
| CHECK_EQ(classic_state, kDFCSNormal); |
| cstate = Control::kNormal_State; |
| break; |
| case SCRBS_HOT: |
| CHECK_EQ(classic_state, DFCS_HOT); |
| cstate = Control::kHot_State; |
| break; |
| case SCRBS_HOVER: |
| CHECK_EQ(classic_state, kDFCSNormal); |
| cstate = Control::kHover_State; |
| break; |
| case SCRBS_PRESSED: |
| CHECK_EQ(classic_state, kDFCSNormal); |
| cstate = Control::kPressed_State; |
| break; |
| case SCRBS_DISABLED: |
| NOTREACHED(); // This should never happen in practice. |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| |
| drawControl(canvas, rect, ctype, cstate); |
| } |
| |
| void Engine::paintScrollbarTrack(WebCanvas* canvas, int part, int state, |
| int classic_state, const WebRect& rect, |
| const WebRect& align_rect) { |
| Control::Type ctype = Control::kUnknown_Type; |
| Control::State cstate = Control::kUnknown_State; |
| |
| switch (part) { |
| case SBP_UPPERTRACKHORZ: |
| ctype = Control::kHorizontalScrollTrackBack_Type; |
| break; |
| case SBP_LOWERTRACKHORZ: |
| ctype = Control::kHorizontalScrollTrackForward_Type; |
| break; |
| case SBP_UPPERTRACKVERT: |
| ctype = Control::kVerticalScrollTrackBack_Type; |
| break; |
| case SBP_LOWERTRACKVERT: |
| ctype = Control::kVerticalScrollTrackForward_Type; |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| |
| switch (state) { |
| case SCRBS_NORMAL: |
| CHECK_EQ(classic_state, kDFCSNormal); |
| cstate = Control::kNormal_State; |
| break; |
| case SCRBS_HOT: |
| NOTREACHED(); // This should never happen in practice. |
| break; |
| case SCRBS_HOVER: |
| CHECK_EQ(classic_state, kDFCSNormal); |
| cstate = Control::kHover_State; |
| break; |
| case SCRBS_PRESSED: |
| NOTREACHED(); // This should never happen in practice. |
| break; |
| case SCRBS_DISABLED: |
| CHECK_EQ(classic_state, DFCS_INACTIVE); |
| cstate = Control::kDisabled_State; |
| break; |
| default: |
| CHECK(false); |
| break; |
| } |
| |
| drawControl(canvas, rect, ctype, cstate); |
| } |
| |
| void Engine::paintTextField(WebCanvas* canvas, int part, int state, |
| int classic_state, const WebRect& rect, |
| WebColor color, bool fill_content_area, |
| bool draw_edges) { |
| Control::Type ctype = Control::kUnknown_Type; |
| Control::State cstate = Control::kUnknown_State; |
| |
| CHECK_EQ(EP_EDITTEXT, part); |
| ctype = Control::kTextField_Type; |
| |
| switch (state) { |
| case ETS_NORMAL: |
| CHECK_EQ(classic_state, kDFCSNormal); |
| cstate = Control::kNormal_State; |
| break; |
| case ETS_HOT: |
| CHECK_EQ(classic_state, DFCS_HOT); |
| cstate = Control::kHot_State; |
| break; |
| case ETS_DISABLED: |
| CHECK_EQ(classic_state, DFCS_INACTIVE); |
| cstate = Control::kDisabled_State; |
| break; |
| case ETS_SELECTED: |
| CHECK_EQ(classic_state, DFCS_PUSHED); |
| cstate = Control::kPressed_State; |
| break; |
| case ETS_FOCUSED: |
| CHECK_EQ(classic_state, kDFCSNormal); |
| cstate = Control::kFocused_State; |
| break; |
| case ETS_READONLY: |
| CHECK_EQ(classic_state, kDFCSNormal); |
| cstate = Control::kReadOnly_State; |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| |
| drawTextField(canvas, rect, ctype, cstate, draw_edges, fill_content_area, |
| color); |
| } |
| |
| void Engine::paintTrackbar(WebCanvas* canvas, int part, int state, |
| int classic_state, const WebRect& rect) { |
| Control::Type ctype = Control::kUnknown_Type; |
| Control::State cstate = Control::kUnknown_State; |
| |
| if (TKP_THUMBBOTTOM == part) { |
| ctype = Control::kHorizontalSliderThumb_Type; |
| switch (state) { |
| case TUS_NORMAL: |
| CHECK_EQ(classic_state, kDFCSNormal); |
| cstate = Control::kNormal_State; |
| break; |
| case TUS_HOT: |
| CHECK_EQ(classic_state, DFCS_HOT); |
| cstate = Control::kHot_State; |
| break; |
| case TUS_DISABLED: |
| CHECK_EQ(classic_state, DFCS_INACTIVE); |
| cstate = Control::kDisabled_State; |
| break; |
| case TUS_PRESSED: |
| CHECK_EQ(classic_state, DFCS_PUSHED); |
| cstate = Control::kPressed_State; |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| } else if (TKP_TRACK == part) { |
| ctype = Control::kHorizontalSliderTrack_Type; |
| CHECK_EQ(part, TUS_NORMAL); |
| CHECK_EQ(classic_state, kDFCSNormal); |
| cstate = Control::kNormal_State; |
| } else { |
| NOTREACHED(); |
| } |
| |
| drawControl(canvas, rect, ctype, cstate); |
| } |
| |
| |
| void Engine::paintProgressBar(WebKit::WebCanvas* canvas, |
| const WebKit::WebRect& barRect, |
| const WebKit::WebRect& valueRect, |
| bool determinate, double) { |
| Control::Type ctype = Control::kProgressBar_Type; |
| Control::State cstate = |
| determinate ? Control::kNormal_State : Control::kIndeterminate_State; |
| drawProgressBar(canvas, ctype, cstate, barRect, valueRect); |
| } |
| |
| } // namespace TestShellWebTheme |