// 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