| // Copyright (c) 2011 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. |
| |
| #include "webkit/tools/test_shell/test_shell.h" |
| |
| #include <windows.h> |
| #include <commdlg.h> |
| #include <objbase.h> |
| #include <process.h> |
| #include <shlwapi.h> |
| |
| #include "base/command_line.h" |
| #include "base/debug/trace_event.h" |
| #include "base/file_util.h" |
| #include "base/memory/memory_debug.h" |
| #include "base/message_loop.h" |
| #include "base/path_service.h" |
| #include "base/resource_util.h" |
| #include "base/stack_container.h" |
| #include "base/string_piece.h" |
| #include "base/string_util.h" |
| #include "base/utf_string_conversions.h" |
| #include "breakpad/src/client/windows/handler/exception_handler.h" |
| #include "grit/webkit_resources.h" |
| #include "grit/webkit_chromium_resources.h" |
| #include "net/base/net_module.h" |
| #include "net/url_request/url_request_file_job.h" |
| #include "skia/ext/bitmap_platform_device.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" |
| #include "ui/base/win/hwnd_util.h" |
| #include "webkit/glue/webkit_glue.h" |
| #include "webkit/glue/webpreferences.h" |
| #include "webkit/glue/plugins/plugin_list.h" |
| #include "webkit/tools/test_shell/resource.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_switches.h" |
| #include "webkit/tools/test_shell/test_webview_delegate.h" |
| |
| using WebKit::WebWidget; |
| |
| #define MAX_LOADSTRING 100 |
| |
| #define BUTTON_WIDTH 72 |
| #define URLBAR_HEIGHT 24 |
| |
| // Global Variables: |
| static wchar_t g_windowTitle[MAX_LOADSTRING]; // The title bar text |
| static wchar_t g_windowClass[MAX_LOADSTRING]; // The main window class name |
| |
| // This is only set for layout tests. It is used to determine the name of a |
| // minidump file. |
| static const size_t kPathBufSize = 2048; |
| static wchar_t g_currentTestName[kPathBufSize]; |
| |
| // Forward declarations of functions included in this code module: |
| static INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); |
| |
| // Hide the window offscreen when in layout test mode. |
| // This would correspond with a minimized window position if x = y = -32000. |
| // However we shift the x to 0 to pass test cross-frame-access-put.html |
| // which expects screenX/screenLeft to be 0 (http://b/issue?id=1227945). |
| // TODO(ericroman): x should be defined as 0 rather than -4. There is |
| // probably a frameborder not being accounted for in the setting/getting. |
| const int kTestWindowXLocation = -4; |
| const int kTestWindowYLocation = -32000; |
| |
| namespace { |
| |
| // This method is used to keep track of the current test name so when we write |
| // a minidump file, we have the test name in the minidump filename. |
| void SetCurrentTestName(const char* path) { |
| const char* lastSlash = strrchr(path, '/'); |
| if (lastSlash) { |
| ++lastSlash; |
| } else { |
| lastSlash = path; |
| } |
| |
| base::wcslcpy(g_currentTestName, |
| UTF8ToWide(lastSlash).c_str(), |
| arraysize(g_currentTestName)); |
| } |
| |
| bool MinidumpCallback(const wchar_t *dumpPath, |
| const wchar_t *minidumpID, |
| void *context, |
| EXCEPTION_POINTERS *exinfo, |
| MDRawAssertionInfo *assertion, |
| bool succeeded) { |
| // Warning: Don't use the heap in this function. It may be corrupted. |
| if (!g_currentTestName[0]) |
| return false; |
| |
| // Try to rename the minidump file to include the crashed test's name. |
| // StackString uses the stack but overflows onto the heap. But we don't |
| // care too much about being completely correct here, since most crashes |
| // will be happening on developers' machines where they have debuggers. |
| StackWString<kPathBufSize * 2> origPath; |
| origPath->append(dumpPath); |
| origPath->push_back(FilePath::kSeparators[0]); |
| origPath->append(minidumpID); |
| origPath->append(L".dmp"); |
| |
| StackWString<kPathBufSize * 2> newPath; |
| newPath->append(dumpPath); |
| newPath->push_back(FilePath::kSeparators[0]); |
| newPath->append(g_currentTestName); |
| newPath->append(L"-"); |
| newPath->append(minidumpID); |
| newPath->append(L".dmp"); |
| |
| // May use the heap, but oh well. If this fails, we'll just have the |
| // original dump file lying around. |
| _wrename(origPath->c_str(), newPath->c_str()); |
| |
| return false; |
| } |
| |
| // Helper method for getting the path to the test shell resources directory. |
| FilePath GetResourcesFilePath() { |
| FilePath path; |
| PathService::Get(base::DIR_SOURCE_ROOT, &path); |
| path = path.AppendASCII("webkit"); |
| path = path.AppendASCII("tools"); |
| path = path.AppendASCII("test_shell"); |
| return path.AppendASCII("resources"); |
| } |
| |
| static base::StringPiece GetRawDataResource(HMODULE module, int resource_id) { |
| void* data_ptr; |
| size_t data_size; |
| return base::GetDataResourceFromModule(module, resource_id, &data_ptr, |
| &data_size) |
| ? base::StringPiece(static_cast<char*>(data_ptr), data_size) |
| : base::StringPiece(); |
| } |
| |
| } // namespace |
| |
| // Initialize static member variable |
| HINSTANCE TestShell::instance_handle_; |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // static methods on TestShell |
| |
| const MINIDUMP_TYPE kFullDumpType = static_cast<MINIDUMP_TYPE>( |
| MiniDumpWithFullMemory | // Full memory from process. |
| MiniDumpWithProcessThreadData | // Get PEB and TEB. |
| MiniDumpWithHandleData); // Get all handle information. |
| |
| void TestShell::InitializeTestShell(bool layout_test_mode, |
| bool allow_external_pages) { |
| // Start COM stuff. |
| HRESULT res = OleInitialize(NULL); |
| DCHECK(SUCCEEDED(res)); |
| |
| window_list_ = new WindowList; |
| instance_handle_ = ::GetModuleHandle(NULL); |
| layout_test_mode_ = layout_test_mode; |
| allow_external_pages_ = allow_external_pages; |
| |
| web_prefs_ = new WebPreferences; |
| |
| ResetWebPreferences(); |
| |
| // Register the Ahem font used by layout tests. |
| DWORD num_fonts = 1; |
| void* font_ptr; |
| size_t font_size; |
| if (base::GetDataResourceFromModule(::GetModuleHandle(NULL), IDR_AHEM_FONT, |
| &font_ptr, &font_size)) { |
| HANDLE rc = AddFontMemResourceEx(font_ptr, font_size, 0, &num_fonts); |
| DCHECK(rc != 0); |
| } |
| |
| const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); |
| if (parsed_command_line.HasSwitch(test_shell::kCrashDumps)) { |
| std::wstring dir( |
| parsed_command_line.GetSwitchValueNative(test_shell::kCrashDumps)); |
| if (parsed_command_line.HasSwitch(test_shell::kCrashDumpsFulldump)) { |
| new google_breakpad::ExceptionHandler( |
| dir, 0, &MinidumpCallback, 0, true, |
| kFullDumpType, 0, 0); |
| } else { |
| new google_breakpad::ExceptionHandler( |
| dir, 0, &MinidumpCallback, 0, true); |
| } |
| } |
| } |
| |
| void TestShell::DestroyWindow(gfx::NativeWindow windowHandle) { |
| // Do we want to tear down some of the machinery behind the scenes too? |
| RemoveWindowFromList(windowHandle); |
| ::DestroyWindow(windowHandle); |
| } |
| |
| void TestShell::PlatformShutdown() { |
| OleUninitialize(); |
| } |
| |
| ATOM TestShell::RegisterWindowClass() { |
| LoadString(instance_handle_, IDS_APP_TITLE, g_windowTitle, MAX_LOADSTRING); |
| LoadString(instance_handle_, IDC_TESTSHELL, g_windowClass, MAX_LOADSTRING); |
| |
| WNDCLASSEX wcex = { |
| sizeof(WNDCLASSEX), |
| CS_HREDRAW | CS_VREDRAW, |
| TestShell::WndProc, |
| 0, |
| 0, |
| instance_handle_, |
| LoadIcon(instance_handle_, MAKEINTRESOURCE(IDI_TESTSHELL)), |
| LoadCursor(NULL, IDC_ARROW), |
| 0, |
| MAKEINTRESOURCE(IDC_TESTSHELL), |
| g_windowClass, |
| LoadIcon(instance_handle_, MAKEINTRESOURCE(IDI_SMALL)), |
| }; |
| return RegisterClassEx(&wcex); |
| } |
| |
| void TestShell::DumpAllBackForwardLists(string16* result) { |
| result->clear(); |
| for (WindowList::iterator iter = TestShell::windowList()->begin(); |
| iter != TestShell::windowList()->end(); iter++) { |
| HWND hwnd = *iter; |
| TestShell* shell = |
| static_cast<TestShell*>(ui::GetWindowUserData(hwnd)); |
| shell->DumpBackForwardList(result); |
| } |
| } |
| |
| std::string TestShell::RewriteLocalUrl(const std::string& url) { |
| // Convert file:///tmp/LayoutTests urls to the actual location on disk. |
| const char kPrefix[] = "file:///tmp/LayoutTests/"; |
| const int kPrefixLen = arraysize(kPrefix) - 1; |
| |
| std::string new_url(url); |
| if (url.compare(0, kPrefixLen, kPrefix, kPrefixLen) == 0) { |
| FilePath replace_url; |
| PathService::Get(base::DIR_EXE, &replace_url); |
| replace_url = replace_url.DirName(); |
| replace_url = replace_url.DirName(); |
| replace_url = replace_url.AppendASCII("third_party"); |
| replace_url = replace_url.AppendASCII("WebKit"); |
| replace_url = replace_url.AppendASCII("LayoutTests"); |
| std::wstring replace_url_str = replace_url.value(); |
| replace_url_str.push_back(L'/'); |
| new_url = std::string("file:///") + |
| WideToUTF8(replace_url_str).append(url.substr(kPrefixLen)); |
| } |
| return new_url; |
| } |
| |
| |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // TestShell implementation |
| |
| void TestShell::PlatformCleanUp() { |
| // When the window is destroyed, tell the Edit field to forget about us, |
| // otherwise we will crash. |
| ui::SetWindowProc(m_editWnd, default_edit_wnd_proc_); |
| ui::SetWindowUserData(m_editWnd, NULL); |
| } |
| |
| void TestShell::EnableUIControl(UIControl control, bool is_enabled) { |
| int id; |
| switch (control) { |
| case BACK_BUTTON: |
| id = IDC_NAV_BACK; |
| break; |
| case FORWARD_BUTTON: |
| id = IDC_NAV_FORWARD; |
| break; |
| case STOP_BUTTON: |
| id = IDC_NAV_STOP; |
| break; |
| default: |
| NOTREACHED() << "Unknown UI control"; |
| return; |
| } |
| EnableWindow(GetDlgItem(m_mainWnd, id), is_enabled); |
| } |
| |
| bool TestShell::Initialize(const GURL& starting_url) { |
| // Perform application initialization: |
| m_mainWnd = CreateWindow(g_windowClass, g_windowTitle, |
| WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, |
| CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, |
| NULL, NULL, instance_handle_, NULL); |
| ui::SetWindowUserData(m_mainWnd, this); |
| |
| HWND hwnd; |
| int x = 0; |
| |
| hwnd = CreateWindow(L"BUTTON", L"Back", |
| WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON , |
| x, 0, BUTTON_WIDTH, URLBAR_HEIGHT, |
| m_mainWnd, (HMENU) IDC_NAV_BACK, instance_handle_, 0); |
| x += BUTTON_WIDTH; |
| |
| hwnd = CreateWindow(L"BUTTON", L"Forward", |
| WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON , |
| x, 0, BUTTON_WIDTH, URLBAR_HEIGHT, |
| m_mainWnd, (HMENU) IDC_NAV_FORWARD, instance_handle_, 0); |
| x += BUTTON_WIDTH; |
| |
| hwnd = CreateWindow(L"BUTTON", L"Reload", |
| WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON , |
| x, 0, BUTTON_WIDTH, URLBAR_HEIGHT, |
| m_mainWnd, (HMENU) IDC_NAV_RELOAD, instance_handle_, 0); |
| x += BUTTON_WIDTH; |
| |
| hwnd = CreateWindow(L"BUTTON", L"Stop", |
| WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON , |
| x, 0, BUTTON_WIDTH, URLBAR_HEIGHT, |
| m_mainWnd, (HMENU) IDC_NAV_STOP, instance_handle_, 0); |
| x += BUTTON_WIDTH; |
| |
| // this control is positioned by ResizeSubViews |
| m_editWnd = CreateWindow(L"EDIT", 0, |
| WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | |
| ES_AUTOVSCROLL | ES_AUTOHSCROLL, |
| x, 0, 0, 0, m_mainWnd, 0, instance_handle_, 0); |
| |
| default_edit_wnd_proc_ = ui::SetWindowProc(m_editWnd, TestShell::EditWndProc); |
| ui::SetWindowUserData(m_editWnd, this); |
| |
| dev_tools_agent_.reset(new TestShellDevToolsAgent()); |
| |
| // create webview |
| m_webViewHost.reset( |
| WebViewHost::Create(m_mainWnd, |
| delegate_.get(), |
| dev_tools_agent_.get(), |
| *TestShell::web_prefs_)); |
| dev_tools_agent_->SetWebView(m_webViewHost->webview()); |
| delegate_->RegisterDragDrop(); |
| |
| // Load our initial content. |
| if (starting_url.is_valid()) |
| LoadURL(starting_url); |
| |
| ShowWindow(webViewWnd(), SW_SHOW); |
| |
| if (IsSVGTestURL(starting_url)) { |
| SizeToSVG(); |
| } else { |
| SizeToDefault(); |
| } |
| |
| return true; |
| } |
| |
| void TestShell::TestFinished() { |
| if (!test_is_pending_) |
| return; // reached when running under test_shell_tests |
| |
| test_is_pending_ = false; |
| |
| UINT_PTR timer_id = reinterpret_cast<UINT_PTR>(this); |
| KillTimer(mainWnd(), timer_id); |
| |
| MessageLoop::current()->Quit(); |
| } |
| |
| // Thread main to run for the thread which just tests for timeout. |
| unsigned int __stdcall WatchDogThread(void *arg) { |
| // If we're debugging a layout test, don't timeout. |
| if (::IsDebuggerPresent()) |
| return 0; |
| |
| TestShell* shell = static_cast<TestShell*>(arg); |
| DWORD timeout = static_cast<DWORD>(shell->GetLayoutTestTimeoutForWatchDog()); |
| DWORD rv = WaitForSingleObject(shell->finished_event(), timeout); |
| if (rv == WAIT_TIMEOUT) { |
| // Print a warning to be caught by the layout-test script. |
| // Note: the layout test driver may or may not recognize |
| // this as a timeout. |
| puts("#TEST_TIMED_OUT\n"); |
| puts("#EOF\n"); |
| fflush(stdout); |
| TerminateProcess(GetCurrentProcess(), 0); |
| } |
| // Finished normally. |
| return 0; |
| } |
| |
| void TestShell::WaitTestFinished() { |
| DCHECK(!test_is_pending_) << "cannot be used recursively"; |
| |
| test_is_pending_ = true; |
| |
| // Create a watchdog thread which just sets a timer and |
| // kills the process if it times out. This catches really |
| // bad hangs where the shell isn't coming back to the |
| // message loop. If the watchdog is what catches a |
| // timeout, it can't do anything except terminate the test |
| // shell, which is unfortunate. |
| finished_event_ = CreateEvent(NULL, TRUE, FALSE, NULL); |
| DCHECK(finished_event_ != NULL); |
| |
| HANDLE thread_handle = reinterpret_cast<HANDLE>(_beginthreadex( |
| NULL, |
| 0, |
| &WatchDogThread, |
| this, |
| 0, |
| 0)); |
| DCHECK(thread_handle != NULL); |
| |
| // TestFinished() will post a quit message to break this loop when the page |
| // finishes loading. |
| while (test_is_pending_) |
| MessageLoop::current()->Run(); |
| |
| // Tell the watchdog that we are finished. |
| SetEvent(finished_event_); |
| |
| // Wait to join the watchdog thread. (up to 1s, then quit) |
| WaitForSingleObject(thread_handle, 1000); |
| } |
| |
| void TestShell::InteractiveSetFocus(WebWidgetHost* host, bool enable) { |
| if (!enable && ::GetFocus() == host->view_handle()) |
| ::SetFocus(NULL); |
| } |
| |
| WebWidget* TestShell::CreatePopupWidget() { |
| DCHECK(!m_popupHost); |
| m_popupHost = WebWidgetHost::Create(NULL, popup_delegate_.get()); |
| ShowWindow(popupWnd(), SW_SHOW); |
| |
| return m_popupHost->webwidget(); |
| } |
| |
| void TestShell::ClosePopup() { |
| PostMessage(popupWnd(), WM_CLOSE, 0, 0); |
| m_popupHost = NULL; |
| } |
| |
| void TestShell::SizeTo(int width, int height) { |
| RECT rc, rw; |
| GetClientRect(m_mainWnd, &rc); |
| GetWindowRect(m_mainWnd, &rw); |
| |
| int client_width = rc.right - rc.left; |
| int window_width = rw.right - rw.left; |
| window_width = (window_width - client_width) + width; |
| |
| int client_height = rc.bottom - rc.top; |
| int window_height = rw.bottom - rw.top; |
| window_height = (window_height - client_height) + height; |
| |
| // add space for the url bar: |
| window_height += URLBAR_HEIGHT; |
| |
| SetWindowPos(m_mainWnd, NULL, 0, 0, window_width, window_height, |
| SWP_NOMOVE | SWP_NOZORDER); |
| } |
| |
| void TestShell::ResizeSubViews() { |
| RECT rc; |
| GetClientRect(m_mainWnd, &rc); |
| |
| int x = BUTTON_WIDTH * 4; |
| MoveWindow(m_editWnd, x, 0, rc.right - x, URLBAR_HEIGHT, TRUE); |
| |
| MoveWindow(webViewWnd(), 0, URLBAR_HEIGHT, rc.right, |
| rc.bottom - URLBAR_HEIGHT, TRUE); |
| } |
| |
| void TestShell::LoadURLForFrame(const GURL& url, |
| const std::wstring& frame_name) { |
| if (!url.is_valid()) |
| return; |
| |
| TRACE_EVENT_BEGIN("url.load", this, url.spec()); |
| |
| if (IsSVGTestURL(url)) { |
| SizeToSVG(); |
| } else { |
| // only resize back to the default when running tests |
| if (layout_test_mode()) |
| SizeToDefault(); |
| } |
| |
| navigation_controller_->LoadEntry( |
| new TestNavigationEntry(-1, url, std::wstring(), frame_name)); |
| } |
| |
| LRESULT CALLBACK TestShell::WndProc(HWND hwnd, UINT message, WPARAM wParam, |
| LPARAM lParam) { |
| TestShell* shell = static_cast<TestShell*>(ui::GetWindowUserData(hwnd)); |
| |
| switch (message) { |
| case WM_COMMAND: |
| { |
| int wmId = LOWORD(wParam); |
| int wmEvent = HIWORD(wParam); |
| |
| switch (wmId) { |
| case IDM_ABOUT: |
| DialogBox(shell->instance_handle_, MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd, |
| About); |
| break; |
| case IDM_EXIT: |
| DestroyWindow(hwnd); |
| break; |
| case IDC_NAV_BACK: |
| shell->GoBackOrForward(-1); |
| break; |
| case IDC_NAV_FORWARD: |
| shell->GoBackOrForward(1); |
| break; |
| case IDC_NAV_RELOAD: |
| case IDC_NAV_STOP: |
| { |
| if (wmId == IDC_NAV_RELOAD) { |
| shell->Reload(); |
| } else { |
| shell->webView()->mainFrame()->stopLoading(); |
| } |
| } |
| break; |
| case IDM_DUMP_BODY_TEXT: |
| shell->DumpDocumentText(); |
| break; |
| case IDM_DUMP_RENDER_TREE: |
| shell->DumpRenderTree(); |
| break; |
| case IDM_ENABLE_IMAGES: |
| case IDM_ENABLE_PLUGINS: |
| case IDM_ENABLE_SCRIPTS: { |
| HMENU menu = GetSubMenu(GetMenu(hwnd), 1); |
| bool was_checked = |
| (GetMenuState(menu, wmId, MF_BYCOMMAND) & MF_CHECKED) != 0; |
| CheckMenuItem(menu, wmId, |
| MF_BYCOMMAND | (was_checked ? MF_UNCHECKED : MF_CHECKED)); |
| switch (wmId) { |
| case IDM_ENABLE_IMAGES: |
| shell->set_allow_images(!was_checked); |
| break; |
| case IDM_ENABLE_PLUGINS: |
| shell->set_allow_plugins(!was_checked); |
| break; |
| case IDM_ENABLE_SCRIPTS: |
| shell->set_allow_scripts(!was_checked); |
| break; |
| } |
| break; |
| } |
| case IDM_SHOW_DEV_TOOLS: |
| shell->ShowDevTools(); |
| break; |
| } |
| } |
| break; |
| |
| case WM_DESTROY: |
| { |
| |
| RemoveWindowFromList(hwnd); |
| |
| if (TestShell::windowList()->empty() || shell->is_modal()) { |
| // Dump all in use memory just before shutdown if in use memory |
| // debugging has been enabled. |
| base::MemoryDebug::DumpAllMemoryInUse(); |
| |
| MessageLoop::current()->PostTask(FROM_HERE, |
| new MessageLoop::QuitTask()); |
| } |
| delete shell; |
| } |
| return 0; |
| |
| case WM_SIZE: |
| if (shell->webView()) |
| shell->ResizeSubViews(); |
| return 0; |
| } |
| |
| return DefWindowProc(hwnd, message, wParam, lParam); |
| } |
| |
| |
| #define MAX_URL_LENGTH 1024 |
| |
| LRESULT CALLBACK TestShell::EditWndProc(HWND hwnd, UINT message, |
| WPARAM wParam, LPARAM lParam) { |
| TestShell* shell = |
| static_cast<TestShell*>(ui::GetWindowUserData(hwnd)); |
| |
| switch (message) { |
| case WM_CHAR: |
| if (wParam == VK_RETURN) { |
| wchar_t str[MAX_URL_LENGTH + 1]; // Leave room for adding a NULL; |
| *((LPWORD)str) = MAX_URL_LENGTH; |
| LRESULT str_len = SendMessage(hwnd, EM_GETLINE, 0, (LPARAM)str); |
| if (str_len > 0) { |
| str[str_len] = 0; // EM_GETLINE doesn't NULL terminate. |
| shell->LoadURL(GURL(str)); |
| } |
| |
| return 0; |
| } |
| } |
| |
| return (LRESULT) CallWindowProc(shell->default_edit_wnd_proc_, hwnd, |
| message, wParam, lParam); |
| } |
| |
| |
| // Message handler for about box. |
| INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { |
| UNREFERENCED_PARAMETER(lParam); |
| switch (message) { |
| case WM_INITDIALOG: |
| return (INT_PTR)TRUE; |
| |
| case WM_COMMAND: |
| if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { |
| EndDialog(hDlg, LOWORD(wParam)); |
| return (INT_PTR)TRUE; |
| } |
| break; |
| } |
| return (INT_PTR)FALSE; |
| } |
| |
| bool TestShell::PromptForSaveFile(const wchar_t* prompt_title, |
| FilePath* result) { |
| wchar_t path_buf[MAX_PATH] = L"data.txt"; |
| |
| OPENFILENAME info = {0}; |
| info.lStructSize = sizeof(info); |
| info.hwndOwner = m_mainWnd; |
| info.hInstance = instance_handle_; |
| info.lpstrFilter = L"*.txt"; |
| info.lpstrFile = path_buf; |
| info.nMaxFile = arraysize(path_buf); |
| info.lpstrTitle = prompt_title; |
| if (!GetSaveFileName(&info)) |
| return false; |
| |
| *result = FilePath(info.lpstrFile); |
| return true; |
| } |
| |
| // static |
| void TestShell::ShowStartupDebuggingDialog() { |
| MessageBox(NULL, L"attach to me?", L"test_shell", MB_OK); |
| } |
| |
| // static |
| base::StringPiece TestShell::ResourceProvider(int key) { |
| return GetRawDataResource(::GetModuleHandle(NULL), key); |
| } |
| |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // WebKit glue functions |
| |
| namespace webkit_glue { |
| |
| string16 GetLocalizedString(int message_id) { |
| wchar_t localized[MAX_LOADSTRING]; |
| int length = LoadString(GetModuleHandle(NULL), message_id, |
| localized, MAX_LOADSTRING); |
| if (!length && GetLastError() == ERROR_RESOURCE_NAME_NOT_FOUND) { |
| NOTREACHED(); |
| return L"No string for this identifier!"; |
| } |
| return string16(localized, length); |
| } |
| |
| // TODO(tc): Convert this to using resources from test_shell.rc. |
| base::StringPiece GetDataResource(int resource_id) { |
| switch (resource_id) { |
| case IDR_BROKENIMAGE: { |
| // Use webkit's broken image icon (16x16) |
| static std::string broken_image_data; |
| if (broken_image_data.empty()) { |
| FilePath path = GetResourcesFilePath(); |
| path = path.AppendASCII("missingImage.gif"); |
| bool success = file_util::ReadFileToString(path, &broken_image_data); |
| if (!success) { |
| LOG(FATAL) << "Failed reading: " << path.value(); |
| } |
| } |
| return broken_image_data; |
| } |
| case IDR_TEXTAREA_RESIZER: { |
| // Use webkit's text area resizer image. |
| static std::string resize_corner_data; |
| if (resize_corner_data.empty()) { |
| FilePath path = GetResourcesFilePath(); |
| path = path.AppendASCII("textAreaResizeCorner.png"); |
| bool success = file_util::ReadFileToString(path, &resize_corner_data); |
| if (!success) { |
| LOG(FATAL) << "Failed reading: " << path.value(); |
| } |
| } |
| return resize_corner_data; |
| } |
| |
| case IDR_SEARCH_CANCEL: |
| case IDR_SEARCH_CANCEL_PRESSED: |
| case IDR_SEARCH_MAGNIFIER: |
| case IDR_SEARCH_MAGNIFIER_RESULTS: |
| case IDR_MEDIA_PAUSE_BUTTON: |
| case IDR_MEDIA_PLAY_BUTTON: |
| case IDR_MEDIA_PLAY_BUTTON_DISABLED: |
| case IDR_MEDIA_SOUND_FULL_BUTTON: |
| case IDR_MEDIA_SOUND_NONE_BUTTON: |
| case IDR_MEDIA_SOUND_DISABLED: |
| case IDR_MEDIA_SLIDER_THUMB: |
| case IDR_MEDIA_VOLUME_SLIDER_THUMB: |
| case IDR_INPUT_SPEECH: |
| case IDR_INPUT_SPEECH_RECORDING: |
| case IDR_INPUT_SPEECH_WAITING: |
| return TestShell::ResourceProvider(resource_id); |
| |
| default: |
| break; |
| } |
| |
| return base::StringPiece(); |
| } |
| |
| HCURSOR LoadCursor(int cursor_id) { |
| return NULL; |
| } |
| |
| bool EnsureFontLoaded(HFONT font) { |
| return true; |
| } |
| |
| bool DownloadUrl(const std::string& url, HWND caller_window) { |
| return false; |
| } |
| |
| } // namespace webkit_glue |