Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(27)

Side by Side Diff: webkit/tools/test_shell/test_shell_mac.mm

Issue 15028002: Delete test_shell. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add dummy test_shell build target. Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 <ApplicationServices/ApplicationServices.h>
6 #import <Cocoa/Cocoa.h>
7 #import <objc/objc-runtime.h>
8 #include <sys/stat.h>
9
10 #include "webkit/tools/test_shell/test_shell.h"
11
12 #include "base/base_paths.h"
13 #include "base/basictypes.h"
14 #include "base/debug/debugger.h"
15 #include "base/file_util.h"
16 #include "base/files/file_path.h"
17 #include "base/logging.h"
18 #include "base/mac/bundle_locations.h"
19 #include "base/mac/mac_util.h"
20 #include "base/mac/scoped_nsautorelease_pool.h"
21 #include "base/message_loop.h"
22 #include "base/path_service.h"
23 #include "base/string16.h"
24 #include "base/strings/string_piece.h"
25 #include "base/utf_string_conversions.h"
26 #include "grit/webkit_resources.h"
27 #include "net/base/mime_util.h"
28 #include "skia/ext/bitmap_platform_device.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
31 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
32 #include "ui/base/resource/data_pack.h"
33 #include "ui/gfx/size.h"
34 #include "webkit/glue/webkit_glue.h"
35 #include "webkit/glue/webpreferences.h"
36 #include "webkit/plugins/npapi/plugin_list.h"
37 #include "webkit/tools/test_shell/mac/test_shell_webview.h"
38 #include "webkit/tools/test_shell/resource.h"
39 #include "webkit/tools/test_shell/simple_resource_loader_bridge.h"
40 #include "webkit/tools/test_shell/test_navigation_controller.h"
41 #include "webkit/tools/test_shell/test_shell_webkit_init.h"
42 #include "webkit/tools/test_shell/test_webview_delegate.h"
43
44 #include "third_party/skia/include/core/SkBitmap.h"
45
46 #import "mac/DumpRenderTreePasteboard.h"
47
48 using WebKit::WebWidget;
49
50 #define MAX_LOADSTRING 100
51
52 // Sizes for URL bar layout
53 #define BUTTON_HEIGHT 22
54 #define BUTTON_WIDTH 72
55 #define BUTTON_MARGIN 8
56 #define URLBAR_HEIGHT 32
57
58 // Global Variables:
59
60 // Content area size for newly created windows.
61 const int kTestWindowWidth = 800;
62 const int kTestWindowHeight = 600;
63
64 // The W3C SVG layout tests use a different size than the other layout tests
65 const int kSVGTestWindowWidth = 480;
66 const int kSVGTestWindowHeight = 360;
67
68 // Hide the window offscreen when in layout test mode. Mac OS X limits
69 // window positions to +/- 16000.
70 const int kTestWindowXLocation = -14000;
71 const int kTestWindowYLocation = -14000;
72
73 // Data pack resource. This is a pointer to the mmapped resources file.
74 static ui::DataPack* g_resource_data_pack = NULL;
75
76 // Define static member variables
77 base::LazyInstance <std::map<gfx::NativeWindow, TestShell *> >
78 TestShell::window_map_ = LAZY_INSTANCE_INITIALIZER;
79
80 // Helper method for getting the path to the test shell resources directory.
81 base::FilePath GetResourcesFilePath() {
82 base::FilePath path;
83 // We need to know if we're bundled or not to know which path to use.
84 if (base::mac::AmIBundled()) {
85 PathService::Get(base::DIR_EXE, &path);
86 path = path.Append(base::FilePath::kParentDirectory);
87 return path.AppendASCII("Resources");
88 } else {
89 PathService::Get(base::DIR_SOURCE_ROOT, &path);
90 path = path.AppendASCII("webkit");
91 path = path.AppendASCII("tools");
92 path = path.AppendASCII("test_shell");
93 return path.AppendASCII("resources");
94 }
95 }
96
97 // Receives notification that the window is closing so that it can start the
98 // tear-down process. Is responsible for deleting itself when done.
99 @interface WindowDelegate : NSObject<NSWindowDelegate> {
100 @private
101 TestShellWebView* m_webView;
102 }
103 - (id)initWithWebView:(TestShellWebView*)view;
104 @end
105
106 @implementation WindowDelegate
107
108 - (id)initWithWebView:(TestShellWebView*)view {
109 if ((self = [super init])) {
110 m_webView = view;
111 }
112 return self;
113 }
114
115 - (void)windowDidBecomeKey:(NSNotification*)notification {
116 [m_webView setIsActive:YES];
117 }
118
119 - (void)windowDidResignKey:(NSNotification*)notification {
120 [m_webView setIsActive:NO];
121 }
122
123 // Called when the window is about to close. Perform the self-destruction
124 // sequence by getting rid of the shell and removing it and the window from
125 // the various global lists. Instead of doing it here, however, we fire off
126 // a delayed call to |-cleanup:| to allow everything to get off the stack
127 // before we go deleting objects. By returning YES, we allow the window to be
128 // removed from the screen.
129 - (BOOL)windowShouldClose:(id)window {
130 m_webView = nil;
131
132 // Try to make the window go away, but it may not when running layout
133 // tests due to the quirkyness of autorelease pools and having no main loop.
134 [window autorelease];
135
136 // clean ourselves up and do the work after clearing the stack of anything
137 // that might have the shell on it.
138 [self performSelectorOnMainThread:@selector(cleanup:)
139 withObject:window
140 waitUntilDone:NO];
141
142 return YES;
143 }
144
145 // does the work of removing the window from our various bookkeeping lists
146 // and gets rid of the shell.
147 - (void)cleanup:(id)window {
148 TestShell::RemoveWindowFromList(window);
149 TestShell::DestroyAssociatedShell(window);
150
151 [self release];
152 }
153
154 @end
155
156 // Mac-specific stuff to do when the dtor is called. Nothing to do in our
157 // case.
158 void TestShell::PlatformCleanUp() {
159 }
160
161 void TestShell::EnableUIControl(UIControl control, bool is_enabled) {
162 // TODO(darin): Implement me.
163 }
164
165 // static
166 void TestShell::DestroyAssociatedShell(gfx::NativeWindow handle) {
167 WindowMap::iterator it = window_map_.Get().find(handle);
168 if (it != window_map_.Get().end()) {
169 // Break the view's association with its shell before deleting the shell.
170 TestShellWebView* web_view =
171 static_cast<TestShellWebView*>(it->second->m_webViewHost->view_handle());
172 if ([web_view isKindOfClass:[TestShellWebView class]]) {
173 [web_view setShell:NULL];
174 }
175
176 delete it->second;
177 window_map_.Get().erase(it);
178 } else {
179 LOG(ERROR) << "Failed to find shell for window during destroy";
180 }
181 }
182
183 // static
184 void TestShell::PlatformShutdown() {
185 // for each window in the window list, release it and destroy its shell
186 for (WindowList::iterator it = TestShell::windowList()->begin();
187 it != TestShell::windowList()->end();
188 ++it) {
189 DestroyAssociatedShell(*it);
190 [*it release];
191 }
192 // assert if we have anything left over, that would be bad.
193 DCHECK(window_map_.Get().empty());
194
195 // Dump the pasteboards we built up.
196 [DumpRenderTreePasteboard releaseLocalPasteboards];
197 }
198
199 // static
200 void TestShell::InitializeTestShell(bool layout_test_mode,
201 bool allow_external_pages) {
202 // This should move to a per-process platform-specific initialization function
203 // when one exists.
204
205 window_list_ = new WindowList;
206 layout_test_mode_ = layout_test_mode;
207 allow_external_pages_ = allow_external_pages;
208
209 web_prefs_ = new WebPreferences;
210
211 // mmap the data pack which holds strings used by WebCore. This is only
212 // a fatal error if we're bundled, which means we might be running layout
213 // tests. This is a harmless failure for test_shell_tests.
214 g_resource_data_pack = new ui::DataPack(ui::SCALE_FACTOR_100P);
215 NSString *resource_path =
216 [base::mac::FrameworkBundle() pathForResource:@"test_shell"
217 ofType:@"pak"];
218 base::FilePath resources_pak_path([resource_path fileSystemRepresentation]);
219 if (!g_resource_data_pack->LoadFromPath(resources_pak_path)) {
220 LOG(FATAL) << "failed to load test_shell.pak";
221 }
222
223 ResetWebPreferences();
224
225 // Load the Ahem font, which is used by layout tests.
226 NSString* ahem_path = [[base::mac::FrameworkBundle() resourcePath]
227 stringByAppendingPathComponent:@"AHEM____.TTF"];
228 NSURL* ahem_path_url = [NSURL fileURLWithPath:ahem_path];
229 CFErrorRef error;
230 if (!CTFontManagerRegisterFontsForURL((CFURLRef)ahem_path_url,
231 kCTFontManagerScopeProcess, &error)) {
232 DLOG(FATAL) << "CTFontManagerRegisterFontsForURL "
233 << [ahem_path fileSystemRepresentation]
234 << [[(NSError*)error description] UTF8String];
235 }
236
237 // Add <app bundle's parent dir>/plugins to the plugin path so we can load
238 // test plugins.
239 base::FilePath plugins_dir;
240 PathService::Get(base::DIR_EXE, &plugins_dir);
241 if (base::mac::AmIBundled()) {
242 plugins_dir = plugins_dir.AppendASCII("../../../plugins");
243 } else {
244 plugins_dir = plugins_dir.AppendASCII("plugins");
245 }
246 webkit::npapi::PluginList::Singleton()->AddExtraPluginDir(plugins_dir);
247 }
248
249 NSButton* MakeTestButton(NSRect* rect, NSString* title, NSView* parent) {
250 NSButton* button = [[[NSButton alloc] initWithFrame:*rect] autorelease];
251 [button setTitle:title];
252 [button setBezelStyle:NSSmallSquareBezelStyle];
253 [button setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)];
254 [parent addSubview:button];
255 rect->origin.x += BUTTON_WIDTH;
256 return button;
257 }
258
259 bool TestShell::Initialize(const GURL& starting_url) {
260 // Perform application initialization:
261 // send message to app controller? need to work this out
262
263 // TODO(awalker): this is a straight recreation of windows test_shell.cc's
264 // window creation code--we should really pull this from the nib and grab
265 // references to the already-created subviews that way.
266 NSRect screen_rect = [[NSScreen mainScreen] visibleFrame];
267 NSRect window_rect = { {0, screen_rect.size.height - kTestWindowHeight},
268 {kTestWindowWidth, kTestWindowHeight} };
269 m_mainWnd = [[NSWindow alloc]
270 initWithContentRect:window_rect
271 styleMask:(NSTitledWindowMask |
272 NSClosableWindowMask |
273 NSMiniaturizableWindowMask |
274 NSResizableWindowMask )
275 backing:NSBackingStoreBuffered
276 defer:NO];
277 [m_mainWnd setTitle:@"TestShell"];
278
279 // Add to our map
280 window_map_.Get()[m_mainWnd] = this;
281
282 // Rely on the window delegate to clean us up rather than immediately
283 // releasing when the window gets closed. We use the delegate to do
284 // everything from the autorelease pool so the shell isn't on the stack
285 // during cleanup (ie, a window close from javascript).
286 [m_mainWnd setReleasedWhenClosed:NO];
287
288 // Create a webview. Note that |web_view| takes ownership of this shell so we
289 // will get cleaned up when it gets destroyed.
290 m_webViewHost.reset(
291 WebViewHost::Create([m_mainWnd contentView],
292 delegate_.get(),
293 0,
294 *TestShell::web_prefs_));
295 delegate_->RegisterDragDrop();
296 TestShellWebView* web_view =
297 static_cast<TestShellWebView*>(m_webViewHost->view_handle());
298 [web_view setShell:this];
299
300 // Create a window delegate to watch for when it's asked to go away. It will
301 // clean itself up so we don't need to hold a reference.
302 [m_mainWnd setDelegate:[[WindowDelegate alloc] initWithWebView:web_view]];
303
304 // create buttons
305 NSRect button_rect = [[m_mainWnd contentView] bounds];
306 button_rect.origin.y = window_rect.size.height - URLBAR_HEIGHT +
307 (URLBAR_HEIGHT - BUTTON_HEIGHT) / 2;
308 button_rect.size.height = BUTTON_HEIGHT;
309 button_rect.origin.x += BUTTON_MARGIN;
310 button_rect.size.width = BUTTON_WIDTH;
311
312 NSView* content = [m_mainWnd contentView];
313
314 NSButton* button = MakeTestButton(&button_rect, @"Back", content);
315 [button setTarget:web_view];
316 [button setAction:@selector(goBack:)];
317
318 button = MakeTestButton(&button_rect, @"Forward", content);
319 [button setTarget:web_view];
320 [button setAction:@selector(goForward:)];
321
322 // reload button
323 button = MakeTestButton(&button_rect, @"Reload", content);
324 [button setTarget:web_view];
325 [button setAction:@selector(reload:)];
326
327 // stop button
328 button = MakeTestButton(&button_rect, @"Stop", content);
329 [button setTarget:web_view];
330 [button setAction:@selector(stopLoading:)];
331
332 // text field for URL
333 button_rect.origin.x += BUTTON_MARGIN;
334 button_rect.size.width = [[m_mainWnd contentView] bounds].size.width -
335 button_rect.origin.x - BUTTON_MARGIN;
336 m_editWnd = [[NSTextField alloc] initWithFrame:button_rect];
337 [[m_mainWnd contentView] addSubview:m_editWnd];
338 [m_editWnd setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)];
339 [m_editWnd setTarget:web_view];
340 [m_editWnd setAction:@selector(takeURLStringValueFrom:)];
341 [[m_editWnd cell] setWraps:NO];
342 [[m_editWnd cell] setScrollable:YES];
343
344 // show the window
345 [m_mainWnd makeKeyAndOrderFront: nil];
346
347 // Load our initial content.
348 if (starting_url.is_valid())
349 LoadURL(starting_url);
350
351 if (IsSVGTestURL(starting_url)) {
352 SizeTo(kSVGTestWindowWidth, kSVGTestWindowHeight);
353 } else {
354 SizeToDefault();
355 }
356
357 return true;
358 }
359
360 void TestShell::InteractiveSetFocus(WebWidgetHost* host, bool enable) {
361 if (enable) {
362 [[host->view_handle() window] makeKeyAndOrderFront:nil];
363 } else {
364 // There is no way to resign key window status in Cocoa. Fake it by
365 // ordering the window out (transferring key status to another window) and
366 // then ordering the window back in, but without making it key.
367 [[host->view_handle() window] orderOut:nil];
368 [[host->view_handle() window] orderFront:nil];
369 }
370 }
371
372 // static
373 void TestShell::DestroyWindow(gfx::NativeWindow windowHandle) {
374 // This code is like -cleanup: on our window delegate. This call needs to be
375 // able to force down a window for tests, so it closes down the window making
376 // sure it cleans up the window delegate and the test shells list of windows
377 // and map of windows to shells.
378
379 TestShell::RemoveWindowFromList(windowHandle);
380 TestShell::DestroyAssociatedShell(windowHandle);
381
382 id windowDelegate = [windowHandle delegate];
383 DCHECK(windowDelegate);
384 [windowHandle setDelegate:nil];
385 [windowDelegate release];
386
387 [windowHandle close];
388 [windowHandle autorelease];
389 }
390
391 WebWidget* TestShell::CreatePopupWidget() {
392 DCHECK(!m_popupHost);
393 m_popupHost = WebWidgetHost::Create(webViewWnd(), popup_delegate_.get());
394
395 return m_popupHost->webwidget();
396 }
397
398 void TestShell::ClosePopup() {
399 // PostMessage(popupWnd(), WM_CLOSE, 0, 0);
400 m_popupHost = NULL;
401 }
402
403 void TestShell::SizeTo(int width, int height) {
404 // WebViewHost::Create() sets the HTML content rect to start 32 pixels below
405 // the top of the window to account for the "toolbar". We need to match that
406 // here otherwise the HTML content area will be too short.
407 NSRect r = [m_mainWnd contentRectForFrameRect:[m_mainWnd frame]];
408 r.size.width = width;
409 r.size.height = height + URLBAR_HEIGHT;
410 [m_mainWnd setFrame:[m_mainWnd frameRectForContentRect:r] display:YES];
411 }
412
413 void TestShell::ResizeSubViews() {
414 // handled by Cocoa for us
415 }
416
417 /* static */ void TestShell::DumpAllBackForwardLists(base::string16* result) {
418 result->clear();
419 for (WindowList::iterator iter = TestShell::windowList()->begin();
420 iter != TestShell::windowList()->end(); iter++) {
421 NSWindow* window = *iter;
422 WindowMap::iterator it = window_map_.Get().find(window);
423 if (it != window_map_.Get().end())
424 it->second->DumpBackForwardList(result);
425 else
426 LOG(ERROR) << "Failed to find shell for window during dump";
427 }
428 }
429
430 void TestShell::LoadURLForFrame(const GURL& url,
431 const base::string16& frame_name) {
432 if (!url.is_valid())
433 return;
434
435 if (IsSVGTestURL(url)) {
436 SizeTo(kSVGTestWindowWidth, kSVGTestWindowHeight);
437 } else {
438 // only resize back to the default when running tests
439 if (layout_test_mode())
440 SizeToDefault();
441 }
442
443 navigation_controller_->LoadEntry(
444 new TestNavigationEntry(-1, url, frame_name));
445 }
446
447 bool TestShell::PromptForSaveFile(const wchar_t* prompt_title,
448 base::FilePath* result)
449 {
450 NSSavePanel* save_panel = [NSSavePanel savePanel];
451
452 /* set up new attributes */
453 [save_panel setAllowedFileTypes:@[@"txt"]];
454 [save_panel setMessage:
455 [NSString stringWithUTF8String:WideToUTF8(prompt_title).c_str()]];
456
457 /* display the NSSavePanel */
458 [save_panel setDirectoryURL:[NSURL fileURLWithPath:NSHomeDirectory()]];
459 [save_panel setNameFieldStringValue:@""];
460 if ([save_panel runModal] == NSFileHandlingPanelOKButton) {
461 *result = base::FilePath([[[save_panel URL] path] fileSystemRepresentation]) ;
462 return true;
463 }
464 return false;
465 }
466
467 // static
468 std::string TestShell::RewriteLocalUrl(const std::string& url) {
469 // Convert file:///tmp/LayoutTests urls to the actual location on disk.
470 const char kPrefix[] = "file:///tmp/LayoutTests/";
471 const int kPrefixLen = arraysize(kPrefix) - 1;
472
473 std::string new_url(url);
474 if (url.compare(0, kPrefixLen, kPrefix, kPrefixLen) == 0) {
475 base::FilePath replace_path;
476 PathService::Get(base::DIR_SOURCE_ROOT, &replace_path);
477 replace_path = replace_path.Append(
478 "third_party/WebKit/LayoutTests/");
479 new_url = std::string("file://") + replace_path.value() +
480 url.substr(kPrefixLen);
481 }
482
483 return new_url;
484 }
485
486 // static
487 void TestShell::ShowStartupDebuggingDialog() {
488 NSAlert* alert = [[[NSAlert alloc] init] autorelease];
489 alert.messageText = @"Attach to me?";
490 alert.informativeText = @"This would probably be a good time to attach your "
491 "debugger.";
492 [alert addButtonWithTitle:@"OK"];
493
494 [alert runModal];
495 }
496
497 base::StringPiece TestShell::ResourceProvider(int key) {
498 base::StringPiece res;
499 g_resource_data_pack->GetStringPiece(key, &res);
500 return res;
501 }
502
503 //-----------------------------------------------------------------------------
504
505 base::string16 TestShellWebKitInit::GetLocalizedString(int message_id) {
506 base::StringPiece res;
507 if (!g_resource_data_pack->GetStringPiece(message_id, &res)) {
508 LOG(FATAL) << "failed to load webkit string with id " << message_id;
509 }
510
511 // Data packs hold strings as either UTF8 or UTF16.
512 base::string16 msg;
513 switch (g_resource_data_pack->GetTextEncodingType()) {
514 case ui::DataPack::UTF8:
515 msg = UTF8ToUTF16(res);
516 break;
517 case ui::DataPack::UTF16:
518 msg = base::string16(reinterpret_cast<const char16*>(res.data()),
519 res.length() / 2);
520 break;
521 case ui::DataPack::BINARY:
522 NOTREACHED();
523 break;
524 }
525
526 return msg;
527 }
528
529 base::StringPiece TestShellWebKitInit::GetDataResource(
530 int resource_id,
531 ui::ScaleFactor scale_factor) {
532 switch (resource_id) {
533 case IDR_BROKENIMAGE: {
534 // Use webkit's broken image icon (16x16)
535 static std::string broken_image_data;
536 if (broken_image_data.empty()) {
537 base::FilePath path = GetResourcesFilePath();
538 // In order to match WebKit's colors for the missing image, we have to
539 // use a PNG. The GIF doesn't have the color range needed to correctly
540 // match the TIFF they use in Safari.
541 path = path.AppendASCII("missingImage.png");
542 bool success = file_util::ReadFileToString(path, &broken_image_data);
543 if (!success) {
544 LOG(FATAL) << "Failed reading: " << path.value();
545 }
546 }
547 return broken_image_data;
548 }
549 case IDR_TEXTAREA_RESIZER: {
550 // Use webkit's text area resizer image.
551 static std::string resize_corner_data;
552 if (resize_corner_data.empty()) {
553 base::FilePath path = GetResourcesFilePath();
554 path = path.AppendASCII("textAreaResizeCorner.png");
555 bool success = file_util::ReadFileToString(path, &resize_corner_data);
556 if (!success) {
557 LOG(FATAL) << "Failed reading: " << path.value();
558 }
559 }
560 return resize_corner_data;
561 }
562
563 case IDR_SEARCH_CANCEL:
564 case IDR_SEARCH_CANCEL_PRESSED:
565 case IDR_SEARCH_MAGNIFIER:
566 case IDR_SEARCH_MAGNIFIER_RESULTS:
567 case IDR_INPUT_SPEECH:
568 case IDR_INPUT_SPEECH_RECORDING:
569 case IDR_INPUT_SPEECH_WAITING:
570 // TODO(flackr): Pass scale_factor to ResourceProvider.
571 return TestShell::ResourceProvider(resource_id);
572
573 default:
574 break;
575 }
576
577 return base::StringPiece();
578 }
579
580 namespace webkit_glue {
581
582 bool DownloadUrl(const std::string& url, NSWindow* caller_window) {
583 return false;
584 }
585
586 void DidLoadPlugin(const std::string& filename) {
587 }
588
589 void DidUnloadPlugin(const std::string& filename) {
590 }
591
592 } // namespace webkit_glue
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698