// 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.
#undef LOG
#include "webkit/tools/test_shell/test_shell.h"
#include "base/base_paths.h"
#include "base/command_line.h"
#include "base/debug_on_start.h"
#include "base/file_path.h"
#include "base/file_util.h"
#if defined(OS_MACOSX)
#include "base/mac_util.h"
#endif
#include "base/md5.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/stats_table.h"
#include "base/utf_string_conversions.h"
#include "build/build_config.h"
#include "gfx/codec/png_codec.h"
#include "gfx/size.h"
#include "googleurl/src/url_util.h"
#include "grit/webkit_strings.h"
#include "net/base/mime_util.h"
#include "net/base/net_util.h"
#include "net/url_request/url_request_file_job.h"
#include "net/url_request/url_request_filter.h"
#include "skia/ext/bitmap_platform_device.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/WebKit/WebKit/chromium/public/WebAccessibilityObject.h"
#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
#include "third_party/WebKit/WebKit/chromium/public/WebKit.h"
#include "third_party/WebKit/WebKit/chromium/public/WebScriptController.h"
#include "third_party/WebKit/WebKit/chromium/public/WebRect.h"
#include "third_party/WebKit/WebKit/chromium/public/WebSize.h"
#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
#include "third_party/WebKit/WebKit/chromium/public/WebURL.h"
#include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h"
#include "third_party/WebKit/WebKit/chromium/public/WebURLResponse.h"
#include "third_party/WebKit/WebKit/chromium/public/WebView.h"
#include "webkit/glue/glue_serialize.h"
#include "webkit/glue/webkit_glue.h"
#include "webkit/glue/webpreferences.h"
#include "webkit/tools/test_shell/accessibility_controller.h"
#include "webkit/tools/test_shell/notification_presenter.h"
#include "webkit/tools/test_shell/simple_resource_loader_bridge.h"
#include "webkit/tools/test_shell/test_navigation_controller.h"
#include "webkit/tools/test_shell/test_shell_devtools_agent.h"
#include "webkit/tools/test_shell/test_shell_devtools_client.h"
#include "webkit/tools/test_shell/test_shell_switches.h"
#include "webkit/tools/test_shell/test_webview_delegate.h"
using WebKit::WebCanvas;
using WebKit::WebFrame;
using WebKit::WebNavigationPolicy;
using WebKit::WebRect;
using WebKit::WebScriptController;
using WebKit::WebSize;
using WebKit::WebURLRequest;
using WebKit::WebView;
namespace {
// Default timeout in ms for file page loads when in layout test mode.
const int kDefaultFileTestTimeoutMillisecs = 10 * 1000;
// Content area size for newly created windows.
const int kTestWindowWidth = 800;
const int kTestWindowHeight = 600;
// The W3C SVG layout tests use a different size than the other layout
// tests.
const int kSVGTestWindowWidth = 480;
const int kSVGTestWindowHeight = 360;
// URLRequestTestShellFileJob is used to serve the inspector
class URLRequestTestShellFileJob : public URLRequestFileJob {
public:
static URLRequestJob* InspectorFactory(URLRequest* request,
const std::string& scheme) {
FilePath path;
PathService::Get(base::DIR_EXE, &path);
path = path.AppendASCII("resources");
path = path.AppendASCII("inspector");
path = path.AppendASCII(request->url().path().substr(1));
return new URLRequestTestShellFileJob(request, path);
}
private:
URLRequestTestShellFileJob(URLRequest* request, const FilePath& path)
: URLRequestFileJob(request, path) {
}
virtual ~URLRequestTestShellFileJob() { }
DISALLOW_COPY_AND_ASSIGN(URLRequestTestShellFileJob);
};
} // namespace
// Initialize static member variable
WindowList* TestShell::window_list_;
WebPreferences* TestShell::web_prefs_ = NULL;
bool TestShell::developer_extras_enabled_ = false;
bool TestShell::inspector_test_mode_ = false;
bool TestShell::layout_test_mode_ = false;
bool TestShell::allow_external_pages_ = false;
int TestShell::file_test_timeout_ms_ = kDefaultFileTestTimeoutMillisecs;
bool TestShell::test_is_preparing_ = false;
bool TestShell::test_is_pending_ = false;
TestShell::TestShell()
: m_mainWnd(NULL),
m_editWnd(NULL),
m_webViewHost(NULL),
m_popupHost(NULL),
m_focusedWidgetHost(NULL),
#if defined(OS_WIN)
default_edit_wnd_proc_(0),
#endif
test_params_(NULL),
is_modal_(false),
is_loading_(false),
allow_images_(true),
allow_plugins_(true),
allow_scripts_(true),
dump_stats_table_on_exit_(false) {
accessibility_controller_.reset(new AccessibilityController(this));
delegate_.reset(new TestWebViewDelegate(this));
popup_delegate_.reset(new TestWebViewDelegate(this));
layout_test_controller_.reset(new LayoutTestController(this));
event_sending_controller_.reset(new EventSendingController(this));
plain_text_controller_.reset(new PlainTextController(this));
text_input_controller_.reset(new TextInputController(this));
navigation_controller_.reset(new TestNavigationController(this));
notification_presenter_.reset(new TestNotificationPresenter(this));
URLRequestFilter* filter = URLRequestFilter::GetInstance();
filter->AddHostnameHandler("test-shell-resource", "inspector",
&URLRequestTestShellFileJob::InspectorFactory);
url_util::AddStandardScheme("test-shell-resource");
}
TestShell::~TestShell() {
delegate_->RevokeDragDrop();
// DevTools frontend page is supposed to be navigated only once and
// loading another URL in that Page is an error.
if (!dev_tools_client_.get()) {
// Navigate to an empty page to fire all the destruction logic for the
// current page.
LoadURL(GURL("about:blank"));
}
// Call GC twice to clean up garbage.
CallJSGC();
CallJSGC();
// Destroy the WebView before the TestWebViewDelegate.
m_webViewHost.reset();
CloseDevTools();
PlatformCleanUp();
StatsTable *table = StatsTable::current();
if (dump_stats_table_on_exit_) {
// Dump the stats table.
printf("\n");
if (table != NULL) {
int counter_max = table->GetMaxCounters();
for (int index = 0; index < counter_max; index++) {
std::string name(table->GetRowName(index));
if (name.length() > 0) {
int value = table->GetRowValue(index);
printf("%s:\t%d\n", name.c_str(), value);
}
}
}
printf("\n");
}
}
void TestShell::UpdateNavigationControls() {
int current_index = navigation_controller()->GetCurrentEntryIndex();
int max_index = navigation_controller()->GetEntryCount() - 1;
EnableUIControl(BACK_BUTTON, current_index > 0);
EnableUIControl(FORWARD_BUTTON, current_index < max_index);
EnableUIControl(STOP_BUTTON, is_loading_);
}
bool TestShell::CreateNewWindow(const GURL& starting_url,
TestShell** result) {
TestShell* shell = new TestShell();
bool rv = shell->Initialize(starting_url);
if (rv) {
if (result)
*result = shell;
TestShell::windowList()->push_back(shell->m_mainWnd);
}
return rv;
}
void TestShell::ShutdownTestShell() {
PlatformShutdown();
SimpleResourceLoaderBridge::Shutdown();
delete window_list_;
delete TestShell::web_prefs_;
}
// All fatal log messages (e.g. DCHECK failures) imply unit test failures
static void UnitTestAssertHandler(const std::string& str) {
FAIL() << str;
}
// static
void TestShell::Dump(TestShell* shell) {
const TestParams* params = NULL;
if ((shell == NULL) || ((params = shell->test_params()) == NULL))
return;
WebScriptController::flushConsoleMessages();
// Dump the requested representation.
WebFrame* frame = shell->webView()->mainFrame();
if (frame) {
bool should_dump_as_text =
shell->layout_test_controller_->ShouldDumpAsText();
bool dumped_anything = false;
if (params->dump_tree) {
dumped_anything = true;
// Text output: the test page can request different types of output
// which we handle here.
if (!should_dump_as_text) {
// Plain text pages should be dumped as text
const string16& mime_type =
frame->dataSource()->response().mimeType();
should_dump_as_text = EqualsASCII(mime_type, "text/plain");
}
if (should_dump_as_text) {
bool recursive = shell->layout_test_controller_->
ShouldDumpChildFramesAsText();
std::string data_utf8 = WideToUTF8(
webkit_glue::DumpFramesAsText(frame, recursive));
if (fwrite(data_utf8.c_str(), 1, data_utf8.size(), stdout) !=
data_utf8.size()) {
LOG(FATAL) << "Short write to stdout, disk full?";
}
} else {
printf("%s", WideToUTF8(
webkit_glue::DumpRenderer(frame)).c_str());
bool recursive = shell->layout_test_controller_->
ShouldDumpChildFrameScrollPositions();
printf("%s", WideToUTF8(
webkit_glue::DumpFrameScrollPosition(frame, recursive)).c_str());
}
if (shell->layout_test_controller_->ShouldDumpBackForwardList()) {
std::wstring bfDump;
DumpAllBackForwardLists(&bfDump);
printf("%s", WideToUTF8(bfDump).c_str());
}
}
if (params->dump_pixels && !should_dump_as_text) {
// Image output: we write the image data to the file given on the
// command line (for the dump pixels argument), and the MD5 sum to
// stdout.
dumped_anything = true;
WebViewHost* view_host = shell->webViewHost();
view_host->webview()->layout();
if (shell->layout_test_controller()->test_repaint()) {
WebSize view_size = view_host->webview()->size();
int width = view_size.width;
int height = view_size.height;
if (shell->layout_test_controller()->sweep_horizontally()) {
for (gfx::Rect column(0, 0, 1, height); column.x() < width;
column.Offset(1, 0)) {
view_host->PaintRect(column);
}
} else {
for (gfx::Rect line(0, 0, width, 1); line.y() < height;
line.Offset(0, 1)) {
view_host->PaintRect(line);
}
}
} else {
view_host->Paint();
}
// See if we need to draw the selection bounds rect. Selection bounds
// rect is the rect enclosing the (possibly transformed) selection.
// The rect should be drawn after everything is laid out and painted.
if (shell->layout_test_controller_->ShouldDumpSelectionRect()) {
// If there is a selection rect - draw a red 1px border enclosing rect
WebRect wr = frame->selectionBoundsRect();
if (!wr.isEmpty()) {
// Render a red rectangle bounding selection rect
SkPaint paint;
paint.setColor(0xFFFF0000); // Fully opaque red
paint.setStyle(SkPaint::kStroke_Style);
paint.setFlags(SkPaint::kAntiAlias_Flag);
paint.setStrokeWidth(1.0f);
SkIRect rect; // Bounding rect
rect.set(wr.x, wr.y, wr.x + wr.width, wr.y + wr.height);
view_host->canvas()->drawIRect(rect, paint);
}
}
std::string md5sum = DumpImage(view_host->canvas(),
params->pixel_file_name, params->pixel_hash);
printf("#MD5:%s\n", md5sum.c_str());
}
if (dumped_anything)
printf("#EOF\n");
fflush(stdout);
}
}
// static
std::string TestShell::DumpImage(skia::PlatformCanvas* canvas,
const std::wstring& file_name, const std::string& pixel_hash) {
skia::BitmapPlatformDevice& device =
static_cast(canvas->getTopPlatformDevice());
const SkBitmap& src_bmp = device.accessBitmap(false);
// Encode image.
std::vector png;
SkAutoLockPixels src_bmp_lock(src_bmp);
gfx::PNGCodec::ColorFormat color_format = gfx::PNGCodec::FORMAT_BGRA;
// Fix the alpha. The expected PNGs on Mac have an alpha channel, so we want
// to keep it. On Windows, the alpha channel is wrong since text/form control
// drawing may have erased it in a few places. So on Windows we force it to
// opaque and also don't write the alpha channel for the reference. Linux
// doesn't have the wrong alpha like Windows, but we ignore it anyway.
#if defined(OS_WIN)
bool discard_transparency = true;
device.makeOpaque(0, 0, src_bmp.width(), src_bmp.height());
#elif defined(OS_MACOSX)
bool discard_transparency = false;
#elif defined(OS_POSIX)
bool discard_transparency = true;
#endif
// Compute MD5 sum. We should have done this before calling
// device.makeOpaque on Windows. Because we do it after the call, there are
// some images that are the pixel identical on windows and other platforms
// but have different MD5 sums. At this point, rebaselining all the windows
// tests is too much of a pain, so we just check in different baselines.
MD5Context ctx;
MD5Init(&ctx);
MD5Update(&ctx, src_bmp.getPixels(), src_bmp.getSize());
MD5Digest digest;
MD5Final(&digest, &ctx);
std::string md5hash = MD5DigestToBase16(digest);
// Only encode and dump the png if the hashes don't match. Encoding the image
// is really expensive.
if (md5hash.compare(pixel_hash) != 0) {
gfx::PNGCodec::Encode(
reinterpret_cast(src_bmp.getPixels()),
color_format, src_bmp.width(), src_bmp.height(),
static_cast(src_bmp.rowBytes()), discard_transparency, &png);
// Write to disk.
file_util::WriteFile(file_name, reinterpret_cast(&png[0]),
png.size());
}
return md5hash;
}
// static
void TestShell::InitLogging(bool suppress_error_dialogs,
bool layout_test_mode,
bool enable_gp_fault_error_box) {
if (suppress_error_dialogs)
logging::SetLogAssertHandler(UnitTestAssertHandler);
#if defined(OS_WIN)
if (!IsDebuggerPresent()) {
UINT new_flags = SEM_FAILCRITICALERRORS |
SEM_NOOPENFILEERRORBOX;
if (!enable_gp_fault_error_box)
new_flags |= SEM_NOGPFAULTERRORBOX;
// Preserve existing error mode, as discussed at
// http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx
UINT existing_flags = SetErrorMode(new_flags);
SetErrorMode(existing_flags | new_flags);
}
#endif
// Only log to a file if we're running layout tests. This prevents debugging
// output from disrupting whether or not we pass.
logging::LoggingDestination destination =
logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG;
if (layout_test_mode)
destination = logging::LOG_ONLY_TO_FILE;
// We might have multiple test_shell processes going at once
FilePath log_filename;
PathService::Get(base::DIR_EXE, &log_filename);
log_filename = log_filename.AppendASCII("test_shell.log");
logging::InitLogging(log_filename.value().c_str(),
destination,
logging::LOCK_LOG_FILE,
logging::DELETE_OLD_LOG_FILE);
// we want process and thread IDs because we may have multiple processes
logging::SetLogItems(true, true, false, true);
// Turn on logging of notImplemented()s inside WebKit, but only if we're
// not running layout tests (because otherwise they'd corrupt the test
// output).
if (!layout_test_mode)
webkit_glue::EnableWebCoreNotImplementedLogging();
}
// static
void TestShell::CleanupLogging() {
logging::CloseLogFile();
}
// static
void TestShell::SetAllowScriptsToCloseWindows() {
if (web_prefs_)
web_prefs_->allow_scripts_to_close_windows = true;
}
// static
void TestShell::ResetWebPreferences() {
DCHECK(web_prefs_);
// Match the settings used by Mac DumpRenderTree, with the exception of
// fonts.
if (web_prefs_) {
*web_prefs_ = WebPreferences();
#if defined(OS_MACOSX)
web_prefs_->serif_font_family = L"Times";
web_prefs_->cursive_font_family = L"Apple Chancery";
web_prefs_->fantasy_font_family = L"Papyrus";
#else
// NOTE: case matters here, this must be 'times new roman', else
// some layout tests fail.
web_prefs_->serif_font_family = L"times new roman";
// These two fonts are picked from the intersection of
// Win XP font list and Vista font list :
// http://www.microsoft.com/typography/fonts/winxp.htm
// http://blogs.msdn.com/michkap/archive/2006/04/04/567881.aspx
// Some of them are installed only with CJK and complex script
// support enabled on Windows XP and are out of consideration here.
// (although we enabled both on our buildbots.)
// They (especially Impact for fantasy) are not typical cursive
// and fantasy fonts, but it should not matter for layout tests
// as long as they're available.
web_prefs_->cursive_font_family = L"Comic Sans MS";
web_prefs_->fantasy_font_family = L"Impact";
#endif
web_prefs_->standard_font_family = web_prefs_->serif_font_family;
web_prefs_->fixed_font_family = L"Courier";
web_prefs_->sans_serif_font_family = L"Helvetica";
web_prefs_->default_encoding = "ISO-8859-1";
web_prefs_->default_font_size = 16;
web_prefs_->default_fixed_font_size = 13;
web_prefs_->minimum_font_size = 1;
web_prefs_->minimum_logical_font_size = 9;
web_prefs_->javascript_can_open_windows_automatically = true;
web_prefs_->dom_paste_enabled = true;
web_prefs_->developer_extras_enabled = !layout_test_mode_ ||
developer_extras_enabled_;
web_prefs_->site_specific_quirks_enabled = true;
web_prefs_->shrinks_standalone_images_to_fit = false;
web_prefs_->uses_universal_detector = false;
web_prefs_->text_areas_are_resizable = false;
web_prefs_->java_enabled = false;
web_prefs_->allow_scripts_to_close_windows = false;
web_prefs_->javascript_can_access_clipboard = true;
web_prefs_->xss_auditor_enabled = false;
// It's off by default for Chrome, but we don't want to
// lose the coverage of dynamic font tests in webkit test.
web_prefs_->remote_fonts_enabled = true;
web_prefs_->local_storage_enabled = true;
web_prefs_->application_cache_enabled = true;
web_prefs_->databases_enabled = true;
web_prefs_->allow_file_access_from_file_urls = true;
// LayoutTests were written with Safari Mac in mind which does not allow
// tabbing to links by default.
web_prefs_->tabs_to_links = false;
// Allow those layout tests running as local files, i.e. under
// LayoutTests/http/tests/local, to access http server.
if (layout_test_mode_)
web_prefs_->allow_universal_access_from_file_urls = true;
}
}
// static
bool TestShell::RemoveWindowFromList(gfx::NativeWindow window) {
WindowList::iterator entry =
std::find(TestShell::windowList()->begin(),
TestShell::windowList()->end(),
window);
if (entry != TestShell::windowList()->end()) {
TestShell::windowList()->erase(entry);
return true;
}
return false;
}
void TestShell::TestTimedOut() {
puts("#TEST_TIMED_OUT\n");
TestFinished();
}
void TestShell::Show(WebNavigationPolicy policy) {
delegate_->show(policy);
}
void TestShell::BindJSObjectsToWindow(WebFrame* frame) {
// Only bind the test classes if we're running tests.
if (layout_test_mode_) {
accessibility_controller_->BindToJavascript(
frame, L"accessibilityController");
layout_test_controller_->BindToJavascript(frame, L"layoutTestController");
event_sending_controller_->BindToJavascript(frame, L"eventSender");
plain_text_controller_->BindToJavascript(frame, L"plainText");
text_input_controller_->BindToJavascript(frame, L"textInputController");
}
}
void TestShell::DumpBackForwardEntry(int index, std::wstring* result) {
int current_index = navigation_controller_->GetLastCommittedEntryIndex();
std::string content_state =
navigation_controller_->GetEntryAtIndex(index)->GetContentState();
if (content_state.empty()) {
content_state = webkit_glue::CreateHistoryStateForURL(
navigation_controller_->GetEntryAtIndex(index)->GetURL());
}
result->append(
webkit_glue::DumpHistoryState(content_state, 8, index == current_index));
}
void TestShell::DumpBackForwardList(std::wstring* result) {
result->append(L"\n============== Back Forward List ==============\n");
for (int i = 0; i < navigation_controller_->GetEntryCount(); ++i)
DumpBackForwardEntry(i, result);
result->append(L"===============================================\n");
}
void TestShell::CallJSGC() {
webView()->mainFrame()->collectGarbage();
}
WebView* TestShell::CreateWebView() {
// If we're running layout tests, only open a new window if the test has
// called layoutTestController.setCanOpenWindows()
if (layout_test_mode_ && !layout_test_controller_->CanOpenWindows())
return NULL;
TestShell* new_win;
if (!CreateNewWindow(GURL(), &new_win))
return NULL;
return new_win->webView();
}
void TestShell::InitializeDevToolsAgent(WebView* webView) {
DCHECK(!dev_tools_agent_.get());
dev_tools_agent_.reset(new TestShellDevToolsAgent(webView));
}
void TestShell::ShowDevTools() {
if (!devtools_shell_) {
FilePath dir_exe;
PathService::Get(base::DIR_EXE, &dir_exe);
FilePath devtools_path =
dir_exe.AppendASCII("resources/inspector/devtools.html");
TestShell* devtools_shell;
TestShell::CreateNewWindow(GURL(devtools_path.value()),
&devtools_shell);
devtools_shell_ = devtools_shell->AsWeakPtr();
devtools_shell_->CreateDevToolsClient(dev_tools_agent_.get());
}
DCHECK(devtools_shell_);
devtools_shell_->Show(WebKit::WebNavigationPolicyNewWindow);
}
void TestShell::CloseDevTools() {
if (devtools_shell_)
devtools_shell_->DestroyWindow(devtools_shell_->mainWnd());
}
void TestShell::CreateDevToolsClient(TestShellDevToolsAgent *agent) {
dev_tools_client_.reset(new TestShellDevToolsClient(agent,
webView()));
}
bool TestShell::IsSVGTestURL(const GURL& url) {
return url.is_valid() && url.spec().find("W3C-SVG-1.1") != std::string::npos;
}
void TestShell::SizeToSVG() {
SizeTo(kSVGTestWindowWidth, kSVGTestWindowHeight);
}
void TestShell::SizeToDefault() {
SizeTo(kTestWindowWidth, kTestWindowHeight);
}
void TestShell::ResetTestController() {
accessibility_controller_->Reset();
layout_test_controller_->Reset();
event_sending_controller_->Reset();
notification_presenter_->Reset();
delegate_->Reset();
}
void TestShell::LoadFile(const FilePath& file) {
LoadURLForFrame(net::FilePathToFileURL(file), std::wstring());
}
void TestShell::LoadURL(const GURL& url) {
// Used as a sentinal for run_webkit_tests.py to know when to start reading
// test output for this test and so we know we're not getting out of sync.
if (layout_test_mode_ && test_params())
printf("#URL:%s\n", test_params()->test_url.c_str());
LoadURLForFrame(url, std::wstring());
}
bool TestShell::Navigate(const TestNavigationEntry& entry, bool reload) {
// Get the right target frame for the entry.
WebFrame* frame = webView()->mainFrame();
if (!entry.GetTargetFrame().empty()) {
frame = webView()->findFrameByName(
WideToUTF16Hack(entry.GetTargetFrame()));
}
// TODO(mpcomplete): should we clear the target frame, or should
// back/forward navigations maintain the target frame?
// A navigation resulting from loading a javascript URL should not be
// treated as a browser initiated event. Instead, we want it to look as if
// the page initiated any load resulting from JS execution.
if (!entry.GetURL().SchemeIs("javascript")) {
delegate_->set_pending_extra_data(
new TestShellExtraData(entry.GetPageID()));
}
// If we are reloading, then WebKit will use the state of the current page.
// Otherwise, we give it the state to navigate to.
if (reload) {
frame->reload(false);
} else if (!entry.GetContentState().empty()) {
DCHECK_NE(entry.GetPageID(), -1);
frame->loadHistoryItem(
webkit_glue::HistoryItemFromString(entry.GetContentState()));
} else {
DCHECK_EQ(entry.GetPageID(), -1);
frame->loadRequest(WebURLRequest(entry.GetURL()));
}
// In case LoadRequest failed before DidCreateDataSource was called.
delegate_->set_pending_extra_data(NULL);
// Restore focus to the main frame prior to loading new request.
// This makes sure that we don't have a focused iframe. Otherwise, that
// iframe would keep focus when the SetFocus called immediately after
// LoadRequest, thus making some tests fail (see http://b/issue?id=845337
// for more details).
webView()->setFocusedFrame(frame);
SetFocus(webViewHost(), true);
return true;
}
void TestShell::GoBackOrForward(int offset) {
navigation_controller_->GoToOffset(offset);
}
void TestShell::DumpDocumentText() {
std::wstring file_path;
if (!PromptForSaveFile(L"Dump document text", &file_path))
return;
const std::string data =
WideToUTF8(webkit_glue::DumpDocumentText(webView()->mainFrame()));
file_util::WriteFile(file_path, data.c_str(), data.length());
}
void TestShell::DumpRenderTree() {
std::wstring file_path;
if (!PromptForSaveFile(L"Dump render tree", &file_path))
return;
const std::string data =
WideToUTF8(webkit_glue::DumpRenderer(webView()->mainFrame()));
file_util::WriteFile(file_path, data.c_str(), data.length());
}
std::wstring TestShell::GetDocumentText() {
return webkit_glue::DumpDocumentText(webView()->mainFrame());
}
void TestShell::Reload() {
navigation_controller_->Reload();
}
void TestShell::SetFocus(WebWidgetHost* host, bool enable) {
if (!layout_test_mode_) {
InteractiveSetFocus(host, enable);
} else {
// Simulate the effects of InteractiveSetFocus(), which includes calling
// both setFocus() and setIsActive().
if (enable) {
if (m_focusedWidgetHost != host) {
if (m_focusedWidgetHost)
m_focusedWidgetHost->webwidget()->setFocus(false);
webView()->setIsActive(enable);
host->webwidget()->setFocus(enable);
m_focusedWidgetHost = host;
}
} else {
if (m_focusedWidgetHost == host) {
host->webwidget()->setFocus(enable);
webView()->setIsActive(enable);
m_focusedWidgetHost = NULL;
}
}
}
}
//-----------------------------------------------------------------------------
namespace webkit_glue {
void PrecacheUrl(const char16* url, int url_length) {}
void AppendToLog(const char* file, int line, const char* msg) {
logging::LogMessage(file, line).stream() << msg;
}
bool GetApplicationDirectory(FilePath* path) {
return PathService::Get(base::DIR_EXE, path);
}
bool GetExeDirectory(FilePath* path) {
return GetApplicationDirectory(path);
}
bool IsPluginRunningInRendererProcess() {
return true;
}
bool GetPluginFinderURL(std::string* plugin_finder_url) {
return false;
}
bool IsDefaultPluginEnabled() {
#if defined(OS_WIN)
FilePath exe_path;
if (PathService::Get(base::FILE_EXE, &exe_path)) {
std::wstring exe_name = file_util::GetFilenameFromPath(
exe_path.ToWStringHack());
if (StartsWith(exe_name, L"test_shell_tests", false))
return true;
}
#endif // OS_WIN
return false;
}
bool IsProtocolSupportedForMedia(const GURL& url) {
if (url.SchemeIsFile() ||
url.SchemeIs("http") ||
url.SchemeIs("https") ||
url.SchemeIs("data"))
return true;
return false;
}
std::wstring GetWebKitLocale() {
return L"en-US";
}
void CloseCurrentConnections() {
// Used in benchmarking, Ignored for test_shell.
}
void SetCacheMode(bool enabled) {
// Used in benchmarking, Ignored for test_shell.
}
std::string GetProductVersion() {
return std::string("Chrome/0.0.0.0");
}
} // namespace webkit_glue