summaryrefslogtreecommitdiffstats
path: root/webkit/tools/test_shell
diff options
context:
space:
mode:
authordpranke@google.com <dpranke@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-14 21:19:21 +0000
committerdpranke@google.com <dpranke@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-14 21:19:21 +0000
commitcf37da383867e81a5998fb06f5bca52dc92552c7 (patch)
treef5cd435729061d74f739cadd0d51a09019c849c2 /webkit/tools/test_shell
parenta1b9f5d1be682acc27767c121e282b2353510b48 (diff)
downloadchromium_src-cf37da383867e81a5998fb06f5bca52dc92552c7.zip
chromium_src-cf37da383867e81a5998fb06f5bca52dc92552c7.tar.gz
chromium_src-cf37da383867e81a5998fb06f5bca52dc92552c7.tar.bz2
This change adds a new "generic" theme to the Windows implementation of
test_shell, so that we can render controls in a platform-verion-independent manner, allowing us to use (almost) a single set of baselines for all versions of Windows. test_shell is modified to accept three new switches: --ux-theme (for the default or "new" XP/Vista theming engine), --classic-theme (for the older "Classic" theming engine), and --generic-theme (for the new Skia-based test theme). Specifying --layout-tests will default to --classic-theme, otherwise --ux-theme is the default (this is compatible with existing test_shell behavior). Once the new version-independent baselines are checked in, we will flip this behavior so --layout-tests defaults to --generic-theme as well. This change adds test_shell_webtheme{engine,control}.{cc,h} as Windows-only build files, and adds documentation to webkit/api/public/win/WebThemeEngine. It also adds a chromium-win-xp platform baseline directory (currently empty) and modifies the layout_test/layout_package/platform_utils_win.py baseline search path to confirm to WebKit's directory search logic (vista and win7 look just in chromium-win, but XP looks in chromium-win-xp first, followed by chromium-win). BUG=none R=darin,pkasting TEST=none Review URL: http://codereview.chromium.org/192021 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@26161 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/tools/test_shell')
-rw-r--r--webkit/tools/test_shell/test_shell.gyp5
-rw-r--r--webkit/tools/test_shell/test_shell_main.cc17
-rw-r--r--webkit/tools/test_shell/test_shell_switches.cc11
-rw-r--r--webkit/tools/test_shell/test_shell_switches.h3
-rw-r--r--webkit/tools/test_shell/test_shell_webkit_init.h29
-rw-r--r--webkit/tools/test_shell/test_shell_webthemecontrol.cc395
-rw-r--r--webkit/tools/test_shell/test_shell_webthemecontrol.h170
-rw-r--r--webkit/tools/test_shell/test_shell_webthemeengine.cc536
-rw-r--r--webkit/tools/test_shell/test_shell_webthemeengine.h64
9 files changed, 1224 insertions, 6 deletions
diff --git a/webkit/tools/test_shell/test_shell.gyp b/webkit/tools/test_shell/test_shell.gyp
index 585e38d..e1648f7 100644
--- a/webkit/tools/test_shell/test_shell.gyp
+++ b/webkit/tools/test_shell/test_shell.gyp
@@ -85,6 +85,10 @@
'test_shell_switches.h',
'test_shell_win.cc',
'test_shell_webkit_init.h',
+ 'test_shell_webthemecontrol.h',
+ 'test_shell_webthemecontrol.cc',
+ 'test_shell_webthemeengine.h',
+ 'test_shell_webthemeengine.cc',
'test_web_worker.h',
'test_webview_delegate.cc',
'test_webview_delegate.h',
@@ -178,6 +182,7 @@
}, { # else: OS!=win
'sources/': [
['exclude', '_win\\.cc$'],
+ ['exclude', '_webtheme(control|engine)\.(cc|h)$'],
],
'sources!': [
'drag_delegate.cc',
diff --git a/webkit/tools/test_shell/test_shell_main.cc b/webkit/tools/test_shell/test_shell_main.cc
index 8f18386..ff280f4 100644
--- a/webkit/tools/test_shell/test_shell_main.cc
+++ b/webkit/tools/test_shell/test_shell_main.cc
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <iostream>
-
#include "base/at_exit.h"
#include "base/basictypes.h"
#include "base/command_line.h"
@@ -80,6 +78,11 @@ int main(int argc, char* argv[]) {
parsed_command_line.HasSwitch(test_shell::kLayoutTests));
bool layout_test_mode =
parsed_command_line.HasSwitch(test_shell::kLayoutTests);
+ bool ux_theme = parsed_command_line.HasSwitch(test_shell::kUxTheme);
+ bool generic_theme =
+ parsed_command_line.HasSwitch(test_shell::kGenericTheme);
+ bool classic_theme = (layout_test_mode && !ux_theme && !generic_theme) ||
+ parsed_command_line.HasSwitch(test_shell::kClassicTheme);
bool enable_gp_fault_error_box = false;
enable_gp_fault_error_box =
@@ -156,9 +159,15 @@ int main(int argc, char* argv[]) {
TestShell::SetAllowScriptsToCloseWindows();
// Disable user themes for layout tests so pixel tests are consistent.
- if (layout_test_mode) {
+#if defined(OS_WIN)
+ TestShellWebTheme::Engine engine;
+#endif
+ if (classic_theme)
platform.SelectUnifiedTheme();
- }
+#if defined(OS_WIN)
+ if (generic_theme)
+ test_shell_webkit_init.setThemeEngine(&engine);
+#endif
if (parsed_command_line.HasSwitch(test_shell::kTestShellTimeOut)) {
const std::wstring timeout_str = parsed_command_line.GetSwitchValue(
diff --git a/webkit/tools/test_shell/test_shell_switches.cc b/webkit/tools/test_shell/test_shell_switches.cc
index 0884929..26a79cb 100644
--- a/webkit/tools/test_shell/test_shell_switches.cc
+++ b/webkit/tools/test_shell/test_shell_switches.cc
@@ -14,6 +14,17 @@ const wchar_t kNoErrorDialogs[] = L"noerrdialogs";
const wchar_t kLayoutTests[] = L"layout-tests";
const wchar_t kCrashDumps[] = L"crash-dumps"; // Enable crash dumps
+// Causes the test_shell to run with a generic theme (part of layout_tests).
+const wchar_t kGenericTheme[] = L"generic-theme";
+
+// This causes the test_shell to run with the classic theme.
+// Passing --layout-tests enables this by default.
+const wchar_t kClassicTheme[] = L"classic-theme";
+
+// This causes the test_shell to run with the new windows theming engine
+// enabled. This is the default unless --layout-tests is specified.
+const wchar_t kUxTheme[] = L"ux-theme";
+
// Command line flags that control the tests when layout-tests is specified.
const wchar_t kNoTree[] = L"notree"; // Don't dump the render tree.
const wchar_t kDumpPixels[] = L"pixel-tests"; // Enable pixel tests.
diff --git a/webkit/tools/test_shell/test_shell_switches.h b/webkit/tools/test_shell/test_shell_switches.h
index be995d1..d07398b 100644
--- a/webkit/tools/test_shell/test_shell_switches.h
+++ b/webkit/tools/test_shell/test_shell_switches.h
@@ -12,6 +12,9 @@ namespace test_shell {
extern const wchar_t kCrashDumps[];
extern const wchar_t kDumpPixels[];
extern const wchar_t kLayoutTests[];
+extern const wchar_t kGenericTheme[];
+extern const wchar_t kClassicTheme[];
+extern const wchar_t kUxTheme[];
extern const wchar_t kNoErrorDialogs[];
extern const wchar_t kNoTree[];
extern const wchar_t kTestShellTimeOut[];
diff --git a/webkit/tools/test_shell/test_shell_webkit_init.h b/webkit/tools/test_shell/test_shell_webkit_init.h
index 354d949..cc25ec7 100644
--- a/webkit/tools/test_shell/test_shell_webkit_init.h
+++ b/webkit/tools/test_shell/test_shell_webkit_init.h
@@ -29,9 +29,14 @@
#include "webkit/tools/test_shell/simple_resource_loader_bridge.h"
#include "v8/include/v8.h"
+#if defined(OS_WIN)
+#include "webkit/api/public/win/WebThemeEngine.h"
+#include "webkit/tools/test_shell/test_shell_webthemeengine.h"
+#endif
+
class TestShellWebKitInit : public webkit_glue::WebKitClientImpl {
public:
- TestShellWebKitInit(bool layout_test_mode) {
+ explicit TestShellWebKitInit(bool layout_test_mode) {
v8::V8::SetCounterFunction(StatsTable::FindLocation);
WebKit::initialize(this);
@@ -56,6 +61,11 @@ class TestShellWebKitInit : public webkit_glue::WebKitClientImpl {
// content during the run. Upon exit that directory is deleted.
if (appcache_dir_.CreateUniqueTempDir())
SimpleAppCacheSystem::InitializeOnUIThread(appcache_dir_.path());
+
+#if defined(OS_WIN)
+ // Ensure we pick up the default theme engine.
+ setThemeEngine(NULL);
+#endif
}
~TestShellWebKitInit() {
@@ -84,7 +94,8 @@ class TestShellWebKitInit : public webkit_glue::WebKitClientImpl {
return false;
}
- virtual bool getFileSize(const WebKit::WebString& path, long long& result) {
+ virtual bool getFileSize(const WebKit::WebString& path,
+ long long& result) {
return file_util::GetFileSize(
FilePath(webkit_glue::WebStringToFilePathString(path)),
reinterpret_cast<int64*>(&result));
@@ -158,12 +169,26 @@ class TestShellWebKitInit : public webkit_glue::WebKitClientImpl {
return SimpleAppCacheSystem::CreateApplicationCacheHost(client);
}
+#if defined(OS_WIN)
+ void setThemeEngine(WebKit::WebThemeEngine* engine) {
+ active_theme_engine_ = engine ? engine : WebKitClientImpl::themeEngine();
+ }
+
+ virtual WebKit::WebThemeEngine *themeEngine() {
+ return active_theme_engine_;
+ }
+#endif
+
private:
webkit_glue::SimpleWebMimeRegistryImpl mime_registry_;
MockWebClipboardImpl mock_clipboard_;
webkit_glue::WebClipboardImpl real_clipboard_;
ScopedTempDir appcache_dir_;
SimpleAppCacheSystem appcache_system_;
+
+#if defined(OS_WIN)
+ WebKit::WebThemeEngine* active_theme_engine_;
+#endif
};
#endif // WEBKIT_TOOLS_TEST_SHELL_TEST_SHELL_WEBKIT_INIT_H_
diff --git a/webkit/tools/test_shell/test_shell_webthemecontrol.cc b/webkit/tools/test_shell/test_shell_webthemecontrol.cc
new file mode 100644
index 0000000..1d806f3
--- /dev/null
+++ b/webkit/tools/test_shell/test_shell_webthemecontrol.cc
@@ -0,0 +1,395 @@
+// Copyright (c) 2009 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,
+// which is used to draw all the native controls on a web page. We use this
+// file when running in layout test mode in order to remove any
+// platform-specific rendering differences due to themes, colors, etc.
+//
+
+#include "webkit/tools/test_shell/test_shell_webthemecontrol.h"
+
+#include "base/logging.h"
+#include "skia/ext/platform_canvas.h"
+#include "skia/ext/skia_utils_win.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkPath.h"
+
+namespace TestShellWebTheme {
+
+const SkColor kEdgeColor = SkColorSetRGB(0, 0, 0);
+const SkColor kReadOnlyColor = SkColorSetRGB(0xe9, 0xc2, 0xa6);
+const SkColor kFgColor = SkColorSetRGB(0, 0, 0);
+
+const SkColor kBgColors[] = {
+ SkColorSetRGB(0, 0, 0), // Unknown
+ SkColorSetRGB(0xc9, 0xc9, 0xc9), // Disabled
+ SkColorSetRGB(0xf3, 0xe0, 0xd0), // Readonly
+ SkColorSetRGB(0x89, 0xc4, 0xff), // Normal
+ SkColorSetRGB(0x43, 0xf9, 0xff), // Hot
+ SkColorSetRGB(0x20, 0xf6, 0xcc), // Focused
+ SkColorSetRGB(0x00, 0xf3, 0xac), // Hover
+ SkColorSetRGB(0xa9, 0xff, 0x12) // Pressed
+};
+
+Control::Control(skia::PlatformCanvas *canvas, const SkIRect &irect,
+ Type ctype, State cstate)
+ : canvas_(canvas),
+ irect_(irect),
+ type_(ctype),
+ state_(cstate),
+ left_(irect.fLeft),
+ right_(irect.fRight),
+ top_(irect.fTop),
+ bottom_(irect.fBottom),
+ height_(irect.height()),
+ width_(irect.width()),
+ edge_color_(kEdgeColor),
+ bg_color_(kBgColors[cstate]),
+ fg_color_(kFgColor) {
+}
+
+Control::~Control() {
+}
+
+void Control::box(const SkIRect &rect, SkColor fill_color) {
+ SkPaint paint;
+
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(fill_color);
+ canvas_->drawIRect(rect, paint);
+
+ paint.setColor(edge_color_);
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas_->drawIRect(rect, paint);
+}
+
+void Control::line(int x0, int y0, int x1, int y1, SkColor color) {
+ SkPaint paint;
+ paint.setColor(color);
+ canvas_->drawLine(SkIntToScalar(x0), SkIntToScalar(y0),
+ SkIntToScalar(x1), SkIntToScalar(y1),
+ paint);
+}
+
+void Control::triangle(int x0, int y0,
+ int x1, int y1,
+ int x2, int y2,
+ SkColor color) {
+ SkPath path;
+ SkPaint paint;
+
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ path.incReserve(4);
+ path.moveTo(SkIntToScalar(x0), SkIntToScalar(y0));
+ path.lineTo(SkIntToScalar(x1), SkIntToScalar(y1));
+ path.lineTo(SkIntToScalar(x2), SkIntToScalar(y2));
+ path.close();
+ canvas_->drawPath(path, paint);
+
+ paint.setColor(edge_color_);
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas_->drawPath(path, paint);
+}
+
+void Control::roundRect(SkColor color) {
+ SkRect rect;
+ SkScalar radius = SkIntToScalar(5);
+ SkPaint paint;
+
+ rect.set(irect_);
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ canvas_->drawRoundRect(rect, radius, radius, paint);
+
+ paint.setColor(edge_color_);
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas_->drawRoundRect(rect, radius, radius, paint);
+}
+
+void Control::oval(SkColor color) {
+ SkRect rect;
+ SkPaint paint;
+
+ rect.set(irect_);
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ canvas_->drawOval(rect, paint);
+
+ paint.setColor(edge_color_);
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas_->drawOval(rect, paint);
+}
+
+void Control::circle(SkScalar radius, SkColor color) {
+ SkScalar cy = SkIntToScalar(top_ + height_ / 2);
+ SkScalar cx = SkIntToScalar(left_ + width_ / 2);
+ SkPaint paint;
+
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ canvas_->drawCircle(cx, cy, radius, paint);
+
+ paint.setColor(edge_color_);
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas_->drawCircle(cx, cy, radius, paint);
+}
+
+void Control::nested_boxes(int indent_left, int indent_top,
+ int indent_right, int indent_bottom,
+ SkColor outer_color, SkColor inner_color) {
+ SkIRect lirect;
+ box(irect_, outer_color);
+ lirect.set(irect_.fLeft + indent_left, irect_.fTop + indent_top,
+ irect_.fRight - indent_right, irect_.fBottom - indent_bottom);
+ box(lirect, inner_color);
+}
+
+
+void Control::markState() {
+ // The horizontal lines in a read only control are spaced by this amount.
+ const int kReadOnlyLineOffset = 5;
+
+ // The length of a triangle side for the corner marks.
+ const int kTriangleSize = 5;
+
+ switch (state_) {
+ case kUnknown_State: // FALLTHROUGH
+ case kDisabled_State: // FALLTHROUGH
+ case kNormal_State:
+ // Don't visually mark these states (color is enough).
+ break;
+ case kReadOnly_State:
+ // Drawing lines across the control.
+ for (int i = top_ + kReadOnlyLineOffset; i < bottom_ ;
+ i += kReadOnlyLineOffset) {
+ line(left_ + 1, i, right_ - 1, i, kReadOnlyColor);
+ }
+ break;
+ case kHot_State:
+ // Draw a triangle in the upper left corner of the control.
+ triangle(left_, top_,
+ left_ + kTriangleSize, top_,
+ left_, top_ + kTriangleSize, edge_color_);
+ break;
+ case kHover_State:
+ // Draw a triangle in the upper right corner of the control.
+ triangle(right_, top_,
+ right_, top_ + kTriangleSize,
+ right_ - kTriangleSize, top_, edge_color_);
+ break;
+ case kFocused_State:
+ // Draw a triangle in the bottom right corner of the control.
+ triangle(right_, bottom_,
+ right_ - kTriangleSize, bottom_,
+ right_, bottom_ - kTriangleSize, edge_color_);
+ break;
+ case kPressed_State:
+ // Draw a triangle in the bottom left corner of the control.
+ triangle(left_, bottom_,
+ left_, bottom_ - kTriangleSize,
+ left_ + kTriangleSize, bottom_, edge_color_);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+void Control::draw() {
+ int half_width = width_ / 2;
+ int half_height = height_ / 2;
+ int quarter_width = width_ / 4;
+ int quarter_height = height_ / 4;
+
+ // Indent amounts for the check in a checkbox or radio button.
+ const int kCheckIndent = 3;
+
+ // Indent amounts for short and long sides of the scrollbar notches.
+ const int kNotchLongOffset = 1;
+ const int kNotchShortOffset = 4;
+ const int kNoOffset = 0;
+ int short_offset;
+ int long_offset;
+
+ // Indent amounts for the short and long sides of a scroll thumb box.
+ const int kThumbLongIndent = 0;
+ const int kThumbShortIndent = 2;
+
+ // Indents for the crosshatch on a scroll grip.
+ const int kGripLongIndent = 3;
+ const int kGripShortIndent = 5;
+
+ // Indents for the the slider track.
+ const int kSliderIndent = 2;
+
+ canvas_->beginPlatformPaint();
+ switch (type_) {
+ case kUnknown_Type:
+ NOTREACHED();
+ break;
+ case kTextField_Type:
+ // We render this by hand outside of this function.
+ NOTREACHED();
+ break;
+ case kPushButton_Type:
+ // push buttons render as a rounded rectangle
+ roundRect(bg_color_);
+ break;
+ case kUncheckedBox_Type:
+ // Unchecked boxes are simply plain boxes.
+ box(irect_, bg_color_);
+ break;
+ case kCheckedBox_Type:
+ nested_boxes(kCheckIndent, kCheckIndent, kCheckIndent, kCheckIndent,
+ bg_color_, fg_color_);
+ break;
+ case kUncheckedRadio_Type:
+ circle(SkIntToScalar(half_height), bg_color_);
+ break;
+ case kCheckedRadio_Type:
+ circle(SkIntToScalar(half_height), bg_color_);
+ circle(SkIntToScalar(half_height - kCheckIndent), fg_color_);
+ break;
+ case kHorizontalScrollTrackBack_Type:
+ // Draw a box with a notch at the left.
+ long_offset = half_height - kNotchLongOffset;
+ short_offset = width_ - kNotchShortOffset;
+ nested_boxes(kNoOffset, long_offset, short_offset, long_offset,
+ bg_color_, edge_color_);
+ break;
+ case kHorizontalScrollTrackForward_Type:
+ // Draw a box with a notch at the right.
+ long_offset = half_height - kNotchLongOffset;
+ short_offset = width_ - kNotchShortOffset;
+ nested_boxes(short_offset, long_offset, kNoOffset, long_offset,
+ bg_color_, fg_color_);
+ break;
+ case kVerticalScrollTrackBack_Type:
+ // Draw a box with a notch at the top.
+ long_offset = half_width - kNotchLongOffset;
+ short_offset = height_ - kNotchShortOffset;
+ nested_boxes(long_offset, kNoOffset, long_offset, short_offset,
+ bg_color_, fg_color_);
+ break;
+ case kVerticalScrollTrackForward_Type:
+ // Draw a box with a notch at the bottom.
+ long_offset = half_width - kNotchLongOffset;
+ short_offset = height_ - kNotchShortOffset;
+ nested_boxes(long_offset, short_offset, long_offset, kNoOffset,
+ bg_color_, fg_color_);
+ break;
+ case kHorizontalScrollThumb_Type:
+ // Draw a narrower box on top of the outside box.
+ nested_boxes(kThumbLongIndent, kThumbShortIndent, kThumbLongIndent,
+ kThumbShortIndent, bg_color_, bg_color_);
+ break;
+ case kVerticalScrollThumb_Type:
+ // Draw a shorter box on top of the outside box.
+ nested_boxes(kThumbShortIndent, kThumbLongIndent, kThumbShortIndent,
+ kThumbLongIndent, bg_color_, bg_color_);
+ break;
+ case kHorizontalSliderThumb_Type:
+ // Slider thumbs are ovals.
+ oval(bg_color_);
+ break;
+ case kHorizontalScrollGrip_Type:
+ // Draw a horizontal crosshatch for the grip.
+ long_offset = half_width - kGripLongIndent;
+ line(left_ + kGripLongIndent, top_ + half_height,
+ right_ - kGripLongIndent, top_ + half_height, fg_color_);
+ line(left_ + long_offset, top_ + kGripShortIndent,
+ left_ + long_offset, bottom_ - kGripShortIndent, fg_color_);
+ line(right_ - long_offset, top_ + kGripShortIndent,
+ right_ - long_offset, bottom_ - kGripShortIndent, fg_color_);
+ break;
+ case kVerticalScrollGrip_Type:
+ // Draw a vertical crosshatch for the grip.
+ long_offset = half_height - kGripLongIndent;
+ line(left_ + half_width, top_ + kGripLongIndent,
+ left_ + half_width, bottom_ - kGripLongIndent, fg_color_);
+ line(left_ + kGripShortIndent, top_ + long_offset,
+ right_ - kGripShortIndent, top_ + long_offset, fg_color_);
+ line(left_ + kGripShortIndent, bottom_ - long_offset,
+ right_ - kGripShortIndent, bottom_ - long_offset, fg_color_);
+ break;
+ case kLeftArrow_Type:
+ // Draw a left arrow inside a box.
+ box(irect_, bg_color_);
+ triangle(right_ - quarter_width, top_ + quarter_height,
+ right_ - quarter_width, bottom_ - quarter_height,
+ left_ + quarter_width, top_ + half_height, fg_color_);
+ break;
+ case kRightArrow_Type:
+ // Draw a left arrow inside a box.
+ box(irect_, bg_color_);
+ triangle(left_ + quarter_width, top_ + quarter_height,
+ right_ - quarter_width, top_ + half_height,
+ left_ + quarter_width, bottom_ - quarter_height, fg_color_);
+ break;
+ case kUpArrow_Type:
+ // Draw an up arrow inside a box.
+ box(irect_, bg_color_);
+ triangle(left_ + quarter_width, bottom_ - quarter_height,
+ left_ + half_width, top_ + quarter_height,
+ right_ - quarter_width, bottom_ - quarter_height, fg_color_);
+ break;
+ case kDownArrow_Type:
+ // Draw a down arrow inside a box.
+ box(irect_, bg_color_);
+ triangle(left_ + quarter_width, top_ + quarter_height,
+ right_ - quarter_width, top_ + quarter_height,
+ left_ + half_width, bottom_ - quarter_height, fg_color_);
+ break;
+ case kHorizontalSliderTrack_Type:
+ // Draw a narrow rect for the track plus box hatches on the ends.
+ SkIRect lirect;
+ lirect = irect_;
+ lirect.inset(kNoOffset, half_height - kSliderIndent);
+ box(lirect, bg_color_);
+ line(left_, top_, left_, bottom_, edge_color_);
+ line(right_, top_, right_, bottom_, edge_color_);
+ break;
+ case kDropDownButton_Type:
+ // Draw a box with a big down arrow on top.
+ box(irect_, bg_color_);
+ triangle(left_ + quarter_width, top_,
+ right_ - quarter_width, top_,
+ left_ + half_width, bottom_, fg_color_);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+
+ markState();
+ canvas_->endPlatformPaint();
+}
+
+// Because rendering a text field is dependent on input
+// parameters the other controls don't have, we render it directly
+// rather than trying to overcomplicate draw() further.
+void Control::drawTextField(bool draw_edges, bool fill_content_area,
+ SkColor color) {
+ SkPaint paint;
+
+ canvas_->beginPlatformPaint();
+ if (fill_content_area) {
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kFill_Style);
+ canvas_->drawIRect(irect_, paint);
+ }
+ if (draw_edges) {
+ paint.setColor(edge_color_);
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas_->drawIRect(irect_, paint);
+ }
+
+ markState();
+ canvas_->endPlatformPaint();
+}
+
+} // namespace TestShellWebTheme
+
diff --git a/webkit/tools/test_shell/test_shell_webthemecontrol.h b/webkit/tools/test_shell/test_shell_webthemecontrol.h
new file mode 100644
index 0000000..bb439af
--- /dev/null
+++ b/webkit/tools/test_shell/test_shell_webthemecontrol.h
@@ -0,0 +1,170 @@
+// Copyright (c) 2009 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.
+
+// TestShellWebTheme::Control implements the generic rendering of controls
+// needed by TestShellWebTheme::Engine. See the comments in that class
+// header file for why this class is needed and used.
+//
+// This class implements a generic set of widgets using Skia. The widgets
+// are optimized for testability, not a pleasing appearance.
+//
+
+#ifndef WEBKIT_TOOLS_TEST_SHELL_TEST_SHELL_WEBTHEMECONTROL_H_
+#define WEBKIT_TOOLS_TEST_SHELL_TEST_SHELL_WEBTHEMECONTROL_H_
+
+#include "base/basictypes.h"
+#include "skia/ext/platform_canvas.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkRect.h"
+
+namespace TestShellWebTheme {
+
+class Control {
+ public:
+ // This list of states mostly mirrors the list in
+ // third_party/WebKit/WebCore/platform/ThemeTypes.h but is maintained
+ // separately since that isn't public and also to minimize dependencies.
+ // Note that the WebKit ThemeTypes seem to imply that a control can be
+ // in multiple states simultaneously but WebThemeEngine only allows for
+ // a single state at a time.
+ //
+ // Some definitions for the various states:
+ // Disabled - indicates that a control can't be modified or selected
+ // (corresponds to HTML 'disabled' attribute)
+ // ReadOnly - indicates that a control can't be modified but can be
+ // selected
+ // Normal - the normal state of control on the page when it isn't
+ // focused or otherwise active
+ // Hot - when the mouse is hovering over a part of the control,
+ // all the other parts are considered "hot"
+ // Hover - when the mouse is directly over a control (the CSS
+ // :hover pseudo-class)
+ // Focused - when the control has the keyboard focus
+ // Pressed - when the control is being triggered (by a mousedown or
+ // a key event).
+ enum State {
+ kUnknown_State = 0,
+ kDisabled_State,
+ kReadOnly_State,
+ kNormal_State,
+ kHot_State,
+ kHover_State,
+ kFocused_State,
+ kPressed_State
+ };
+
+ // This list of types mostly mirrors the list in
+ // third_party/WebKit/WebCore/platform/ThemeTypes.h but is maintained
+ // separately since that isn't public and also to minimize dependencies.
+ //
+ // Note that what the user might think of as a single control can be
+ // made up of multiple parts. For example, a single scroll bar contains
+ // six clickable parts - two arrows, the "thumb" indicating the current
+ // position on the bar, the other two parts of the bar (before and after
+ // the thumb) and the "gripper" on the thumb itself.
+ //
+ enum Type {
+ kUnknown_Type = 0,
+ kTextField_Type,
+ kPushButton_Type,
+ kUncheckedBox_Type,
+ kCheckedBox_Type,
+ kUncheckedRadio_Type,
+ kCheckedRadio_Type,
+ kHorizontalScrollTrackBack_Type,
+ kHorizontalScrollTrackForward_Type,
+ kHorizontalScrollThumb_Type,
+ kHorizontalScrollGrip_Type,
+ kVerticalScrollTrackBack_Type,
+ kVerticalScrollTrackForward_Type,
+ kVerticalScrollThumb_Type,
+ kVerticalScrollGrip_Type,
+ kLeftArrow_Type,
+ kRightArrow_Type,
+ kUpArrow_Type,
+ kDownArrow_Type,
+ kHorizontalSliderTrack_Type,
+ kHorizontalSliderThumb_Type,
+ kDropDownButton_Type
+ };
+
+ // canvas is the canvas to draw onto, and rect gives the size of the
+ // control. ctype and cstate specify the type and state of the control.
+ Control(skia::PlatformCanvas *canvas, const SkIRect &rect,
+ Type ctype, State cstate);
+ ~Control();
+
+ // Draws the control.
+ void draw();
+
+ // Use this for TextField controls instead, because the logic
+ // for drawing them is dependent on what WebKit tells us to do.
+ // If draw_edges is true, draw an edge around the control. If
+ // fill_content_area is true, fill the content area with the given color.
+ void drawTextField(bool draw_edges, bool fill_content_area, SkColor color);
+
+ private:
+ // Draws a box of size specified by irect, filled with the given color.
+ // The box will have a border drawn in the default edge color.
+ void box(const SkIRect &irect, SkColor color);
+
+
+ // Draws a triangle of size specified by the three pairs of coordinates,
+ // filled with the given color. The box will have an edge drawn in the
+ // default edge color.
+ void triangle(int x0, int y0, int x1, int y1, int x2, int y2,
+ SkColor color);
+
+ // Draws a rectangle the size of the control with rounded corners, filled
+ // with the specified color (and with a border in the default edge color).
+ void roundRect(SkColor color);
+
+ // Draws an oval the size of the control, filled with the specified color
+ // and with a border in the default edge color.
+ void oval(SkColor color);
+
+ // Draws a circle centered in the control with the specified radius,
+ // filled with the specified color, and with a border draw in the
+ // default edge color.
+ void circle(SkScalar radius, SkColor color);
+
+ // Draws a box the size of the control, filled with the outer_color and
+ // with a border in the default edge color, and then draws another box
+ // indented on all four sides by the specified amounts, filled with the
+ // inner color and with a border in the default edge color.
+ void nested_boxes(int indent_left, int indent_top,
+ int indent_right, int indent_bottom,
+ SkColor outer_color, SkColor inner_color);
+
+ // Draws a line between the two points in the given color.
+ void line(int x0, int y0, int x1, int y1, SkColor color);
+
+ // Draws a distinctive mark on the control for each state, so that the
+ // state of the control can be determined without needing to know which
+ // color is which.
+ void markState();
+
+ skia::PlatformCanvas* canvas_;
+ const SkIRect irect_;
+ const Type type_;
+ const State state_;
+ const SkColor edge_color_;
+ const SkColor bg_color_;
+ const SkColor fg_color_;
+
+ // The following are convenience accessors for irect_.
+ const int left_;
+ const int right_;
+ const int top_;
+ const int bottom_;
+ const int width_;
+ const int height_;
+
+ DISALLOW_COPY_AND_ASSIGN(Control);
+};
+
+} // namespace TestShellWebTheme
+
+#endif // WEBKIT_TOOLS_TEST_SHELL_TEST_SHELL_WEBTHEMECONTROL_H_
+
diff --git a/webkit/tools/test_shell/test_shell_webthemeengine.cc b/webkit/tools/test_shell/test_shell_webthemeengine.cc
new file mode 100644
index 0000000..95c7d75
--- /dev/null
+++ b/webkit/tools/test_shell/test_shell_webthemeengine.cc
@@ -0,0 +1,536 @@
+// Copyright (c) 2009 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 "webkit/api/public/WebCanvas.h"
+#include "webkit/api/public/WebRect.h"
+#include "webkit/tools/test_shell/test_shell_webthemecontrol.h"
+#include "third_party/skia/include/core/SkRect.h"
+
+#ifndef CHECK_EQ
+#define CHECK_EQ(a, b) CHECK((a) == (b))
+#endif
+
+// 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 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;
+ 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);
+}
+
+} // namespace TestShellWebTheme
diff --git a/webkit/tools/test_shell/test_shell_webthemeengine.h b/webkit/tools/test_shell/test_shell_webthemeengine.h
new file mode 100644
index 0000000..c4b1fce
--- /dev/null
+++ b/webkit/tools/test_shell/test_shell_webthemeengine.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2009 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.
+
+// TestShellWebTheme::Engine implements the WebThemeEngine
+// API used by the Windows version of Chromium to render native form
+// controls like checkboxes, radio buttons, and scroll bars. The normal
+// implementation (native_theme) renders the controls using either the
+// UXTheme theming engine present in XP, Vista, and Win 7, or the "classic"
+// theme used if that theme is selected in the Desktop settings.
+// Unfortunately, both of these themes render controls differently on the
+// different versions of Windows.
+//
+// In order to ensure maximum consistency of baselines across the different
+// Windows versions, we provide a simple implementation for test_shell here
+// instead. These controls are actually platform-independent (they're rendered
+// using Skia) and could be used on Linux and the Mac as well, should we
+// choose to do so at some point.
+//
+
+#ifndef WEBKIT_TOOLS_TEST_SHELL_TEST_SHELL_WEBTHEMEENGINE_H_
+#define WEBKIT_TOOLS_TEST_SHELL_TEST_SHELL_WEBTHEMEENGINE_H_
+
+#include "base/basictypes.h"
+#include "webkit/api/public/win/WebThemeEngine.h"
+
+namespace TestShellWebTheme {
+
+class Engine : public WebKit::WebThemeEngine {
+ public:
+ Engine() {}
+
+ // WebThemeEngine methods:
+ virtual void paintButton(
+ WebKit::WebCanvas*, int part, int state, int classic_state,
+ const WebKit::WebRect&);
+ virtual void paintMenuList(
+ WebKit::WebCanvas*, int part, int state, int classic_state,
+ const WebKit::WebRect&);
+ virtual void paintScrollbarArrow(
+ WebKit::WebCanvas*, int state, int classic_state,
+ const WebKit::WebRect&);
+ virtual void paintScrollbarThumb(
+ WebKit::WebCanvas*, int part, int state, int classic_state,
+ const WebKit::WebRect&);
+ virtual void paintScrollbarTrack(
+ WebKit::WebCanvas*, int part, int state, int classic_state,
+ const WebKit::WebRect&, const WebKit::WebRect& align_rect);
+ virtual void paintTextField(
+ WebKit::WebCanvas*, int part, int state, int classic_state,
+ const WebKit::WebRect&, WebKit::WebColor, bool fill_content_area,
+ bool draw_edges);
+ virtual void paintTrackbar(
+ WebKit::WebCanvas*, int part, int state, int classic_state,
+ const WebKit::WebRect&);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Engine);
+};
+
+} // namespace TestShellWebTheme
+
+#endif // WEBKIT_TOOLS_TEST_SHELL_TEST_SHELL_WEBTHEMEENGINE_H_
+