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 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: 105 SyncNavigationStateVisitor() {} 106 virtual ~SyncNavigationStateVisitor() {} 107 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: 118 explicit ProxyToRenderViewVisitor(WebTestProxyBase* proxy) 119 : proxy_(proxy), 120 render_view_(NULL) { 121 } 122 virtual ~ProxyToRenderViewVisitor() {} 123 124 RenderView* render_view() const { return render_view_; } 125 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: 148 explicit NavigateAwayVisitor(RenderView* main_render_view) 149 : main_render_view_(main_render_view) {} 150 virtual ~NavigateAwayVisitor() {} 151 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: 168 explicit UseSynchronousResizeModeVisitor(bool enable) : enable_(enable) {} 169 virtual ~UseSynchronousResizeModeVisitor() {} 170 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 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 192 WebKitTestRunner::~WebKitTestRunner() { 193 } 194 195 // WebTestDelegate ----------------------------------------------------------- 196 197 void WebKitTestRunner::ClearEditCommand() { 198 render_view()->ClearEditCommands(); 199 } 200 201 void WebKitTestRunner::SetEditCommand(const std::string& name, 202 const std::string& value) { 203 render_view()->SetEditCommandForNextKeyEvent(name, value); 204 } 205 206 void WebKitTestRunner::SetGamepadProvider( 207 scoped_ptr<RendererGamepadProvider> provider) { 208 SetMockGamepadProvider(provider.Pass()); 209 } 210 211 void WebKitTestRunner::SetDeviceLightData(const double data) { 212 SetMockDeviceLightData(data); 213 } 214 215 void WebKitTestRunner::SetDeviceMotionData(const WebDeviceMotionData& data) { 216 SetMockDeviceMotionData(data); 217 } 218 219 void WebKitTestRunner::SetDeviceOrientationData( 220 const WebDeviceOrientationData& data) { 221 SetMockDeviceOrientationData(data); 222 } 223 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 232 void WebKitTestRunner::ResetScreenOrientation() { 233 MockScreenOrientationClient* mock_client = 234 proxy()->GetScreenOrientationClientMock(); 235 mock_client->ResetData(); 236 } 237 238 void WebKitTestRunner::DidChangeBatteryStatus( 239 const blink::WebBatteryStatus& status) { 240 MockBatteryStatusChanged(status); 241 } 242 243 void WebKitTestRunner::PrintMessage(const std::string& message) { 244 Send(new ShellViewHostMsg_PrintMessage(routing_id(), message)); 245 } 246 247 void WebKitTestRunner::PostTask(WebTask* task) { 248 Platform::current()->callOnMainThread(InvokeTaskHelper, task); 249 } 250 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 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 269 long long WebKitTestRunner::GetCurrentTimeInMillisecond() { 270 return base::TimeDelta(base::Time::Now() - 271 base::Time::UnixEpoch()).ToInternalValue() / 272 base::Time::kMicrosecondsPerMillisecond; 273 } 274 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 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 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 324 TestPreferences* WebKitTestRunner::Preferences() { 325 return &prefs_; 326 } 327 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 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 366 void WebKitTestRunner::UseUnfortunateSynchronousResizeMode(bool enable) { 367 UseSynchronousResizeModeVisitor visitor(enable); 368 RenderView::ForEach(&visitor); 369 } 370 371 void WebKitTestRunner::EnableAutoResizeMode(const WebSize& min_size, 372 const WebSize& max_size) { 373 content::EnableAutoResizeMode(render_view(), min_size, max_size); 374 } 375 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 382 void WebKitTestRunner::ClearDevToolsLocalStorage() { 383 Send(new ShellViewHostMsg_ClearDevToolsLocalStorage(routing_id())); 384 } 385 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 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 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 406 void WebKitTestRunner::ClearAllDatabases() { 407 Send(new ShellViewHostMsg_ClearAllDatabases(routing_id())); 408 } 409 410 void WebKitTestRunner::SetDatabaseQuota(int quota) { 411 Send(new ShellViewHostMsg_SetDatabaseQuota(routing_id(), quota)); 412 } 413 414 blink::WebNotificationPresenter::Permission 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 424 void WebKitTestRunner::GrantWebNotificationPermission(const GURL& origin, 425 bool permission_granted) { 426 Send(new ShellViewHostMsg_GrantWebNotificationPermission( 427 routing_id(), origin, permission_granted)); 428 } 429 430 void WebKitTestRunner::ClearWebNotificationPermissions() { 431 Send(new ShellViewHostMsg_ClearWebNotificationPermissions(routing_id())); 432 } 433 434 void WebKitTestRunner::SetDeviceScaleFactor(float factor) { 435 content::SetDeviceScaleFactor(render_view(), factor); 436 } 437 438 void WebKitTestRunner::SetDeviceColorProfile(const std::string& name) { 439 content::SetDeviceColorProfile(render_view(), name); 440 } 441 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 469 void WebKitTestRunner::SetAcceptAllCookies(bool accept) { 470 Send(new ShellViewHostMsg_AcceptAllCookies(routing_id(), accept)); 471 } 472 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 492 void WebKitTestRunner::SetLocale(const std::string& locale) { 493 setlocale(LC_ALL, locale.c_str()); 494 } 495 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 513 void WebKitTestRunner::CloseRemainingWindows() { 514 NavigateAwayVisitor visitor(render_view()); 515 RenderView::ForEach(&visitor); 516 Send(new ShellViewHostMsg_CloseRemainingWindows(routing_id())); 517 } 518 519 void WebKitTestRunner::DeleteAllCookies() { 520 Send(new ShellViewHostMsg_DeleteAllCookies(routing_id())); 521 } 522 523 int WebKitTestRunner::NavigationEntryCount() { 524 return GetLocalSessionHistoryLength(render_view()); 525 } 526 527 void WebKitTestRunner::GoToOffset(int offset) { 528 Send(new ShellViewHostMsg_GoToOffset(routing_id(), offset)); 529 } 530 531 void WebKitTestRunner::Reload() { 532 Send(new ShellViewHostMsg_Reload(routing_id())); 533 } 534 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 541 bool WebKitTestRunner::AllowExternalPages() { 542 return test_config_.allow_external_pages; 543 } 544 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 568 void WebKitTestRunner::DidClearWindowObject(WebLocalFrame* frame) { 569 WebTestingSupport::injectInternalsObject(frame); 570 ShellRenderProcessObserver::GetInstance()->test_interfaces()->BindTo(frame); 571 GCController::Install(frame); 572 } 573 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 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 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 609 void WebKitTestRunner::DidFailProvisionalLoad(WebLocalFrame* frame, 610 const WebURLError& error) { 611 focus_on_next_commit_ = false; 612 } 613 614 // Public methods - ----------------------------------------------------------- 615 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 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 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 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 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 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 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 737 void WebKitTestRunner::OnNotifyDone() { 738 render_view()->GetWebView()->mainFrame()->executeScript( 739 WebScriptSource(WebString::fromUTF8("testRunner.notifyDone();"))); 740 } 741 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 751 void WebKitTestRunner::ReportLeakDetectionResult( 752 const LeakDetectionResult& report) { 753 Send(new ShellViewHostMsg_LeakDetectionDone(routing_id(), report)); 754 } 755 756 } // namespace content 757