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 "content/shell/renderer/webkit_test_runner.h"
6
7 #include <algorithm>
8 #include <clocale>
9 #include <cmath>
10
11 #include "base/base64.h"
12 #include "base/command_line.h"
13 #include "base/compiler_specific.h"
14 #include "base/debug/debugger.h"
15 #include "base/files/file_path.h"
16 #include "base/md5.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/message_loop/message_loop.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/stringprintf.h"
21 #include "base/strings/sys_string_conversions.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "base/time/time.h"
24 #include "content/public/common/content_switches.h"
25 #include "content/public/common/url_constants.h"
26 #include "content/public/common/web_preferences.h"
27 #include "content/public/renderer/render_view.h"
28 #include "content/public/renderer/render_view_visitor.h"
29 #include "content/public/renderer/renderer_gamepad_provider.h"
30 #include "content/public/test/layouttest_support.h"
31 #include "content/shell/common/shell_messages.h"
32 #include "content/shell/common/shell_switches.h"
33 #include "content/shell/common/webkit_test_helpers.h"
34 #include "content/shell/renderer/gc_controller.h"
35 #include "content/shell/renderer/leak_detector.h"
36 #include "content/shell/renderer/shell_render_process_observer.h"
37 #include "content/shell/renderer/test_runner/mock_screen_orientation_client.h"
38 #include "content/shell/renderer/test_runner/web_task.h"
39 #include "content/shell/renderer/test_runner/web_test_interfaces.h"
40 #include "content/shell/renderer/test_runner/web_test_proxy.h"
41 #include "content/shell/renderer/test_runner/web_test_runner.h"
42 #include "net/base/filename_util.h"
43 #include "net/base/net_errors.h"
44 #include "skia/ext/platform_canvas.h"
45 #include "third_party/WebKit/public/platform/Platform.h"
46 #include "third_party/WebKit/public/platform/WebCString.h"
47 #include "third_party/WebKit/public/platform/WebPoint.h"
48 #include "third_party/WebKit/public/platform/WebRect.h"
49 #include "third_party/WebKit/public/platform/WebSize.h"
50 #include "third_party/WebKit/public/platform/WebString.h"
51 #include "third_party/WebKit/public/platform/WebURL.h"
52 #include "third_party/WebKit/public/platform/WebURLError.h"
53 #include "third_party/WebKit/public/platform/WebURLRequest.h"
54 #include "third_party/WebKit/public/platform/WebURLResponse.h"
55 #include "third_party/WebKit/public/web/WebArrayBufferView.h"
56 #include "third_party/WebKit/public/web/WebContextMenuData.h"
57 #include "third_party/WebKit/public/web/WebDataSource.h"
58 #include "third_party/WebKit/public/web/WebDevToolsAgent.h"
59 #include "third_party/WebKit/public/web/WebDocument.h"
60 #include "third_party/WebKit/public/web/WebElement.h"
61 #include "third_party/WebKit/public/web/WebHistoryItem.h"
62 #include "third_party/WebKit/public/web/WebKit.h"
63 #include "third_party/WebKit/public/web/WebLeakDetector.h"
64 #include "third_party/WebKit/public/web/WebLocalFrame.h"
65 #include "third_party/WebKit/public/web/WebScriptSource.h"
66 #include "third_party/WebKit/public/web/WebTestingSupport.h"
67 #include "third_party/WebKit/public/web/WebView.h"
68 #include "ui/gfx/rect.h"
69
70 using blink::Platform;
71 using blink::WebArrayBufferView;
72 using blink::WebContextMenuData;
73 using blink::WebDevToolsAgent;
74 using blink::WebDeviceMotionData;
75 using blink::WebDeviceOrientationData;
76 using blink::WebElement;
77 using blink::WebLocalFrame;
78 using blink::WebHistoryItem;
79 using blink::WebLocalFrame;
80 using blink::WebPoint;
81 using blink::WebRect;
82 using blink::WebScriptSource;
83 using blink::WebSize;
84 using blink::WebString;
85 using blink::WebURL;
86 using blink::WebURLError;
87 using blink::WebURLRequest;
88 using blink::WebScreenOrientationType;
89 using blink::WebTestingSupport;
90 using blink::WebVector;
91 using blink::WebView;
92
93 namespace content {
94
95 namespace {
96
InvokeTaskHelper(void * context)97 void InvokeTaskHelper(void* context) {
98 WebTask* task = reinterpret_cast<WebTask*>(context);
99 task->run();
100 delete task;
101 }
102
103 class SyncNavigationStateVisitor : public RenderViewVisitor {
104 public:
SyncNavigationStateVisitor()105 SyncNavigationStateVisitor() {}
~SyncNavigationStateVisitor()106 virtual ~SyncNavigationStateVisitor() {}
107
Visit(RenderView * render_view)108 virtual bool Visit(RenderView* render_view) OVERRIDE {
109 SyncNavigationState(render_view);
110 return true;
111 }
112 private:
113 DISALLOW_COPY_AND_ASSIGN(SyncNavigationStateVisitor);
114 };
115
116 class ProxyToRenderViewVisitor : public RenderViewVisitor {
117 public:
ProxyToRenderViewVisitor(WebTestProxyBase * proxy)118 explicit ProxyToRenderViewVisitor(WebTestProxyBase* proxy)
119 : proxy_(proxy),
120 render_view_(NULL) {
121 }
~ProxyToRenderViewVisitor()122 virtual ~ProxyToRenderViewVisitor() {}
123
render_view() const124 RenderView* render_view() const { return render_view_; }
125
Visit(RenderView * render_view)126 virtual bool Visit(RenderView* render_view) OVERRIDE {
127 WebKitTestRunner* test_runner = WebKitTestRunner::Get(render_view);
128 if (!test_runner) {
129 NOTREACHED();
130 return true;
131 }
132 if (test_runner->proxy() == proxy_) {
133 render_view_ = render_view;
134 return false;
135 }
136 return true;
137 }
138
139 private:
140 WebTestProxyBase* proxy_;
141 RenderView* render_view_;
142
143 DISALLOW_COPY_AND_ASSIGN(ProxyToRenderViewVisitor);
144 };
145
146 class NavigateAwayVisitor : public RenderViewVisitor {
147 public:
NavigateAwayVisitor(RenderView * main_render_view)148 explicit NavigateAwayVisitor(RenderView* main_render_view)
149 : main_render_view_(main_render_view) {}
~NavigateAwayVisitor()150 virtual ~NavigateAwayVisitor() {}
151
Visit(RenderView * render_view)152 virtual bool Visit(RenderView* render_view) OVERRIDE {
153 if (render_view == main_render_view_)
154 return true;
155 render_view->GetWebView()->mainFrame()->loadRequest(
156 WebURLRequest(GURL(url::kAboutBlankURL)));
157 return true;
158 }
159
160 private:
161 RenderView* main_render_view_;
162
163 DISALLOW_COPY_AND_ASSIGN(NavigateAwayVisitor);
164 };
165
166 class UseSynchronousResizeModeVisitor : public RenderViewVisitor {
167 public:
UseSynchronousResizeModeVisitor(bool enable)168 explicit UseSynchronousResizeModeVisitor(bool enable) : enable_(enable) {}
~UseSynchronousResizeModeVisitor()169 virtual ~UseSynchronousResizeModeVisitor() {}
170
Visit(RenderView * render_view)171 virtual bool Visit(RenderView* render_view) OVERRIDE {
172 UseSynchronousResizeMode(render_view, enable_);
173 return true;
174 }
175
176 private:
177 bool enable_;
178 };
179
180 } // namespace
181
WebKitTestRunner(RenderView * render_view)182 WebKitTestRunner::WebKitTestRunner(RenderView* render_view)
183 : RenderViewObserver(render_view),
184 RenderViewObserverTracker<WebKitTestRunner>(render_view),
185 proxy_(NULL),
186 focused_view_(NULL),
187 is_main_window_(false),
188 focus_on_next_commit_(false),
189 leak_detector_(new LeakDetector(this)) {
190 }
191
~WebKitTestRunner()192 WebKitTestRunner::~WebKitTestRunner() {
193 }
194
195 // WebTestDelegate -----------------------------------------------------------
196
ClearEditCommand()197 void WebKitTestRunner::ClearEditCommand() {
198 render_view()->ClearEditCommands();
199 }
200
SetEditCommand(const std::string & name,const std::string & value)201 void WebKitTestRunner::SetEditCommand(const std::string& name,
202 const std::string& value) {
203 render_view()->SetEditCommandForNextKeyEvent(name, value);
204 }
205
SetGamepadProvider(scoped_ptr<RendererGamepadProvider> provider)206 void WebKitTestRunner::SetGamepadProvider(
207 scoped_ptr<RendererGamepadProvider> provider) {
208 SetMockGamepadProvider(provider.Pass());
209 }
210
SetDeviceLightData(const double data)211 void WebKitTestRunner::SetDeviceLightData(const double data) {
212 SetMockDeviceLightData(data);
213 }
214
SetDeviceMotionData(const WebDeviceMotionData & data)215 void WebKitTestRunner::SetDeviceMotionData(const WebDeviceMotionData& data) {
216 SetMockDeviceMotionData(data);
217 }
218
SetDeviceOrientationData(const WebDeviceOrientationData & data)219 void WebKitTestRunner::SetDeviceOrientationData(
220 const WebDeviceOrientationData& data) {
221 SetMockDeviceOrientationData(data);
222 }
223
SetScreenOrientation(const WebScreenOrientationType & orientation)224 void WebKitTestRunner::SetScreenOrientation(
225 const WebScreenOrientationType& orientation) {
226 MockScreenOrientationClient* mock_client =
227 proxy()->GetScreenOrientationClientMock();
228 mock_client->UpdateDeviceOrientation(
229 render_view()->GetWebView()->mainFrame()->toWebLocalFrame(), orientation);
230 }
231
ResetScreenOrientation()232 void WebKitTestRunner::ResetScreenOrientation() {
233 MockScreenOrientationClient* mock_client =
234 proxy()->GetScreenOrientationClientMock();
235 mock_client->ResetData();
236 }
237
DidChangeBatteryStatus(const blink::WebBatteryStatus & status)238 void WebKitTestRunner::DidChangeBatteryStatus(
239 const blink::WebBatteryStatus& status) {
240 MockBatteryStatusChanged(status);
241 }
242
PrintMessage(const std::string & message)243 void WebKitTestRunner::PrintMessage(const std::string& message) {
244 Send(new ShellViewHostMsg_PrintMessage(routing_id(), message));
245 }
246
PostTask(WebTask * task)247 void WebKitTestRunner::PostTask(WebTask* task) {
248 Platform::current()->callOnMainThread(InvokeTaskHelper, task);
249 }
250
PostDelayedTask(WebTask * task,long long ms)251 void WebKitTestRunner::PostDelayedTask(WebTask* task, long long ms) {
252 base::MessageLoop::current()->PostDelayedTask(
253 FROM_HERE,
254 base::Bind(&WebTask::run, base::Owned(task)),
255 base::TimeDelta::FromMilliseconds(ms));
256 }
257
RegisterIsolatedFileSystem(const blink::WebVector<blink::WebString> & absolute_filenames)258 WebString WebKitTestRunner::RegisterIsolatedFileSystem(
259 const blink::WebVector<blink::WebString>& absolute_filenames) {
260 std::vector<base::FilePath> files;
261 for (size_t i = 0; i < absolute_filenames.size(); ++i)
262 files.push_back(base::FilePath::FromUTF16Unsafe(absolute_filenames[i]));
263 std::string filesystem_id;
264 Send(new ShellViewHostMsg_RegisterIsolatedFileSystem(
265 routing_id(), files, &filesystem_id));
266 return WebString::fromUTF8(filesystem_id);
267 }
268
GetCurrentTimeInMillisecond()269 long long WebKitTestRunner::GetCurrentTimeInMillisecond() {
270 return base::TimeDelta(base::Time::Now() -
271 base::Time::UnixEpoch()).ToInternalValue() /
272 base::Time::kMicrosecondsPerMillisecond;
273 }
274
GetAbsoluteWebStringFromUTF8Path(const std::string & utf8_path)275 WebString WebKitTestRunner::GetAbsoluteWebStringFromUTF8Path(
276 const std::string& utf8_path) {
277 base::FilePath path = base::FilePath::FromUTF8Unsafe(utf8_path);
278 if (!path.IsAbsolute()) {
279 GURL base_url =
280 net::FilePathToFileURL(test_config_.current_working_directory.Append(
281 FILE_PATH_LITERAL("foo")));
282 net::FileURLToFilePath(base_url.Resolve(utf8_path), &path);
283 }
284 return path.AsUTF16Unsafe();
285 }
286
LocalFileToDataURL(const WebURL & file_url)287 WebURL WebKitTestRunner::LocalFileToDataURL(const WebURL& file_url) {
288 base::FilePath local_path;
289 if (!net::FileURLToFilePath(file_url, &local_path))
290 return WebURL();
291
292 std::string contents;
293 Send(new ShellViewHostMsg_ReadFileToString(
294 routing_id(), local_path, &contents));
295
296 std::string contents_base64;
297 base::Base64Encode(contents, &contents_base64);
298
299 const char data_url_prefix[] = "data:text/css:charset=utf-8;base64,";
300 return WebURL(GURL(data_url_prefix + contents_base64));
301 }
302
RewriteLayoutTestsURL(const std::string & utf8_url)303 WebURL WebKitTestRunner::RewriteLayoutTestsURL(const std::string& utf8_url) {
304 const char kPrefix[] = "file:///tmp/LayoutTests/";
305 const int kPrefixLen = arraysize(kPrefix) - 1;
306
307 if (utf8_url.compare(0, kPrefixLen, kPrefix, kPrefixLen))
308 return WebURL(GURL(utf8_url));
309
310 base::FilePath replace_path =
311 ShellRenderProcessObserver::GetInstance()->webkit_source_dir().Append(
312 FILE_PATH_LITERAL("LayoutTests/"));
313 #if defined(OS_WIN)
314 std::string utf8_path = base::WideToUTF8(replace_path.value());
315 #else
316 std::string utf8_path =
317 base::WideToUTF8(base::SysNativeMBToWide(replace_path.value()));
318 #endif
319 std::string new_url =
320 std::string("file://") + utf8_path + utf8_url.substr(kPrefixLen);
321 return WebURL(GURL(new_url));
322 }
323
Preferences()324 TestPreferences* WebKitTestRunner::Preferences() {
325 return &prefs_;
326 }
327
ApplyPreferences()328 void WebKitTestRunner::ApplyPreferences() {
329 WebPreferences prefs = render_view()->GetWebkitPreferences();
330 ExportLayoutTestSpecificPreferences(prefs_, &prefs);
331 render_view()->SetWebkitPreferences(prefs);
332 Send(new ShellViewHostMsg_OverridePreferences(routing_id(), prefs));
333 }
334
makeURLErrorDescription(const WebURLError & error)335 std::string WebKitTestRunner::makeURLErrorDescription(
336 const WebURLError& error) {
337 std::string domain = error.domain.utf8();
338 int code = error.reason;
339
340 if (domain == net::kErrorDomain) {
341 domain = "NSURLErrorDomain";
342 switch (error.reason) {
343 case net::ERR_ABORTED:
344 code = -999; // NSURLErrorCancelled
345 break;
346 case net::ERR_UNSAFE_PORT:
347 // Our unsafe port checking happens at the network stack level, but we
348 // make this translation here to match the behavior of stock WebKit.
349 domain = "WebKitErrorDomain";
350 code = 103;
351 break;
352 case net::ERR_ADDRESS_INVALID:
353 case net::ERR_ADDRESS_UNREACHABLE:
354 case net::ERR_NETWORK_ACCESS_DENIED:
355 code = -1004; // NSURLErrorCannotConnectToHost
356 break;
357 }
358 } else {
359 DLOG(WARNING) << "Unknown error domain";
360 }
361
362 return base::StringPrintf("<NSError domain %s, code %d, failing URL \"%s\">",
363 domain.c_str(), code, error.unreachableURL.spec().data());
364 }
365
UseUnfortunateSynchronousResizeMode(bool enable)366 void WebKitTestRunner::UseUnfortunateSynchronousResizeMode(bool enable) {
367 UseSynchronousResizeModeVisitor visitor(enable);
368 RenderView::ForEach(&visitor);
369 }
370
EnableAutoResizeMode(const WebSize & min_size,const WebSize & max_size)371 void WebKitTestRunner::EnableAutoResizeMode(const WebSize& min_size,
372 const WebSize& max_size) {
373 content::EnableAutoResizeMode(render_view(), min_size, max_size);
374 }
375
DisableAutoResizeMode(const WebSize & new_size)376 void WebKitTestRunner::DisableAutoResizeMode(const WebSize& new_size) {
377 content::DisableAutoResizeMode(render_view(), new_size);
378 if (!new_size.isEmpty())
379 ForceResizeRenderView(render_view(), new_size);
380 }
381
ClearDevToolsLocalStorage()382 void WebKitTestRunner::ClearDevToolsLocalStorage() {
383 Send(new ShellViewHostMsg_ClearDevToolsLocalStorage(routing_id()));
384 }
385
ShowDevTools(const std::string & settings,const std::string & frontend_url)386 void WebKitTestRunner::ShowDevTools(const std::string& settings,
387 const std::string& frontend_url) {
388 Send(new ShellViewHostMsg_ShowDevTools(
389 routing_id(), settings, frontend_url));
390 }
391
CloseDevTools()392 void WebKitTestRunner::CloseDevTools() {
393 Send(new ShellViewHostMsg_CloseDevTools(routing_id()));
394 WebDevToolsAgent* agent = render_view()->GetWebView()->devToolsAgent();
395 if (agent)
396 agent->detach();
397 }
398
EvaluateInWebInspector(long call_id,const std::string & script)399 void WebKitTestRunner::EvaluateInWebInspector(long call_id,
400 const std::string& script) {
401 WebDevToolsAgent* agent = render_view()->GetWebView()->devToolsAgent();
402 if (agent)
403 agent->evaluateInWebInspector(call_id, WebString::fromUTF8(script));
404 }
405
ClearAllDatabases()406 void WebKitTestRunner::ClearAllDatabases() {
407 Send(new ShellViewHostMsg_ClearAllDatabases(routing_id()));
408 }
409
SetDatabaseQuota(int quota)410 void WebKitTestRunner::SetDatabaseQuota(int quota) {
411 Send(new ShellViewHostMsg_SetDatabaseQuota(routing_id(), quota));
412 }
413
414 blink::WebNotificationPresenter::Permission
CheckWebNotificationPermission(const GURL & origin)415 WebKitTestRunner::CheckWebNotificationPermission(const GURL& origin) {
416 int permission = blink::WebNotificationPresenter::PermissionNotAllowed;
417 Send(new ShellViewHostMsg_CheckWebNotificationPermission(
418 routing_id(),
419 origin,
420 &permission));
421 return static_cast<blink::WebNotificationPresenter::Permission>(permission);
422 }
423
GrantWebNotificationPermission(const GURL & origin,bool permission_granted)424 void WebKitTestRunner::GrantWebNotificationPermission(const GURL& origin,
425 bool permission_granted) {
426 Send(new ShellViewHostMsg_GrantWebNotificationPermission(
427 routing_id(), origin, permission_granted));
428 }
429
ClearWebNotificationPermissions()430 void WebKitTestRunner::ClearWebNotificationPermissions() {
431 Send(new ShellViewHostMsg_ClearWebNotificationPermissions(routing_id()));
432 }
433
SetDeviceScaleFactor(float factor)434 void WebKitTestRunner::SetDeviceScaleFactor(float factor) {
435 content::SetDeviceScaleFactor(render_view(), factor);
436 }
437
SetDeviceColorProfile(const std::string & name)438 void WebKitTestRunner::SetDeviceColorProfile(const std::string& name) {
439 content::SetDeviceColorProfile(render_view(), name);
440 }
441
SetFocus(WebTestProxyBase * proxy,bool focus)442 void WebKitTestRunner::SetFocus(WebTestProxyBase* proxy, bool focus) {
443 ProxyToRenderViewVisitor visitor(proxy);
444 RenderView::ForEach(&visitor);
445 if (!visitor.render_view()) {
446 NOTREACHED();
447 return;
448 }
449
450 // Check whether the focused view was closed meanwhile.
451 if (!WebKitTestRunner::Get(focused_view_))
452 focused_view_ = NULL;
453
454 if (focus) {
455 if (focused_view_ != visitor.render_view()) {
456 if (focused_view_)
457 SetFocusAndActivate(focused_view_, false);
458 SetFocusAndActivate(visitor.render_view(), true);
459 focused_view_ = visitor.render_view();
460 }
461 } else {
462 if (focused_view_ == visitor.render_view()) {
463 SetFocusAndActivate(visitor.render_view(), false);
464 focused_view_ = NULL;
465 }
466 }
467 }
468
SetAcceptAllCookies(bool accept)469 void WebKitTestRunner::SetAcceptAllCookies(bool accept) {
470 Send(new ShellViewHostMsg_AcceptAllCookies(routing_id(), accept));
471 }
472
PathToLocalResource(const std::string & resource)473 std::string WebKitTestRunner::PathToLocalResource(const std::string& resource) {
474 #if defined(OS_WIN)
475 if (resource.find("/tmp/") == 0) {
476 // We want a temp file.
477 GURL base_url = net::FilePathToFileURL(test_config_.temp_path);
478 return base_url.Resolve(resource.substr(strlen("/tmp/"))).spec();
479 }
480 #endif
481
482 // Some layout tests use file://// which we resolve as a UNC path. Normalize
483 // them to just file:///.
484 std::string result = resource;
485 while (base::StringToLowerASCII(result).find("file:////") == 0) {
486 result = result.substr(0, strlen("file:///")) +
487 result.substr(strlen("file:////"));
488 }
489 return RewriteLayoutTestsURL(result).spec();
490 }
491
SetLocale(const std::string & locale)492 void WebKitTestRunner::SetLocale(const std::string& locale) {
493 setlocale(LC_ALL, locale.c_str());
494 }
495
TestFinished()496 void WebKitTestRunner::TestFinished() {
497 if (!is_main_window_) {
498 Send(new ShellViewHostMsg_TestFinishedInSecondaryWindow(routing_id()));
499 return;
500 }
501 WebTestInterfaces* interfaces =
502 ShellRenderProcessObserver::GetInstance()->test_interfaces();
503 interfaces->SetTestIsRunning(false);
504 if (interfaces->TestRunner()->ShouldDumpBackForwardList()) {
505 SyncNavigationStateVisitor visitor;
506 RenderView::ForEach(&visitor);
507 Send(new ShellViewHostMsg_CaptureSessionHistory(routing_id()));
508 } else {
509 CaptureDump();
510 }
511 }
512
CloseRemainingWindows()513 void WebKitTestRunner::CloseRemainingWindows() {
514 NavigateAwayVisitor visitor(render_view());
515 RenderView::ForEach(&visitor);
516 Send(new ShellViewHostMsg_CloseRemainingWindows(routing_id()));
517 }
518
DeleteAllCookies()519 void WebKitTestRunner::DeleteAllCookies() {
520 Send(new ShellViewHostMsg_DeleteAllCookies(routing_id()));
521 }
522
NavigationEntryCount()523 int WebKitTestRunner::NavigationEntryCount() {
524 return GetLocalSessionHistoryLength(render_view());
525 }
526
GoToOffset(int offset)527 void WebKitTestRunner::GoToOffset(int offset) {
528 Send(new ShellViewHostMsg_GoToOffset(routing_id(), offset));
529 }
530
Reload()531 void WebKitTestRunner::Reload() {
532 Send(new ShellViewHostMsg_Reload(routing_id()));
533 }
534
LoadURLForFrame(const WebURL & url,const std::string & frame_name)535 void WebKitTestRunner::LoadURLForFrame(const WebURL& url,
536 const std::string& frame_name) {
537 Send(new ShellViewHostMsg_LoadURLForFrame(
538 routing_id(), url, frame_name));
539 }
540
AllowExternalPages()541 bool WebKitTestRunner::AllowExternalPages() {
542 return test_config_.allow_external_pages;
543 }
544
DumpHistoryForWindow(WebTestProxyBase * proxy)545 std::string WebKitTestRunner::DumpHistoryForWindow(WebTestProxyBase* proxy) {
546 size_t pos = 0;
547 std::vector<int>::iterator id;
548 for (id = routing_ids_.begin(); id != routing_ids_.end(); ++id, ++pos) {
549 RenderView* render_view = RenderView::FromRoutingID(*id);
550 if (!render_view) {
551 NOTREACHED();
552 continue;
553 }
554 if (WebKitTestRunner::Get(render_view)->proxy() == proxy)
555 break;
556 }
557
558 if (id == routing_ids_.end()) {
559 NOTREACHED();
560 return std::string();
561 }
562 return DumpBackForwardList(session_histories_[pos],
563 current_entry_indexes_[pos]);
564 }
565
566 // RenderViewObserver --------------------------------------------------------
567
DidClearWindowObject(WebLocalFrame * frame)568 void WebKitTestRunner::DidClearWindowObject(WebLocalFrame* frame) {
569 WebTestingSupport::injectInternalsObject(frame);
570 ShellRenderProcessObserver::GetInstance()->test_interfaces()->BindTo(frame);
571 GCController::Install(frame);
572 }
573
OnMessageReceived(const IPC::Message & message)574 bool WebKitTestRunner::OnMessageReceived(const IPC::Message& message) {
575 bool handled = true;
576 IPC_BEGIN_MESSAGE_MAP(WebKitTestRunner, message)
577 IPC_MESSAGE_HANDLER(ShellViewMsg_SetTestConfiguration,
578 OnSetTestConfiguration)
579 IPC_MESSAGE_HANDLER(ShellViewMsg_SessionHistory, OnSessionHistory)
580 IPC_MESSAGE_HANDLER(ShellViewMsg_Reset, OnReset)
581 IPC_MESSAGE_HANDLER(ShellViewMsg_NotifyDone, OnNotifyDone)
582 IPC_MESSAGE_HANDLER(ShellViewMsg_TryLeakDetection, OnTryLeakDetection)
583 IPC_MESSAGE_UNHANDLED(handled = false)
584 IPC_END_MESSAGE_MAP()
585
586 return handled;
587 }
588
Navigate(const GURL & url)589 void WebKitTestRunner::Navigate(const GURL& url) {
590 focus_on_next_commit_ = true;
591 if (!is_main_window_ &&
592 ShellRenderProcessObserver::GetInstance()->main_test_runner() == this) {
593 WebTestInterfaces* interfaces =
594 ShellRenderProcessObserver::GetInstance()->test_interfaces();
595 interfaces->SetTestIsRunning(true);
596 interfaces->ConfigureForTestWithURL(GURL(), false);
597 ForceResizeRenderView(render_view(), WebSize(800, 600));
598 }
599 }
600
DidCommitProvisionalLoad(WebLocalFrame * frame,bool is_new_navigation)601 void WebKitTestRunner::DidCommitProvisionalLoad(WebLocalFrame* frame,
602 bool is_new_navigation) {
603 if (!focus_on_next_commit_)
604 return;
605 focus_on_next_commit_ = false;
606 render_view()->GetWebView()->setFocusedFrame(frame);
607 }
608
DidFailProvisionalLoad(WebLocalFrame * frame,const WebURLError & error)609 void WebKitTestRunner::DidFailProvisionalLoad(WebLocalFrame* frame,
610 const WebURLError& error) {
611 focus_on_next_commit_ = false;
612 }
613
614 // Public methods - -----------------------------------------------------------
615
Reset()616 void WebKitTestRunner::Reset() {
617 // The proxy_ is always non-NULL, it is set right after construction.
618 proxy_->set_widget(render_view()->GetWebView());
619 proxy_->Reset();
620 prefs_.Reset();
621 routing_ids_.clear();
622 session_histories_.clear();
623 current_entry_indexes_.clear();
624
625 render_view()->ClearEditCommands();
626 render_view()->GetWebView()->mainFrame()->setName(WebString());
627 render_view()->GetWebView()->mainFrame()->clearOpener();
628 render_view()->GetWebView()->setPageScaleFactorLimits(-1, -1);
629 render_view()->GetWebView()->setPageScaleFactor(1, WebPoint(0, 0));
630
631 // Resetting the internals object also overrides the WebPreferences, so we
632 // have to sync them to WebKit again.
633 WebTestingSupport::resetInternalsObject(
634 render_view()->GetWebView()->mainFrame()->toWebLocalFrame());
635 render_view()->SetWebkitPreferences(render_view()->GetWebkitPreferences());
636 }
637
638 // Private methods -----------------------------------------------------------
639
CaptureDump()640 void WebKitTestRunner::CaptureDump() {
641 WebTestInterfaces* interfaces =
642 ShellRenderProcessObserver::GetInstance()->test_interfaces();
643 TRACE_EVENT0("shell", "WebKitTestRunner::CaptureDump");
644
645 if (interfaces->TestRunner()->ShouldDumpAsAudio()) {
646 std::vector<unsigned char> vector_data;
647 interfaces->TestRunner()->GetAudioData(&vector_data);
648 Send(new ShellViewHostMsg_AudioDump(routing_id(), vector_data));
649 } else {
650 Send(new ShellViewHostMsg_TextDump(routing_id(),
651 proxy()->CaptureTree(false)));
652
653 if (test_config_.enable_pixel_dumping &&
654 interfaces->TestRunner()->ShouldGeneratePixelResults()) {
655 CHECK(render_view()->GetWebView()->isAcceleratedCompositingActive());
656 proxy()->CapturePixelsAsync(base::Bind(
657 &WebKitTestRunner::CaptureDumpPixels, base::Unretained(this)));
658 return;
659 }
660 }
661
662 CaptureDumpComplete();
663 }
664
CaptureDumpPixels(const SkBitmap & snapshot)665 void WebKitTestRunner::CaptureDumpPixels(const SkBitmap& snapshot) {
666 DCHECK_NE(0, snapshot.info().fWidth);
667 DCHECK_NE(0, snapshot.info().fHeight);
668
669 SkAutoLockPixels snapshot_lock(snapshot);
670 // The snapshot arrives from the GPU process via shared memory. Because MSan
671 // can't track initializedness across processes, we must assure it that the
672 // pixels are in fact initialized.
673 MSAN_UNPOISON(snapshot.getPixels(), snapshot.getSize());
674 base::MD5Digest digest;
675 base::MD5Sum(snapshot.getPixels(), snapshot.getSize(), &digest);
676 std::string actual_pixel_hash = base::MD5DigestToBase16(digest);
677
678 if (actual_pixel_hash == test_config_.expected_pixel_hash) {
679 SkBitmap empty_image;
680 Send(new ShellViewHostMsg_ImageDump(
681 routing_id(), actual_pixel_hash, empty_image));
682 } else {
683 Send(new ShellViewHostMsg_ImageDump(
684 routing_id(), actual_pixel_hash, snapshot));
685 }
686
687 CaptureDumpComplete();
688 }
689
CaptureDumpComplete()690 void WebKitTestRunner::CaptureDumpComplete() {
691 render_view()->GetWebView()->mainFrame()->stopLoading();
692
693 base::MessageLoop::current()->PostTask(
694 FROM_HERE,
695 base::Bind(base::IgnoreResult(&WebKitTestRunner::Send),
696 base::Unretained(this),
697 new ShellViewHostMsg_TestFinished(routing_id())));
698 }
699
OnSetTestConfiguration(const ShellTestConfiguration & params)700 void WebKitTestRunner::OnSetTestConfiguration(
701 const ShellTestConfiguration& params) {
702 test_config_ = params;
703 is_main_window_ = true;
704
705 ForceResizeRenderView(
706 render_view(),
707 WebSize(params.initial_size.width(), params.initial_size.height()));
708 SetFocus(proxy_, true);
709
710 WebTestInterfaces* interfaces =
711 ShellRenderProcessObserver::GetInstance()->test_interfaces();
712 interfaces->SetTestIsRunning(true);
713 interfaces->ConfigureForTestWithURL(params.test_url,
714 params.enable_pixel_dumping);
715 }
716
OnSessionHistory(const std::vector<int> & routing_ids,const std::vector<std::vector<PageState>> & session_histories,const std::vector<unsigned> & current_entry_indexes)717 void WebKitTestRunner::OnSessionHistory(
718 const std::vector<int>& routing_ids,
719 const std::vector<std::vector<PageState> >& session_histories,
720 const std::vector<unsigned>& current_entry_indexes) {
721 routing_ids_ = routing_ids;
722 session_histories_ = session_histories;
723 current_entry_indexes_ = current_entry_indexes;
724 CaptureDump();
725 }
726
OnReset()727 void WebKitTestRunner::OnReset() {
728 ShellRenderProcessObserver::GetInstance()->test_interfaces()->ResetAll();
729 Reset();
730 // Navigating to about:blank will make sure that no new loads are initiated
731 // by the renderer.
732 render_view()->GetWebView()->mainFrame()->loadRequest(
733 WebURLRequest(GURL(url::kAboutBlankURL)));
734 Send(new ShellViewHostMsg_ResetDone(routing_id()));
735 }
736
OnNotifyDone()737 void WebKitTestRunner::OnNotifyDone() {
738 render_view()->GetWebView()->mainFrame()->executeScript(
739 WebScriptSource(WebString::fromUTF8("testRunner.notifyDone();")));
740 }
741
OnTryLeakDetection()742 void WebKitTestRunner::OnTryLeakDetection() {
743 WebLocalFrame* main_frame =
744 render_view()->GetWebView()->mainFrame()->toWebLocalFrame();
745 DCHECK_EQ(GURL(url::kAboutBlankURL), GURL(main_frame->document().url()));
746 DCHECK(!main_frame->isLoading());
747
748 leak_detector_->TryLeakDetection(main_frame);
749 }
750
ReportLeakDetectionResult(const LeakDetectionResult & report)751 void WebKitTestRunner::ReportLeakDetectionResult(
752 const LeakDetectionResult& report) {
753 Send(new ShellViewHostMsg_LeakDetectionDone(routing_id(), report));
754 }
755
756 } // namespace content
757