1 // Copyright 2013 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/browser/webkit_test_controller.h" 6 7 #include <iostream> 8 9 #include "base/base64.h" 10 #include "base/command_line.h" 11 #include "base/message_loop/message_loop.h" 12 #include "base/run_loop.h" 13 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/stringprintf.h" 15 #include "content/public/browser/devtools_manager.h" 16 #include "content/public/browser/dom_storage_context.h" 17 #include "content/public/browser/gpu_data_manager.h" 18 #include "content/public/browser/navigation_controller.h" 19 #include "content/public/browser/navigation_entry.h" 20 #include "content/public/browser/notification_service.h" 21 #include "content/public/browser/notification_types.h" 22 #include "content/public/browser/render_process_host.h" 23 #include "content/public/browser/render_view_host.h" 24 #include "content/public/browser/render_widget_host_view.h" 25 #include "content/public/browser/storage_partition.h" 26 #include "content/public/browser/web_contents.h" 27 #include "content/public/common/content_switches.h" 28 #include "content/public/common/url_constants.h" 29 #include "content/shell/browser/shell.h" 30 #include "content/shell/browser/shell_browser_context.h" 31 #include "content/shell/browser/shell_content_browser_client.h" 32 #include "content/shell/browser/shell_devtools_frontend.h" 33 #include "content/shell/common/shell_messages.h" 34 #include "content/shell/common/shell_switches.h" 35 #include "content/shell/common/webkit_test_helpers.h" 36 #include "ui/gfx/codec/png_codec.h" 37 38 namespace content { 39 40 const int kTestSVGWindowWidthDip = 480; 41 const int kTestSVGWindowHeightDip = 360; 42 43 // WebKitTestResultPrinter ---------------------------------------------------- 44 45 WebKitTestResultPrinter::WebKitTestResultPrinter( 46 std::ostream* output, std::ostream* error) 47 : state_(DURING_TEST), 48 capture_text_only_(false), 49 encode_binary_data_(false), 50 output_(output), 51 error_(error) { 52 } 53 54 WebKitTestResultPrinter::~WebKitTestResultPrinter() { 55 } 56 57 void WebKitTestResultPrinter::PrintTextHeader() { 58 if (state_ != DURING_TEST) 59 return; 60 if (!capture_text_only_) 61 *output_ << "Content-Type: text/plain\n"; 62 state_ = IN_TEXT_BLOCK; 63 } 64 65 void WebKitTestResultPrinter::PrintTextBlock(const std::string& block) { 66 if (state_ != IN_TEXT_BLOCK) 67 return; 68 *output_ << block; 69 } 70 71 void WebKitTestResultPrinter::PrintTextFooter() { 72 if (state_ != IN_TEXT_BLOCK) 73 return; 74 if (!capture_text_only_) { 75 *output_ << "#EOF\n"; 76 output_->flush(); 77 } 78 state_ = IN_IMAGE_BLOCK; 79 } 80 81 void WebKitTestResultPrinter::PrintImageHeader( 82 const std::string& actual_hash, 83 const std::string& expected_hash) { 84 if (state_ != IN_IMAGE_BLOCK || capture_text_only_) 85 return; 86 *output_ << "\nActualHash: " << actual_hash << "\n"; 87 if (!expected_hash.empty()) 88 *output_ << "\nExpectedHash: " << expected_hash << "\n"; 89 } 90 91 void WebKitTestResultPrinter::PrintImageBlock( 92 const std::vector<unsigned char>& png_image) { 93 if (state_ != IN_IMAGE_BLOCK || capture_text_only_) 94 return; 95 *output_ << "Content-Type: image/png\n"; 96 if (encode_binary_data_) { 97 PrintEncodedBinaryData(png_image); 98 return; 99 } 100 101 *output_ << "Content-Length: " << png_image.size() << "\n"; 102 output_->write( 103 reinterpret_cast<const char*>(&png_image[0]), png_image.size()); 104 } 105 106 void WebKitTestResultPrinter::PrintImageFooter() { 107 if (state_ != IN_IMAGE_BLOCK) 108 return; 109 if (!capture_text_only_) { 110 *output_ << "#EOF\n"; 111 output_->flush(); 112 } 113 state_ = AFTER_TEST; 114 } 115 116 void WebKitTestResultPrinter::PrintAudioHeader() { 117 DCHECK_EQ(state_, DURING_TEST); 118 if (!capture_text_only_) 119 *output_ << "Content-Type: audio/wav\n"; 120 state_ = IN_AUDIO_BLOCK; 121 } 122 123 void WebKitTestResultPrinter::PrintAudioBlock( 124 const std::vector<unsigned char>& audio_data) { 125 if (state_ != IN_AUDIO_BLOCK || capture_text_only_) 126 return; 127 if (encode_binary_data_) { 128 PrintEncodedBinaryData(audio_data); 129 return; 130 } 131 132 *output_ << "Content-Length: " << audio_data.size() << "\n"; 133 output_->write( 134 reinterpret_cast<const char*>(&audio_data[0]), audio_data.size()); 135 } 136 137 void WebKitTestResultPrinter::PrintAudioFooter() { 138 if (state_ != IN_AUDIO_BLOCK) 139 return; 140 if (!capture_text_only_) { 141 *output_ << "#EOF\n"; 142 output_->flush(); 143 } 144 state_ = IN_IMAGE_BLOCK; 145 } 146 147 void WebKitTestResultPrinter::AddMessage(const std::string& message) { 148 AddMessageRaw(message + "\n"); 149 } 150 151 void WebKitTestResultPrinter::AddMessageRaw(const std::string& message) { 152 if (state_ != DURING_TEST) 153 return; 154 *output_ << message; 155 } 156 157 void WebKitTestResultPrinter::AddErrorMessage(const std::string& message) { 158 if (!capture_text_only_) 159 *error_ << message << "\n"; 160 if (state_ != DURING_TEST) 161 return; 162 PrintTextHeader(); 163 *output_ << message << "\n"; 164 PrintTextFooter(); 165 PrintImageFooter(); 166 } 167 168 void WebKitTestResultPrinter::PrintEncodedBinaryData( 169 const std::vector<unsigned char>& data) { 170 *output_ << "Content-Transfer-Encoding: base64\n"; 171 172 std::string data_base64; 173 base::Base64Encode( 174 base::StringPiece(reinterpret_cast<const char*>(&data[0]), data.size()), 175 &data_base64); 176 177 *output_ << "Content-Length: " << data_base64.length() << "\n"; 178 output_->write(data_base64.c_str(), data_base64.length()); 179 } 180 181 void WebKitTestResultPrinter::CloseStderr() { 182 if (state_ != AFTER_TEST) 183 return; 184 if (!capture_text_only_) { 185 *error_ << "#EOF\n"; 186 error_->flush(); 187 } 188 } 189 190 191 // WebKitTestController ------------------------------------------------------- 192 193 WebKitTestController* WebKitTestController::instance_ = NULL; 194 195 // static 196 WebKitTestController* WebKitTestController::Get() { 197 DCHECK(instance_); 198 return instance_; 199 } 200 201 WebKitTestController::WebKitTestController() 202 : main_window_(NULL), 203 test_phase_(BETWEEN_TESTS), 204 is_leak_detection_enabled_(CommandLine::ForCurrentProcess()->HasSwitch( 205 switches::kEnableLeakDetection)) { 206 CHECK(!instance_); 207 instance_ = this; 208 printer_.reset(new WebKitTestResultPrinter(&std::cout, &std::cerr)); 209 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEncodeBinary)) 210 printer_->set_encode_binary_data(true); 211 registrar_.Add(this, 212 NOTIFICATION_RENDERER_PROCESS_CREATED, 213 NotificationService::AllSources()); 214 GpuDataManager::GetInstance()->AddObserver(this); 215 ResetAfterLayoutTest(); 216 } 217 218 WebKitTestController::~WebKitTestController() { 219 DCHECK(CalledOnValidThread()); 220 CHECK(instance_ == this); 221 CHECK(test_phase_ == BETWEEN_TESTS); 222 GpuDataManager::GetInstance()->RemoveObserver(this); 223 DiscardMainWindow(); 224 instance_ = NULL; 225 } 226 227 bool WebKitTestController::PrepareForLayoutTest( 228 const GURL& test_url, 229 const base::FilePath& current_working_directory, 230 bool enable_pixel_dumping, 231 const std::string& expected_pixel_hash) { 232 DCHECK(CalledOnValidThread()); 233 test_phase_ = DURING_TEST; 234 current_working_directory_ = current_working_directory; 235 enable_pixel_dumping_ = enable_pixel_dumping; 236 expected_pixel_hash_ = expected_pixel_hash; 237 test_url_ = test_url; 238 printer_->reset(); 239 ShellBrowserContext* browser_context = 240 ShellContentBrowserClient::Get()->browser_context(); 241 if (test_url.spec().find("compositing/") != std::string::npos) 242 is_compositing_test_ = true; 243 initial_size_ = gfx::Size( 244 Shell::kDefaultTestWindowWidthDip, Shell::kDefaultTestWindowHeightDip); 245 // The W3C SVG layout tests use a different size than the other layout tests. 246 if (test_url.spec().find("W3C-SVG-1.1") != std::string::npos) 247 initial_size_ = gfx::Size(kTestSVGWindowWidthDip, kTestSVGWindowHeightDip); 248 if (!main_window_) { 249 main_window_ = content::Shell::CreateNewWindow( 250 browser_context, 251 GURL(), 252 NULL, 253 MSG_ROUTING_NONE, 254 initial_size_); 255 WebContentsObserver::Observe(main_window_->web_contents()); 256 send_configuration_to_next_host_ = true; 257 current_pid_ = base::kNullProcessId; 258 main_window_->LoadURL(test_url); 259 } else { 260 #if defined(OS_MACOSX) 261 // Shell::SizeTo is not implemented on all platforms. 262 main_window_->SizeTo(initial_size_); 263 #endif 264 main_window_->web_contents()->GetRenderViewHost()->GetView() 265 ->SetSize(initial_size_); 266 main_window_->web_contents()->GetRenderViewHost()->WasResized(); 267 RenderViewHost* render_view_host = 268 main_window_->web_contents()->GetRenderViewHost(); 269 WebPreferences prefs = render_view_host->GetWebkitPreferences(); 270 OverrideWebkitPrefs(&prefs); 271 render_view_host->UpdateWebkitPreferences(prefs); 272 SendTestConfiguration(); 273 274 NavigationController::LoadURLParams params(test_url); 275 params.transition_type = PageTransitionFromInt( 276 PAGE_TRANSITION_TYPED | PAGE_TRANSITION_FROM_ADDRESS_BAR); 277 params.should_clear_history_list = true; 278 main_window_->web_contents()->GetController().LoadURLWithParams(params); 279 main_window_->web_contents()->Focus(); 280 } 281 main_window_->web_contents()->GetRenderViewHost()->SetActive(true); 282 main_window_->web_contents()->GetRenderViewHost()->Focus(); 283 return true; 284 } 285 286 bool WebKitTestController::ResetAfterLayoutTest() { 287 DCHECK(CalledOnValidThread()); 288 printer_->PrintTextFooter(); 289 printer_->PrintImageFooter(); 290 printer_->CloseStderr(); 291 send_configuration_to_next_host_ = false; 292 test_phase_ = BETWEEN_TESTS; 293 is_compositing_test_ = false; 294 enable_pixel_dumping_ = false; 295 expected_pixel_hash_.clear(); 296 test_url_ = GURL(); 297 prefs_ = WebPreferences(); 298 should_override_prefs_ = false; 299 300 #if defined(OS_ANDROID) 301 // Re-using the shell's main window on Android causes issues with networking 302 // requests never succeeding. See http://crbug.com/277652. 303 DiscardMainWindow(); 304 #endif 305 return true; 306 } 307 308 void WebKitTestController::SetTempPath(const base::FilePath& temp_path) { 309 temp_path_ = temp_path; 310 } 311 312 void WebKitTestController::RendererUnresponsive() { 313 DCHECK(CalledOnValidThread()); 314 LOG(WARNING) << "renderer unresponsive"; 315 } 316 317 void WebKitTestController::WorkerCrashed() { 318 DCHECK(CalledOnValidThread()); 319 printer_->AddErrorMessage("#CRASHED - worker"); 320 DiscardMainWindow(); 321 } 322 323 void WebKitTestController::OverrideWebkitPrefs(WebPreferences* prefs) { 324 if (should_override_prefs_) { 325 *prefs = prefs_; 326 } else { 327 ApplyLayoutTestDefaultPreferences(prefs); 328 if (is_compositing_test_) { 329 CommandLine& command_line = *CommandLine::ForCurrentProcess(); 330 if (!command_line.HasSwitch(switches::kDisableGpu)) 331 prefs->accelerated_2d_canvas_enabled = true; 332 prefs->accelerated_compositing_for_video_enabled = true; 333 prefs->mock_scrollbars_enabled = true; 334 } 335 } 336 } 337 338 void WebKitTestController::OpenURL(const GURL& url) { 339 if (test_phase_ != DURING_TEST) 340 return; 341 342 Shell::CreateNewWindow(main_window_->web_contents()->GetBrowserContext(), 343 url, 344 main_window_->web_contents()->GetSiteInstance(), 345 MSG_ROUTING_NONE, 346 gfx::Size()); 347 } 348 349 void WebKitTestController::TestFinishedInSecondaryWindow() { 350 RenderViewHost* render_view_host = 351 main_window_->web_contents()->GetRenderViewHost(); 352 render_view_host->Send( 353 new ShellViewMsg_NotifyDone(render_view_host->GetRoutingID())); 354 } 355 356 bool WebKitTestController::IsMainWindow(WebContents* web_contents) const { 357 return main_window_ && web_contents == main_window_->web_contents(); 358 } 359 360 bool WebKitTestController::OnMessageReceived(const IPC::Message& message) { 361 DCHECK(CalledOnValidThread()); 362 bool handled = true; 363 IPC_BEGIN_MESSAGE_MAP(WebKitTestController, message) 364 IPC_MESSAGE_HANDLER(ShellViewHostMsg_PrintMessage, OnPrintMessage) 365 IPC_MESSAGE_HANDLER(ShellViewHostMsg_TextDump, OnTextDump) 366 IPC_MESSAGE_HANDLER(ShellViewHostMsg_ImageDump, OnImageDump) 367 IPC_MESSAGE_HANDLER(ShellViewHostMsg_AudioDump, OnAudioDump) 368 IPC_MESSAGE_HANDLER(ShellViewHostMsg_OverridePreferences, 369 OnOverridePreferences) 370 IPC_MESSAGE_HANDLER(ShellViewHostMsg_TestFinished, OnTestFinished) 371 IPC_MESSAGE_HANDLER(ShellViewHostMsg_ClearDevToolsLocalStorage, 372 OnClearDevToolsLocalStorage) 373 IPC_MESSAGE_HANDLER(ShellViewHostMsg_ShowDevTools, OnShowDevTools) 374 IPC_MESSAGE_HANDLER(ShellViewHostMsg_CloseDevTools, OnCloseDevTools) 375 IPC_MESSAGE_HANDLER(ShellViewHostMsg_GoToOffset, OnGoToOffset) 376 IPC_MESSAGE_HANDLER(ShellViewHostMsg_Reload, OnReload) 377 IPC_MESSAGE_HANDLER(ShellViewHostMsg_LoadURLForFrame, OnLoadURLForFrame) 378 IPC_MESSAGE_HANDLER(ShellViewHostMsg_CaptureSessionHistory, 379 OnCaptureSessionHistory) 380 IPC_MESSAGE_HANDLER(ShellViewHostMsg_CloseRemainingWindows, 381 OnCloseRemainingWindows) 382 IPC_MESSAGE_HANDLER(ShellViewHostMsg_ResetDone, OnResetDone) 383 IPC_MESSAGE_HANDLER(ShellViewHostMsg_LeakDetectionDone, OnLeakDetectionDone) 384 IPC_MESSAGE_UNHANDLED(handled = false) 385 IPC_END_MESSAGE_MAP() 386 387 return handled; 388 } 389 390 void WebKitTestController::PluginCrashed(const base::FilePath& plugin_path, 391 base::ProcessId plugin_pid) { 392 DCHECK(CalledOnValidThread()); 393 printer_->AddErrorMessage( 394 base::StringPrintf("#CRASHED - plugin (pid %d)", plugin_pid)); 395 base::MessageLoop::current()->PostTask( 396 FROM_HERE, 397 base::Bind(base::IgnoreResult(&WebKitTestController::DiscardMainWindow), 398 base::Unretained(this))); 399 } 400 401 void WebKitTestController::RenderViewCreated(RenderViewHost* render_view_host) { 402 DCHECK(CalledOnValidThread()); 403 // Might be kNullProcessHandle, in which case we will receive a notification 404 // later when the RenderProcessHost was created. 405 if (render_view_host->GetProcess()->GetHandle() != base::kNullProcessHandle) 406 current_pid_ = base::GetProcId(render_view_host->GetProcess()->GetHandle()); 407 if (!send_configuration_to_next_host_) 408 return; 409 send_configuration_to_next_host_ = false; 410 SendTestConfiguration(); 411 } 412 413 void WebKitTestController::RenderProcessGone(base::TerminationStatus status) { 414 DCHECK(CalledOnValidThread()); 415 if (current_pid_ != base::kNullProcessId) { 416 printer_->AddErrorMessage(std::string("#CRASHED - renderer (pid ") + 417 base::IntToString(current_pid_) + ")"); 418 } else { 419 printer_->AddErrorMessage("#CRASHED - renderer"); 420 } 421 DiscardMainWindow(); 422 } 423 424 void WebKitTestController::DevToolsProcessCrashed() { 425 DCHECK(CalledOnValidThread()); 426 printer_->AddErrorMessage("#CRASHED - devtools"); 427 DiscardMainWindow(); 428 } 429 430 void WebKitTestController::WebContentsDestroyed() { 431 DCHECK(CalledOnValidThread()); 432 printer_->AddErrorMessage("FAIL: main window was destroyed"); 433 DiscardMainWindow(); 434 } 435 436 void WebKitTestController::Observe(int type, 437 const NotificationSource& source, 438 const NotificationDetails& details) { 439 DCHECK(CalledOnValidThread()); 440 switch (type) { 441 case NOTIFICATION_RENDERER_PROCESS_CREATED: { 442 if (!main_window_) 443 return; 444 RenderViewHost* render_view_host = 445 main_window_->web_contents()->GetRenderViewHost(); 446 if (!render_view_host) 447 return; 448 RenderProcessHost* render_process_host = 449 Source<RenderProcessHost>(source).ptr(); 450 if (render_process_host != render_view_host->GetProcess()) 451 return; 452 current_pid_ = base::GetProcId(render_process_host->GetHandle()); 453 break; 454 } 455 default: 456 NOTREACHED(); 457 } 458 } 459 460 void WebKitTestController::OnGpuProcessCrashed( 461 base::TerminationStatus exit_code) { 462 DCHECK(CalledOnValidThread()); 463 printer_->AddErrorMessage("#CRASHED - gpu"); 464 DiscardMainWindow(); 465 } 466 467 void WebKitTestController::DiscardMainWindow() { 468 // If we're running a test, we need to close all windows and exit the message 469 // loop. Otherwise, we're already outside of the message loop, and we just 470 // discard the main window. 471 WebContentsObserver::Observe(NULL); 472 if (test_phase_ != BETWEEN_TESTS) { 473 Shell::CloseAllWindows(); 474 base::MessageLoop::current()->PostTask(FROM_HERE, 475 base::MessageLoop::QuitClosure()); 476 test_phase_ = CLEAN_UP; 477 } else if (main_window_) { 478 main_window_->Close(); 479 } 480 main_window_ = NULL; 481 current_pid_ = base::kNullProcessId; 482 } 483 484 void WebKitTestController::SendTestConfiguration() { 485 RenderViewHost* render_view_host = 486 main_window_->web_contents()->GetRenderViewHost(); 487 ShellTestConfiguration params; 488 params.current_working_directory = current_working_directory_; 489 params.temp_path = temp_path_; 490 params.test_url = test_url_; 491 params.enable_pixel_dumping = enable_pixel_dumping_; 492 params.allow_external_pages = CommandLine::ForCurrentProcess()->HasSwitch( 493 switches::kAllowExternalPages); 494 params.expected_pixel_hash = expected_pixel_hash_; 495 params.initial_size = initial_size_; 496 render_view_host->Send(new ShellViewMsg_SetTestConfiguration( 497 render_view_host->GetRoutingID(), params)); 498 } 499 500 void WebKitTestController::OnTestFinished() { 501 test_phase_ = CLEAN_UP; 502 if (!printer_->output_finished()) 503 printer_->PrintImageFooter(); 504 RenderViewHost* render_view_host = 505 main_window_->web_contents()->GetRenderViewHost(); 506 base::MessageLoop::current()->PostTask( 507 FROM_HERE, 508 base::Bind(base::IgnoreResult(&WebKitTestController::Send), 509 base::Unretained(this), 510 new ShellViewMsg_Reset(render_view_host->GetRoutingID()))); 511 } 512 513 void WebKitTestController::OnImageDump( 514 const std::string& actual_pixel_hash, 515 const SkBitmap& image) { 516 SkAutoLockPixels image_lock(image); 517 518 printer_->PrintImageHeader(actual_pixel_hash, expected_pixel_hash_); 519 520 // Only encode and dump the png if the hashes don't match. Encoding the 521 // image is really expensive. 522 if (actual_pixel_hash != expected_pixel_hash_) { 523 std::vector<unsigned char> png; 524 525 // Only the expected PNGs for Mac have a valid alpha channel. 526 #if defined(OS_MACOSX) 527 bool discard_transparency = false; 528 #else 529 bool discard_transparency = true; 530 #endif 531 if (CommandLine::ForCurrentProcess()->HasSwitch( 532 switches::kEnableOverlayFullscreenVideo)) 533 discard_transparency = false; 534 535 std::vector<gfx::PNGCodec::Comment> comments; 536 comments.push_back(gfx::PNGCodec::Comment("checksum", actual_pixel_hash)); 537 bool success = gfx::PNGCodec::Encode( 538 static_cast<const unsigned char*>(image.getPixels()), 539 gfx::PNGCodec::FORMAT_BGRA, 540 gfx::Size(image.width(), image.height()), 541 static_cast<int>(image.rowBytes()), 542 discard_transparency, 543 comments, 544 &png); 545 if (success) 546 printer_->PrintImageBlock(png); 547 } 548 printer_->PrintImageFooter(); 549 } 550 551 void WebKitTestController::OnAudioDump(const std::vector<unsigned char>& dump) { 552 printer_->PrintAudioHeader(); 553 printer_->PrintAudioBlock(dump); 554 printer_->PrintAudioFooter(); 555 } 556 557 void WebKitTestController::OnTextDump(const std::string& dump) { 558 printer_->PrintTextHeader(); 559 printer_->PrintTextBlock(dump); 560 printer_->PrintTextFooter(); 561 } 562 563 void WebKitTestController::OnPrintMessage(const std::string& message) { 564 printer_->AddMessageRaw(message); 565 } 566 567 void WebKitTestController::OnOverridePreferences(const WebPreferences& prefs) { 568 should_override_prefs_ = true; 569 prefs_ = prefs; 570 } 571 572 void WebKitTestController::OnClearDevToolsLocalStorage() { 573 ShellBrowserContext* browser_context = 574 ShellContentBrowserClient::Get()->browser_context(); 575 StoragePartition* storage_partition = 576 BrowserContext::GetStoragePartition(browser_context, NULL); 577 storage_partition->GetDOMStorageContext()->DeleteLocalStorage( 578 content::GetDevToolsPathAsURL("", "").GetOrigin()); 579 } 580 581 void WebKitTestController::OnShowDevTools(const std::string& settings, 582 const std::string& frontend_url) { 583 main_window_->ShowDevToolsForTest(settings, frontend_url); 584 } 585 586 void WebKitTestController::OnCloseDevTools() { 587 main_window_->CloseDevTools(); 588 } 589 590 void WebKitTestController::OnGoToOffset(int offset) { 591 main_window_->GoBackOrForward(offset); 592 } 593 594 void WebKitTestController::OnReload() { 595 main_window_->Reload(); 596 } 597 598 void WebKitTestController::OnLoadURLForFrame(const GURL& url, 599 const std::string& frame_name) { 600 main_window_->LoadURLForFrame(url, frame_name); 601 } 602 603 void WebKitTestController::OnCaptureSessionHistory() { 604 std::vector<int> routing_ids; 605 std::vector<std::vector<PageState> > session_histories; 606 std::vector<unsigned> current_entry_indexes; 607 608 RenderViewHost* render_view_host = 609 main_window_->web_contents()->GetRenderViewHost(); 610 611 for (std::vector<Shell*>::iterator window = Shell::windows().begin(); 612 window != Shell::windows().end(); 613 ++window) { 614 WebContents* web_contents = (*window)->web_contents(); 615 // Only capture the history from windows in the same process as the main 616 // window. During layout tests, we only use two processes when an 617 // devtools window is open. This should not happen during history navigation 618 // tests. 619 if (render_view_host->GetProcess() != 620 web_contents->GetRenderViewHost()->GetProcess()) { 621 NOTREACHED(); 622 continue; 623 } 624 routing_ids.push_back(web_contents->GetRenderViewHost()->GetRoutingID()); 625 current_entry_indexes.push_back( 626 web_contents->GetController().GetCurrentEntryIndex()); 627 std::vector<PageState> history; 628 for (int entry = 0; entry < web_contents->GetController().GetEntryCount(); 629 ++entry) { 630 PageState state = web_contents->GetController().GetEntryAtIndex(entry)-> 631 GetPageState(); 632 if (!state.IsValid()) { 633 state = PageState::CreateFromURL( 634 web_contents->GetController().GetEntryAtIndex(entry)->GetURL()); 635 } 636 history.push_back(state); 637 } 638 session_histories.push_back(history); 639 } 640 641 Send(new ShellViewMsg_SessionHistory(render_view_host->GetRoutingID(), 642 routing_ids, 643 session_histories, 644 current_entry_indexes)); 645 } 646 647 void WebKitTestController::OnCloseRemainingWindows() { 648 DevToolsManager::GetInstance()->CloseAllClientHosts(); 649 std::vector<Shell*> open_windows(Shell::windows()); 650 for (size_t i = 0; i < open_windows.size(); ++i) { 651 if (open_windows[i] != main_window_) 652 open_windows[i]->Close(); 653 } 654 base::MessageLoop::current()->RunUntilIdle(); 655 } 656 657 void WebKitTestController::OnResetDone() { 658 if (is_leak_detection_enabled_) { 659 if (main_window_ && main_window_->web_contents()) { 660 RenderViewHost* render_view_host = 661 main_window_->web_contents()->GetRenderViewHost(); 662 render_view_host->Send( 663 new ShellViewMsg_TryLeakDetection(render_view_host->GetRoutingID())); 664 } 665 return; 666 } 667 668 base::MessageLoop::current()->PostTask(FROM_HERE, 669 base::MessageLoop::QuitClosure()); 670 } 671 672 void WebKitTestController::OnLeakDetectionDone( 673 const LeakDetectionResult& result) { 674 if (!result.leaked) { 675 base::MessageLoop::current()->PostTask(FROM_HERE, 676 base::MessageLoop::QuitClosure()); 677 return; 678 } 679 680 printer_->AddErrorMessage( 681 base::StringPrintf("#LEAK - renderer pid %d (%s)", current_pid_, 682 result.detail.c_str())); 683 DiscardMainWindow(); 684 } 685 686 } // namespace content 687