OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "webkit/tools/test_shell/test_shell.h" | |
6 | |
7 #include <windows.h> | |
8 #include <commdlg.h> | |
9 #include <objbase.h> | |
10 #include <process.h> | |
11 #include <shlwapi.h> | |
12 | |
13 #include "base/command_line.h" | |
14 #include "base/containers/stack_container.h" | |
15 #include "base/debug/trace_event.h" | |
16 #include "base/file_util.h" | |
17 #include "base/message_loop.h" | |
18 #include "base/path_service.h" | |
19 #include "base/string_util.h" | |
20 #include "base/strings/string_piece.h" | |
21 #include "base/utf_string_conversions.h" | |
22 #include "base/win/resource_util.h" | |
23 #include "breakpad/src/client/windows/handler/exception_handler.h" | |
24 #include "grit/webkit_chromium_resources.h" | |
25 #include "grit/webkit_resources.h" | |
26 #include "net/base/net_module.h" | |
27 #include "net/url_request/url_request_file_job.h" | |
28 #include "skia/ext/bitmap_platform_device.h" | |
29 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" | |
30 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" | |
31 #include "ui/base/win/hwnd_util.h" | |
32 #include "ui/base/win/scoped_ole_initializer.h" | |
33 #include "webkit/glue/webkit_glue.h" | |
34 #include "webkit/glue/webpreferences.h" | |
35 #include "webkit/plugins/npapi/plugin_list.h" | |
36 #include "webkit/tools/test_shell/resource.h" | |
37 #include "webkit/tools/test_shell/test_navigation_controller.h" | |
38 #include "webkit/tools/test_shell/test_shell_devtools_agent.h" | |
39 #include "webkit/tools/test_shell/test_shell_switches.h" | |
40 #include "webkit/tools/test_shell/test_shell_webkit_init.h" | |
41 #include "webkit/tools/test_shell/test_webview_delegate.h" | |
42 | |
43 using WebKit::WebWidget; | |
44 | |
45 #define MAX_LOADSTRING 100 | |
46 | |
47 #define BUTTON_WIDTH 72 | |
48 #define URLBAR_HEIGHT 24 | |
49 | |
50 // Global Variables: | |
51 static wchar_t g_windowTitle[MAX_LOADSTRING]; // The title bar text | |
52 static wchar_t g_windowClass[MAX_LOADSTRING]; // The main window class name | |
53 | |
54 // This is only set for layout tests. It is used to determine the name of a | |
55 // minidump file. | |
56 static const size_t kPathBufSize = 2048; | |
57 static wchar_t g_currentTestName[kPathBufSize]; | |
58 | |
59 // Forward declarations of functions included in this code module: | |
60 static INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); | |
61 | |
62 // Hide the window offscreen when in layout test mode. | |
63 // This would correspond with a minimized window position if x = y = -32000. | |
64 // However we shift the x to 0 to pass test cross-frame-access-put.html | |
65 // which expects screenX/screenLeft to be 0 (http://b/issue?id=1227945). | |
66 // TODO(ericroman): x should be defined as 0 rather than -4. There is | |
67 // probably a frameborder not being accounted for in the setting/getting. | |
68 const int kTestWindowXLocation = -4; | |
69 const int kTestWindowYLocation = -32000; | |
70 | |
71 namespace { | |
72 | |
73 // This method is used to keep track of the current test name so when we write | |
74 // a minidump file, we have the test name in the minidump filename. | |
75 void SetCurrentTestName(const char* path) { | |
76 const char* lastSlash = strrchr(path, '/'); | |
77 if (lastSlash) { | |
78 ++lastSlash; | |
79 } else { | |
80 lastSlash = path; | |
81 } | |
82 | |
83 base::wcslcpy(g_currentTestName, | |
84 UTF8ToWide(lastSlash).c_str(), | |
85 arraysize(g_currentTestName)); | |
86 } | |
87 | |
88 bool MinidumpCallback(const wchar_t *dumpPath, | |
89 const wchar_t *minidumpID, | |
90 void *context, | |
91 EXCEPTION_POINTERS *exinfo, | |
92 MDRawAssertionInfo *assertion, | |
93 bool succeeded) { | |
94 // Warning: Don't use the heap in this function. It may be corrupted. | |
95 if (!g_currentTestName[0]) | |
96 return false; | |
97 | |
98 // Try to rename the minidump file to include the crashed test's name. | |
99 // StackString uses the stack but overflows onto the heap. But we don't | |
100 // care too much about being completely correct here, since most crashes | |
101 // will be happening on developers' machines where they have debuggers. | |
102 base::StackString16<kPathBufSize * 2> origPath; | |
103 origPath->append(dumpPath); | |
104 origPath->push_back(base::FilePath::kSeparators[0]); | |
105 origPath->append(minidumpID); | |
106 origPath->append(L".dmp"); | |
107 | |
108 base::StackString16<kPathBufSize * 2> newPath; | |
109 newPath->append(dumpPath); | |
110 newPath->push_back(base::FilePath::kSeparators[0]); | |
111 newPath->append(g_currentTestName); | |
112 newPath->append(L"-"); | |
113 newPath->append(minidumpID); | |
114 newPath->append(L".dmp"); | |
115 | |
116 // May use the heap, but oh well. If this fails, we'll just have the | |
117 // original dump file lying around. | |
118 _wrename(origPath->c_str(), newPath->c_str()); | |
119 | |
120 return false; | |
121 } | |
122 | |
123 // Helper method for getting the path to the test shell resources directory. | |
124 base::FilePath GetResourcesFilePath() { | |
125 base::FilePath path; | |
126 PathService::Get(base::DIR_SOURCE_ROOT, &path); | |
127 path = path.AppendASCII("webkit"); | |
128 path = path.AppendASCII("tools"); | |
129 path = path.AppendASCII("test_shell"); | |
130 return path.AppendASCII("resources"); | |
131 } | |
132 | |
133 static base::StringPiece GetRawDataResource(HMODULE module, int resource_id) { | |
134 void* data_ptr; | |
135 size_t data_size; | |
136 return base::win::GetDataResourceFromModule(module, resource_id, &data_ptr, | |
137 &data_size) | |
138 ? base::StringPiece(static_cast<char*>(data_ptr), data_size) | |
139 : base::StringPiece(); | |
140 } | |
141 | |
142 } // namespace | |
143 | |
144 // static | |
145 HINSTANCE TestShell::instance_handle_; | |
146 ui::ScopedOleInitializer* TestShell::ole_initializer_; | |
147 | |
148 ///////////////////////////////////////////////////////////////////////////// | |
149 // static methods on TestShell | |
150 | |
151 const MINIDUMP_TYPE kFullDumpType = static_cast<MINIDUMP_TYPE>( | |
152 MiniDumpWithFullMemory | // Full memory from process. | |
153 MiniDumpWithProcessThreadData | // Get PEB and TEB. | |
154 MiniDumpWithHandleData); // Get all handle information. | |
155 | |
156 void TestShell::InitializeTestShell(bool layout_test_mode, | |
157 bool allow_external_pages) { | |
158 ole_initializer_ = new ui::ScopedOleInitializer(); | |
159 | |
160 window_list_ = new WindowList; | |
161 instance_handle_ = ::GetModuleHandle(NULL); | |
162 layout_test_mode_ = layout_test_mode; | |
163 allow_external_pages_ = allow_external_pages; | |
164 | |
165 web_prefs_ = new WebPreferences; | |
166 | |
167 ResetWebPreferences(); | |
168 | |
169 // Register the Ahem font used by layout tests. | |
170 DWORD num_fonts = 1; | |
171 void* font_ptr; | |
172 size_t font_size; | |
173 if (base::win::GetDataResourceFromModule(::GetModuleHandle(NULL), | |
174 IDR_AHEM_FONT, &font_ptr, &font_size)) { | |
175 HANDLE rc = AddFontMemResourceEx(font_ptr, font_size, 0, &num_fonts); | |
176 DCHECK(rc != 0); | |
177 } | |
178 | |
179 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); | |
180 if (parsed_command_line.HasSwitch(test_shell::kCrashDumps)) { | |
181 base::string16 dir( | |
182 parsed_command_line.GetSwitchValueNative(test_shell::kCrashDumps)); | |
183 if (parsed_command_line.HasSwitch(test_shell::kCrashDumpsFulldump)) { | |
184 new google_breakpad::ExceptionHandler( | |
185 dir, // dump_path | |
186 NULL, // filter | |
187 &MinidumpCallback, // callback | |
188 NULL, // callback_context | |
189 google_breakpad::ExceptionHandler::HANDLER_ALL, // handler_types | |
190 kFullDumpType, // dump_type | |
191 static_cast<const wchar_t*>(NULL), // pipe_name | |
192 NULL); // custom_info | |
193 } else { | |
194 new google_breakpad::ExceptionHandler( | |
195 dir, // dump_path | |
196 NULL, // filter | |
197 &MinidumpCallback, // callback | |
198 NULL, // callback_context | |
199 google_breakpad::ExceptionHandler::HANDLER_ALL); // handler_tpes | |
200 } | |
201 } | |
202 } | |
203 | |
204 void TestShell::DestroyWindow(gfx::NativeWindow windowHandle) { | |
205 // Do we want to tear down some of the machinery behind the scenes too? | |
206 RemoveWindowFromList(windowHandle); | |
207 ::DestroyWindow(windowHandle); | |
208 } | |
209 | |
210 void TestShell::PlatformShutdown() { | |
211 delete ole_initializer_; | |
212 ole_initializer_ = NULL; | |
213 } | |
214 | |
215 ATOM TestShell::RegisterWindowClass() { | |
216 LoadString(instance_handle_, IDS_APP_TITLE, g_windowTitle, MAX_LOADSTRING); | |
217 LoadString(instance_handle_, IDC_TESTSHELL, g_windowClass, MAX_LOADSTRING); | |
218 | |
219 WNDCLASSEX wcex = { | |
220 sizeof(WNDCLASSEX), | |
221 CS_HREDRAW | CS_VREDRAW, | |
222 TestShell::WndProc, | |
223 0, | |
224 0, | |
225 instance_handle_, | |
226 LoadIcon(instance_handle_, MAKEINTRESOURCE(IDI_TESTSHELL)), | |
227 LoadCursor(NULL, IDC_ARROW), | |
228 0, | |
229 MAKEINTRESOURCE(IDC_TESTSHELL), | |
230 g_windowClass, | |
231 LoadIcon(instance_handle_, MAKEINTRESOURCE(IDI_SMALL)), | |
232 }; | |
233 return RegisterClassEx(&wcex); | |
234 } | |
235 | |
236 void TestShell::DumpAllBackForwardLists(base::string16* result) { | |
237 result->clear(); | |
238 for (WindowList::iterator iter = TestShell::windowList()->begin(); | |
239 iter != TestShell::windowList()->end(); iter++) { | |
240 HWND hwnd = *iter; | |
241 TestShell* shell = | |
242 static_cast<TestShell*>(ui::GetWindowUserData(hwnd)); | |
243 shell->DumpBackForwardList(result); | |
244 } | |
245 } | |
246 | |
247 std::string TestShell::RewriteLocalUrl(const std::string& url) { | |
248 // Convert file:///tmp/LayoutTests urls to the actual location on disk. | |
249 const char kPrefix[] = "file:///tmp/LayoutTests/"; | |
250 const int kPrefixLen = arraysize(kPrefix) - 1; | |
251 | |
252 std::string new_url(url); | |
253 if (url.compare(0, kPrefixLen, kPrefix, kPrefixLen) == 0) { | |
254 base::FilePath replace_url; | |
255 PathService::Get(base::DIR_EXE, &replace_url); | |
256 replace_url = replace_url.DirName(); | |
257 replace_url = replace_url.DirName(); | |
258 replace_url = replace_url.AppendASCII("third_party"); | |
259 replace_url = replace_url.AppendASCII("WebKit"); | |
260 replace_url = replace_url.AppendASCII("LayoutTests"); | |
261 base::string16 replace_url_str = replace_url.value(); | |
262 replace_url_str.push_back(L'/'); | |
263 new_url = std::string("file:///") + | |
264 UTF16ToUTF8(replace_url_str).append(url.substr(kPrefixLen)); | |
265 } | |
266 return new_url; | |
267 } | |
268 | |
269 | |
270 | |
271 ///////////////////////////////////////////////////////////////////////////// | |
272 // TestShell implementation | |
273 | |
274 void TestShell::PlatformCleanUp() { | |
275 // When the window is destroyed, tell the Edit field to forget about us, | |
276 // otherwise we will crash. | |
277 ui::SetWindowProc(m_editWnd, default_edit_wnd_proc_); | |
278 ui::SetWindowUserData(m_editWnd, NULL); | |
279 } | |
280 | |
281 void TestShell::EnableUIControl(UIControl control, bool is_enabled) { | |
282 int id; | |
283 switch (control) { | |
284 case BACK_BUTTON: | |
285 id = IDC_NAV_BACK; | |
286 break; | |
287 case FORWARD_BUTTON: | |
288 id = IDC_NAV_FORWARD; | |
289 break; | |
290 case STOP_BUTTON: | |
291 id = IDC_NAV_STOP; | |
292 break; | |
293 default: | |
294 NOTREACHED() << "Unknown UI control"; | |
295 return; | |
296 } | |
297 EnableWindow(GetDlgItem(m_mainWnd, id), is_enabled); | |
298 } | |
299 | |
300 bool TestShell::Initialize(const GURL& starting_url) { | |
301 // Perform application initialization: | |
302 m_mainWnd = CreateWindow(g_windowClass, g_windowTitle, | |
303 WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, | |
304 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, | |
305 NULL, NULL, instance_handle_, NULL); | |
306 ui::SetWindowUserData(m_mainWnd, this); | |
307 | |
308 HWND hwnd; | |
309 int x = 0; | |
310 | |
311 hwnd = CreateWindow(L"BUTTON", L"Back", | |
312 WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON , | |
313 x, 0, BUTTON_WIDTH, URLBAR_HEIGHT, | |
314 m_mainWnd, (HMENU) IDC_NAV_BACK, instance_handle_, 0); | |
315 x += BUTTON_WIDTH; | |
316 | |
317 hwnd = CreateWindow(L"BUTTON", L"Forward", | |
318 WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON , | |
319 x, 0, BUTTON_WIDTH, URLBAR_HEIGHT, | |
320 m_mainWnd, (HMENU) IDC_NAV_FORWARD, instance_handle_, 0); | |
321 x += BUTTON_WIDTH; | |
322 | |
323 hwnd = CreateWindow(L"BUTTON", L"Reload", | |
324 WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON , | |
325 x, 0, BUTTON_WIDTH, URLBAR_HEIGHT, | |
326 m_mainWnd, (HMENU) IDC_NAV_RELOAD, instance_handle_, 0); | |
327 x += BUTTON_WIDTH; | |
328 | |
329 hwnd = CreateWindow(L"BUTTON", L"Stop", | |
330 WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON , | |
331 x, 0, BUTTON_WIDTH, URLBAR_HEIGHT, | |
332 m_mainWnd, (HMENU) IDC_NAV_STOP, instance_handle_, 0); | |
333 x += BUTTON_WIDTH; | |
334 | |
335 // this control is positioned by ResizeSubViews | |
336 m_editWnd = CreateWindow(L"EDIT", 0, | |
337 WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | | |
338 ES_AUTOVSCROLL | ES_AUTOHSCROLL, | |
339 x, 0, 0, 0, m_mainWnd, 0, instance_handle_, 0); | |
340 | |
341 default_edit_wnd_proc_ = ui::SetWindowProc(m_editWnd, TestShell::EditWndProc); | |
342 ui::SetWindowUserData(m_editWnd, this); | |
343 | |
344 dev_tools_agent_.reset(new TestShellDevToolsAgent()); | |
345 | |
346 // create webview | |
347 m_webViewHost.reset( | |
348 WebViewHost::Create(m_mainWnd, | |
349 delegate_.get(), | |
350 dev_tools_agent_.get(), | |
351 *TestShell::web_prefs_)); | |
352 dev_tools_agent_->SetWebView(m_webViewHost->webview()); | |
353 delegate_->RegisterDragDrop(); | |
354 | |
355 // Load our initial content. | |
356 if (starting_url.is_valid()) | |
357 LoadURL(starting_url); | |
358 | |
359 ShowWindow(webViewWnd(), SW_SHOW); | |
360 | |
361 if (IsSVGTestURL(starting_url)) { | |
362 SizeToSVG(); | |
363 } else { | |
364 SizeToDefault(); | |
365 } | |
366 | |
367 return true; | |
368 } | |
369 | |
370 void TestShell::InteractiveSetFocus(WebWidgetHost* host, bool enable) { | |
371 if (!enable && ::GetFocus() == host->view_handle()) | |
372 ::SetFocus(NULL); | |
373 } | |
374 | |
375 WebWidget* TestShell::CreatePopupWidget() { | |
376 DCHECK(!m_popupHost); | |
377 m_popupHost = WebWidgetHost::Create(NULL, popup_delegate_.get()); | |
378 ShowWindow(popupWnd(), SW_SHOW); | |
379 | |
380 return m_popupHost->webwidget(); | |
381 } | |
382 | |
383 void TestShell::ClosePopup() { | |
384 PostMessage(popupWnd(), WM_CLOSE, 0, 0); | |
385 m_popupHost = NULL; | |
386 } | |
387 | |
388 void TestShell::SizeTo(int width, int height) { | |
389 RECT rc, rw; | |
390 GetClientRect(m_mainWnd, &rc); | |
391 GetWindowRect(m_mainWnd, &rw); | |
392 | |
393 int client_width = rc.right - rc.left; | |
394 int window_width = rw.right - rw.left; | |
395 window_width = (window_width - client_width) + width; | |
396 | |
397 int client_height = rc.bottom - rc.top; | |
398 int window_height = rw.bottom - rw.top; | |
399 window_height = (window_height - client_height) + height; | |
400 | |
401 // add space for the url bar: | |
402 window_height += URLBAR_HEIGHT; | |
403 | |
404 SetWindowPos(m_mainWnd, NULL, 0, 0, window_width, window_height, | |
405 SWP_NOMOVE | SWP_NOZORDER); | |
406 } | |
407 | |
408 void TestShell::ResizeSubViews() { | |
409 RECT rc; | |
410 GetClientRect(m_mainWnd, &rc); | |
411 | |
412 int x = BUTTON_WIDTH * 4; | |
413 MoveWindow(m_editWnd, x, 0, rc.right - x, URLBAR_HEIGHT, TRUE); | |
414 | |
415 MoveWindow(webViewWnd(), 0, URLBAR_HEIGHT, rc.right, | |
416 rc.bottom - URLBAR_HEIGHT, TRUE); | |
417 } | |
418 | |
419 void TestShell::LoadURLForFrame(const GURL& url, | |
420 const base::string16& frame_name) { | |
421 if (!url.is_valid()) | |
422 return; | |
423 | |
424 TRACE_EVENT_BEGIN_ETW("url.load", this, url.spec()); | |
425 | |
426 if (IsSVGTestURL(url)) { | |
427 SizeToSVG(); | |
428 } else { | |
429 // only resize back to the default when running tests | |
430 if (layout_test_mode()) | |
431 SizeToDefault(); | |
432 } | |
433 | |
434 navigation_controller_->LoadEntry( | |
435 new TestNavigationEntry(-1, url, frame_name)); | |
436 } | |
437 | |
438 LRESULT CALLBACK TestShell::WndProc(HWND hwnd, UINT message, WPARAM wParam, | |
439 LPARAM lParam) { | |
440 TestShell* shell = static_cast<TestShell*>(ui::GetWindowUserData(hwnd)); | |
441 | |
442 switch (message) { | |
443 case WM_COMMAND: | |
444 { | |
445 int wmId = LOWORD(wParam); | |
446 int wmEvent = HIWORD(wParam); | |
447 | |
448 switch (wmId) { | |
449 case IDM_ABOUT: | |
450 DialogBox(shell->instance_handle_, MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd, | |
451 About); | |
452 break; | |
453 case IDM_EXIT: | |
454 DestroyWindow(hwnd); | |
455 break; | |
456 case IDC_NAV_BACK: | |
457 shell->GoBackOrForward(-1); | |
458 break; | |
459 case IDC_NAV_FORWARD: | |
460 shell->GoBackOrForward(1); | |
461 break; | |
462 case IDC_NAV_RELOAD: | |
463 case IDC_NAV_STOP: | |
464 { | |
465 if (wmId == IDC_NAV_RELOAD) { | |
466 shell->Reload(); | |
467 } else { | |
468 shell->webView()->mainFrame()->stopLoading(); | |
469 } | |
470 } | |
471 break; | |
472 case IDM_DUMP_BODY_TEXT: | |
473 shell->DumpDocumentText(); | |
474 break; | |
475 case IDM_DUMP_RENDER_TREE: | |
476 shell->DumpRenderTree(); | |
477 break; | |
478 case IDM_ENABLE_IMAGES: | |
479 case IDM_ENABLE_PLUGINS: | |
480 case IDM_ENABLE_SCRIPTS: { | |
481 HMENU menu = GetSubMenu(GetMenu(hwnd), 1); | |
482 bool was_checked = | |
483 (GetMenuState(menu, wmId, MF_BYCOMMAND) & MF_CHECKED) != 0; | |
484 CheckMenuItem(menu, wmId, | |
485 MF_BYCOMMAND | (was_checked ? MF_UNCHECKED : MF_CHECKED)); | |
486 switch (wmId) { | |
487 case IDM_ENABLE_IMAGES: | |
488 shell->set_allow_images(!was_checked); | |
489 break; | |
490 case IDM_ENABLE_PLUGINS: | |
491 shell->set_allow_plugins(!was_checked); | |
492 break; | |
493 case IDM_ENABLE_SCRIPTS: | |
494 shell->set_allow_scripts(!was_checked); | |
495 break; | |
496 } | |
497 break; | |
498 } | |
499 case IDM_SHOW_DEV_TOOLS: | |
500 shell->ShowDevTools(); | |
501 break; | |
502 } | |
503 } | |
504 break; | |
505 | |
506 case WM_DESTROY: | |
507 { | |
508 | |
509 RemoveWindowFromList(hwnd); | |
510 | |
511 if (TestShell::windowList()->empty() || shell->is_modal()) { | |
512 MessageLoop::current()->PostTask(FROM_HERE, | |
513 MessageLoop::QuitClosure()); | |
514 } | |
515 delete shell; | |
516 } | |
517 return 0; | |
518 | |
519 case WM_SIZE: | |
520 if (shell->webView()) | |
521 shell->ResizeSubViews(); | |
522 return 0; | |
523 } | |
524 | |
525 return DefWindowProc(hwnd, message, wParam, lParam); | |
526 } | |
527 | |
528 | |
529 #define MAX_URL_LENGTH 1024 | |
530 | |
531 LRESULT CALLBACK TestShell::EditWndProc(HWND hwnd, UINT message, | |
532 WPARAM wParam, LPARAM lParam) { | |
533 TestShell* shell = | |
534 static_cast<TestShell*>(ui::GetWindowUserData(hwnd)); | |
535 | |
536 switch (message) { | |
537 case WM_CHAR: | |
538 if (wParam == VK_RETURN) { | |
539 wchar_t str[MAX_URL_LENGTH + 1]; // Leave room for adding a NULL; | |
540 *((LPWORD)str) = MAX_URL_LENGTH; | |
541 LRESULT str_len = SendMessage(hwnd, EM_GETLINE, 0, (LPARAM)str); | |
542 if (str_len > 0) { | |
543 str[str_len] = 0; // EM_GETLINE doesn't NULL terminate. | |
544 shell->LoadURL(GURL(str)); | |
545 } | |
546 | |
547 return 0; | |
548 } | |
549 } | |
550 | |
551 return (LRESULT) CallWindowProc(shell->default_edit_wnd_proc_, hwnd, | |
552 message, wParam, lParam); | |
553 } | |
554 | |
555 | |
556 // Message handler for about box. | |
557 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { | |
558 UNREFERENCED_PARAMETER(lParam); | |
559 switch (message) { | |
560 case WM_INITDIALOG: | |
561 return (INT_PTR)TRUE; | |
562 | |
563 case WM_COMMAND: | |
564 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { | |
565 EndDialog(hDlg, LOWORD(wParam)); | |
566 return (INT_PTR)TRUE; | |
567 } | |
568 break; | |
569 } | |
570 return (INT_PTR)FALSE; | |
571 } | |
572 | |
573 bool TestShell::PromptForSaveFile(const wchar_t* prompt_title, | |
574 base::FilePath* result) { | |
575 wchar_t path_buf[MAX_PATH] = L"data.txt"; | |
576 | |
577 OPENFILENAME info = {0}; | |
578 info.lStructSize = sizeof(info); | |
579 info.hwndOwner = m_mainWnd; | |
580 info.hInstance = instance_handle_; | |
581 info.lpstrFilter = L"*.txt\0"; | |
582 info.lpstrFile = path_buf; | |
583 info.nMaxFile = arraysize(path_buf); | |
584 info.lpstrTitle = prompt_title; | |
585 if (!GetSaveFileName(&info)) | |
586 return false; | |
587 | |
588 *result = base::FilePath(info.lpstrFile); | |
589 return true; | |
590 } | |
591 | |
592 // static | |
593 void TestShell::ShowStartupDebuggingDialog() { | |
594 MessageBox(NULL, L"attach to me?", L"test_shell", MB_OK); | |
595 } | |
596 | |
597 // static | |
598 base::StringPiece TestShell::ResourceProvider(int key) { | |
599 return GetRawDataResource(::GetModuleHandle(NULL), key); | |
600 } | |
601 | |
602 | |
603 base::string16 TestShellWebKitInit::GetLocalizedString(int message_id) { | |
604 wchar_t localized[MAX_LOADSTRING]; | |
605 int length = LoadString(GetModuleHandle(NULL), message_id, | |
606 localized, MAX_LOADSTRING); | |
607 if (!length && GetLastError() == ERROR_RESOURCE_NAME_NOT_FOUND) { | |
608 NOTREACHED(); | |
609 return L"No string for this identifier!"; | |
610 } | |
611 return base::string16(localized, length); | |
612 } | |
613 | |
614 // TODO(tc): Convert this to using resources from test_shell.rc. | |
615 base::StringPiece TestShellWebKitInit::GetDataResource( | |
616 int resource_id, | |
617 ui::ScaleFactor scale_factor) { | |
618 switch (resource_id) { | |
619 case IDR_BROKENIMAGE: { | |
620 // Use webkit's broken image icon (16x16) | |
621 static std::string broken_image_data; | |
622 if (broken_image_data.empty()) { | |
623 base::FilePath path = GetResourcesFilePath(); | |
624 path = path.AppendASCII("missingImage.gif"); | |
625 bool success = file_util::ReadFileToString(path, &broken_image_data); | |
626 if (!success) { | |
627 LOG(FATAL) << "Failed reading: " << path.value(); | |
628 } | |
629 } | |
630 return broken_image_data; | |
631 } | |
632 case IDR_TEXTAREA_RESIZER: { | |
633 // Use webkit's text area resizer image. | |
634 static std::string resize_corner_data; | |
635 if (resize_corner_data.empty()) { | |
636 base::FilePath path = GetResourcesFilePath(); | |
637 path = path.AppendASCII("textAreaResizeCorner.png"); | |
638 bool success = file_util::ReadFileToString(path, &resize_corner_data); | |
639 if (!success) { | |
640 LOG(FATAL) << "Failed reading: " << path.value(); | |
641 } | |
642 } | |
643 return resize_corner_data; | |
644 } | |
645 | |
646 case IDR_SEARCH_CANCEL: | |
647 case IDR_SEARCH_CANCEL_PRESSED: | |
648 case IDR_SEARCH_MAGNIFIER: | |
649 case IDR_SEARCH_MAGNIFIER_RESULTS: | |
650 case IDR_INPUT_SPEECH: | |
651 case IDR_INPUT_SPEECH_RECORDING: | |
652 case IDR_INPUT_SPEECH_WAITING: | |
653 //TODO(flackr): Pass scale_factor. | |
654 return TestShell::ResourceProvider(resource_id); | |
655 | |
656 default: | |
657 break; | |
658 } | |
659 | |
660 return base::StringPiece(); | |
661 } | |
662 | |
663 ///////////////////////////////////////////////////////////////////////////// | |
664 // WebKit glue functions | |
665 | |
666 namespace webkit_glue { | |
667 | |
668 bool EnsureFontLoaded(HFONT font) { | |
669 return true; | |
670 } | |
671 | |
672 bool DownloadUrl(const std::string& url, HWND caller_window) { | |
673 return false; | |
674 } | |
675 | |
676 } // namespace webkit_glue | |
OLD | NEW |