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/browser/web_contents_view.h" 28 #include "content/public/common/content_switches.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 CHECK(!instance_); 205 instance_ = this; 206 printer_.reset(new WebKitTestResultPrinter(&std::cout, &std::cerr)); 207 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEncodeBinary)) 208 printer_->set_encode_binary_data(true); 209 registrar_.Add(this, 210 NOTIFICATION_RENDERER_PROCESS_CREATED, 211 NotificationService::AllSources()); 212 GpuDataManager::GetInstance()->AddObserver(this); 213 ResetAfterLayoutTest(); 214 } 215 216 WebKitTestController::~WebKitTestController() { 217 DCHECK(CalledOnValidThread()); 218 CHECK(instance_ == this); 219 CHECK(test_phase_ == BETWEEN_TESTS); 220 GpuDataManager::GetInstance()->RemoveObserver(this); 221 DiscardMainWindow(); 222 instance_ = NULL; 223 } 224 225 bool WebKitTestController::PrepareForLayoutTest( 226 const GURL& test_url, 227 const base::FilePath& current_working_directory, 228 bool enable_pixel_dumping, 229 const std::string& expected_pixel_hash) { 230 DCHECK(CalledOnValidThread()); 231 test_phase_ = DURING_TEST; 232 current_working_directory_ = current_working_directory; 233 enable_pixel_dumping_ = enable_pixel_dumping; 234 expected_pixel_hash_ = expected_pixel_hash; 235 test_url_ = test_url; 236 printer_->reset(); 237 ShellBrowserContext* browser_context = 238 ShellContentBrowserClient::Get()->browser_context(); 239 if (test_url.spec().find("compositing/") != std::string::npos) 240 is_compositing_test_ = true; 241 initial_size_ = gfx::Size( 242 Shell::kDefaultTestWindowWidthDip, Shell::kDefaultTestWindowHeightDip); 243 // The W3C SVG layout tests use a different size than the other layout tests. 244 if (test_url.spec().find("W3C-SVG-1.1") != std::string::npos) 245 initial_size_ = gfx::Size(kTestSVGWindowWidthDip, kTestSVGWindowHeightDip); 246 if (!main_window_) { 247 main_window_ = content::Shell::CreateNewWindow( 248 browser_context, 249 GURL(), 250 NULL, 251 MSG_ROUTING_NONE, 252 initial_size_); 253 WebContentsObserver::Observe(main_window_->web_contents()); 254 send_configuration_to_next_host_ = true; 255 current_pid_ = base::kNullProcessId; 256 main_window_->LoadURL(test_url); 257 } else { 258 #if (defined(OS_WIN) && !defined(USE_AURA)) || \ 259 defined(TOOLKIT_GTK) || defined(OS_MACOSX) 260 // Shell::SizeTo is not implemented on all platforms. 261 main_window_->SizeTo(initial_size_); 262 #endif 263 main_window_->web_contents()->GetRenderViewHost()->GetView() 264 ->SetSize(initial_size_); 265 main_window_->web_contents()->GetRenderViewHost()->WasResized(); 266 RenderViewHost* render_view_host = 267 main_window_->web_contents()->GetRenderViewHost(); 268 WebPreferences prefs = render_view_host->GetWebkitPreferences(); 269 OverrideWebkitPrefs(&prefs); 270 render_view_host->UpdateWebkitPreferences(prefs); 271 SendTestConfiguration(); 272 273 NavigationController::LoadURLParams params(test_url); 274 params.transition_type = PageTransitionFromInt( 275 PAGE_TRANSITION_TYPED | PAGE_TRANSITION_FROM_ADDRESS_BAR); 276 params.should_clear_history_list = true; 277 main_window_->web_contents()->GetController().LoadURLWithParams(params); 278 main_window_->web_contents()->GetView()->Focus(); 279 } 280 main_window_->web_contents()->GetRenderViewHost()->SetActive(true); 281 main_window_->web_contents()->GetRenderViewHost()->Focus(); 282 return true; 283 } 284 285 bool WebKitTestController::ResetAfterLayoutTest() { 286 DCHECK(CalledOnValidThread()); 287 printer_->PrintTextFooter(); 288 printer_->PrintImageFooter(); 289 printer_->CloseStderr(); 290 send_configuration_to_next_host_ = false; 291 test_phase_ = BETWEEN_TESTS; 292 is_compositing_test_ = false; 293 enable_pixel_dumping_ = false; 294 expected_pixel_hash_.clear(); 295 test_url_ = GURL(); 296 prefs_ = WebPreferences(); 297 should_override_prefs_ = false; 298 299 #if defined(OS_ANDROID) 300 // Re-using the shell's main window on Android causes issues with networking 301 // requests never succeeding. See http://crbug.com/277652. 302 DiscardMainWindow(); 303 #endif 304 return true; 305 } 306 307 void WebKitTestController::SetTempPath(const base::FilePath& temp_path) { 308 temp_path_ = temp_path; 309 } 310 311 void WebKitTestController::RendererUnresponsive() { 312 DCHECK(CalledOnValidThread()); 313 LOG(WARNING) << "renderer unresponsive"; 314 } 315 316 void WebKitTestController::WorkerCrashed() { 317 DCHECK(CalledOnValidThread()); 318 printer_->AddErrorMessage("#CRASHED - worker"); 319 DiscardMainWindow(); 320 } 321 322 void WebKitTestController::OverrideWebkitPrefs(WebPreferences* prefs) { 323 if (should_override_prefs_) { 324 *prefs = prefs_; 325 } else { 326 ApplyLayoutTestDefaultPreferences(prefs); 327 if (is_compositing_test_) { 328 CommandLine& command_line = *CommandLine::ForCurrentProcess(); 329 if (!command_line.HasSwitch(switches::kEnableSoftwareCompositing)) 330 prefs->accelerated_2d_canvas_enabled = true; 331 prefs->accelerated_compositing_for_video_enabled = true; 332 prefs->mock_scrollbars_enabled = true; 333 } 334 } 335 } 336 337 void WebKitTestController::OpenURL(const GURL& url) { 338 if (test_phase_ != DURING_TEST) 339 return; 340 341 Shell::CreateNewWindow(main_window_->web_contents()->GetBrowserContext(), 342 url, 343 main_window_->web_contents()->GetSiteInstance(), 344 MSG_ROUTING_NONE, 345 gfx::Size()); 346 } 347 348 void WebKitTestController::TestFinishedInSecondaryWindow() { 349 RenderViewHost* render_view_host = 350 main_window_->web_contents()->GetRenderViewHost(); 351 render_view_host->Send( 352 new ShellViewMsg_NotifyDone(render_view_host->GetRoutingID())); 353 } 354 355 bool WebKitTestController::IsMainWindow(WebContents* web_contents) const { 356 return main_window_ && web_contents == main_window_->web_contents(); 357 } 358 359 bool WebKitTestController::OnMessageReceived(const IPC::Message& message) { 360 DCHECK(CalledOnValidThread()); 361 bool handled = true; 362 IPC_BEGIN_MESSAGE_MAP(WebKitTestController, message) 363 IPC_MESSAGE_HANDLER(ShellViewHostMsg_PrintMessage, OnPrintMessage) 364 IPC_MESSAGE_HANDLER(ShellViewHostMsg_TextDump, OnTextDump) 365 IPC_MESSAGE_HANDLER(ShellViewHostMsg_ImageDump, OnImageDump) 366 IPC_MESSAGE_HANDLER(ShellViewHostMsg_AudioDump, OnAudioDump) 367 IPC_MESSAGE_HANDLER(ShellViewHostMsg_OverridePreferences, 368 OnOverridePreferences) 369 IPC_MESSAGE_HANDLER(ShellViewHostMsg_TestFinished, OnTestFinished) 370 IPC_MESSAGE_HANDLER(ShellViewHostMsg_ShowDevTools, OnShowDevTools) 371 IPC_MESSAGE_HANDLER(ShellViewHostMsg_CloseDevTools, OnCloseDevTools) 372 IPC_MESSAGE_HANDLER(ShellViewHostMsg_GoToOffset, OnGoToOffset) 373 IPC_MESSAGE_HANDLER(ShellViewHostMsg_Reload, OnReload) 374 IPC_MESSAGE_HANDLER(ShellViewHostMsg_LoadURLForFrame, OnLoadURLForFrame) 375 IPC_MESSAGE_HANDLER(ShellViewHostMsg_CaptureSessionHistory, 376 OnCaptureSessionHistory) 377 IPC_MESSAGE_HANDLER(ShellViewHostMsg_CloseRemainingWindows, 378 OnCloseRemainingWindows) 379 IPC_MESSAGE_HANDLER(ShellViewHostMsg_ResetDone, OnResetDone) 380 IPC_MESSAGE_UNHANDLED(handled = false) 381 IPC_END_MESSAGE_MAP() 382 383 return handled; 384 } 385 386 void WebKitTestController::PluginCrashed(const base::FilePath& plugin_path, 387 base::ProcessId plugin_pid) { 388 DCHECK(CalledOnValidThread()); 389 printer_->AddErrorMessage( 390 base::StringPrintf("#CRASHED - plugin (pid %d)", plugin_pid)); 391 base::MessageLoop::current()->PostTask( 392 FROM_HERE, 393 base::Bind(base::IgnoreResult(&WebKitTestController::DiscardMainWindow), 394 base::Unretained(this))); 395 } 396 397 void WebKitTestController::RenderViewCreated(RenderViewHost* render_view_host) { 398 DCHECK(CalledOnValidThread()); 399 // Might be kNullProcessHandle, in which case we will receive a notification 400 // later when the RenderProcessHost was created. 401 if (render_view_host->GetProcess()->GetHandle() != base::kNullProcessHandle) 402 current_pid_ = base::GetProcId(render_view_host->GetProcess()->GetHandle()); 403 if (!send_configuration_to_next_host_) 404 return; 405 send_configuration_to_next_host_ = false; 406 SendTestConfiguration(); 407 } 408 409 void WebKitTestController::RenderProcessGone(base::TerminationStatus status) { 410 DCHECK(CalledOnValidThread()); 411 if (current_pid_ != base::kNullProcessId) { 412 printer_->AddErrorMessage(std::string("#CRASHED - renderer (pid ") + 413 base::IntToString(current_pid_) + ")"); 414 } else { 415 printer_->AddErrorMessage("#CRASHED - renderer"); 416 } 417 DiscardMainWindow(); 418 } 419 420 void WebKitTestController::WebContentsDestroyed(WebContents* web_contents) { 421 DCHECK(CalledOnValidThread()); 422 printer_->AddErrorMessage("FAIL: main window was destroyed"); 423 DiscardMainWindow(); 424 } 425 426 void WebKitTestController::Observe(int type, 427 const NotificationSource& source, 428 const NotificationDetails& details) { 429 DCHECK(CalledOnValidThread()); 430 switch (type) { 431 case NOTIFICATION_RENDERER_PROCESS_CREATED: { 432 if (!main_window_) 433 return; 434 RenderViewHost* render_view_host = 435 main_window_->web_contents()->GetRenderViewHost(); 436 if (!render_view_host) 437 return; 438 RenderProcessHost* render_process_host = 439 Source<RenderProcessHost>(source).ptr(); 440 if (render_process_host != render_view_host->GetProcess()) 441 return; 442 current_pid_ = base::GetProcId(render_process_host->GetHandle()); 443 break; 444 } 445 default: 446 NOTREACHED(); 447 } 448 } 449 450 void WebKitTestController::OnGpuProcessCrashed( 451 base::TerminationStatus exit_code) { 452 DCHECK(CalledOnValidThread()); 453 printer_->AddErrorMessage("#CRASHED - gpu"); 454 DiscardMainWindow(); 455 } 456 457 void WebKitTestController::TimeoutHandler() { 458 DCHECK(CalledOnValidThread()); 459 printer_->AddErrorMessage( 460 "FAIL: Timed out waiting for notifyDone to be called"); 461 DiscardMainWindow(); 462 } 463 464 void WebKitTestController::DiscardMainWindow() { 465 // If we're running a test, we need to close all windows and exit the message 466 // loop. Otherwise, we're already outside of the message loop, and we just 467 // discard the main window. 468 WebContentsObserver::Observe(NULL); 469 if (test_phase_ != BETWEEN_TESTS) { 470 Shell::CloseAllWindows(); 471 base::MessageLoop::current()->PostTask(FROM_HERE, 472 base::MessageLoop::QuitClosure()); 473 test_phase_ = CLEAN_UP; 474 } else if (main_window_) { 475 main_window_->Close(); 476 } 477 main_window_ = NULL; 478 current_pid_ = base::kNullProcessId; 479 } 480 481 void WebKitTestController::SendTestConfiguration() { 482 RenderViewHost* render_view_host = 483 main_window_->web_contents()->GetRenderViewHost(); 484 ShellTestConfiguration params; 485 params.current_working_directory = current_working_directory_; 486 params.temp_path = temp_path_; 487 params.test_url = test_url_; 488 params.enable_pixel_dumping = enable_pixel_dumping_; 489 params.allow_external_pages = CommandLine::ForCurrentProcess()->HasSwitch( 490 switches::kAllowExternalPages); 491 params.expected_pixel_hash = expected_pixel_hash_; 492 params.initial_size = initial_size_; 493 render_view_host->Send(new ShellViewMsg_SetTestConfiguration( 494 render_view_host->GetRoutingID(), params)); 495 } 496 497 void WebKitTestController::OnTestFinished() { 498 test_phase_ = CLEAN_UP; 499 if (!printer_->output_finished()) 500 printer_->PrintImageFooter(); 501 RenderViewHost* render_view_host = 502 main_window_->web_contents()->GetRenderViewHost(); 503 base::MessageLoop::current()->PostTask( 504 FROM_HERE, 505 base::Bind(base::IgnoreResult(&WebKitTestController::Send), 506 base::Unretained(this), 507 new ShellViewMsg_Reset(render_view_host->GetRoutingID()))); 508 } 509 510 void WebKitTestController::OnImageDump( 511 const std::string& actual_pixel_hash, 512 const SkBitmap& image) { 513 SkAutoLockPixels image_lock(image); 514 515 printer_->PrintImageHeader(actual_pixel_hash, expected_pixel_hash_); 516 517 // Only encode and dump the png if the hashes don't match. Encoding the 518 // image is really expensive. 519 if (actual_pixel_hash != expected_pixel_hash_) { 520 std::vector<unsigned char> png; 521 522 // Only the expected PNGs for Mac have a valid alpha channel. 523 #if defined(OS_MACOSX) 524 bool discard_transparency = false; 525 #else 526 bool discard_transparency = true; 527 #endif 528 if (CommandLine::ForCurrentProcess()->HasSwitch( 529 switches::kEnableOverlayFullscreenVideo)) 530 discard_transparency = false; 531 532 std::vector<gfx::PNGCodec::Comment> comments; 533 comments.push_back(gfx::PNGCodec::Comment("checksum", actual_pixel_hash)); 534 bool success = gfx::PNGCodec::Encode( 535 static_cast<const unsigned char*>(image.getPixels()), 536 gfx::PNGCodec::FORMAT_BGRA, 537 gfx::Size(image.width(), image.height()), 538 static_cast<int>(image.rowBytes()), 539 discard_transparency, 540 comments, 541 &png); 542 if (success) 543 printer_->PrintImageBlock(png); 544 } 545 printer_->PrintImageFooter(); 546 } 547 548 void WebKitTestController::OnAudioDump(const std::vector<unsigned char>& dump) { 549 printer_->PrintAudioHeader(); 550 printer_->PrintAudioBlock(dump); 551 printer_->PrintAudioFooter(); 552 } 553 554 void WebKitTestController::OnTextDump(const std::string& dump) { 555 printer_->PrintTextHeader(); 556 printer_->PrintTextBlock(dump); 557 printer_->PrintTextFooter(); 558 } 559 560 void WebKitTestController::OnPrintMessage(const std::string& message) { 561 printer_->AddMessageRaw(message); 562 } 563 564 void WebKitTestController::OnOverridePreferences(const WebPreferences& prefs) { 565 should_override_prefs_ = true; 566 prefs_ = prefs; 567 } 568 569 void WebKitTestController::OnShowDevTools() { 570 ShellBrowserContext* browser_context = 571 ShellContentBrowserClient::Get()->browser_context(); 572 StoragePartition* storage_partition = 573 BrowserContext::GetStoragePartition(browser_context, NULL); 574 storage_partition->GetDOMStorageContext()->DeleteLocalStorage( 575 content::GetDevToolsPathAsURL().GetOrigin()); 576 main_window_->ShowDevTools(); 577 } 578 579 void WebKitTestController::OnCloseDevTools() { 580 main_window_->CloseDevTools(); 581 } 582 583 void WebKitTestController::OnGoToOffset(int offset) { 584 main_window_->GoBackOrForward(offset); 585 } 586 587 void WebKitTestController::OnReload() { 588 main_window_->Reload(); 589 } 590 591 void WebKitTestController::OnLoadURLForFrame(const GURL& url, 592 const std::string& frame_name) { 593 main_window_->LoadURLForFrame(url, frame_name); 594 } 595 596 void WebKitTestController::OnCaptureSessionHistory() { 597 std::vector<int> routing_ids; 598 std::vector<std::vector<PageState> > session_histories; 599 std::vector<unsigned> current_entry_indexes; 600 601 RenderViewHost* render_view_host = 602 main_window_->web_contents()->GetRenderViewHost(); 603 604 for (std::vector<Shell*>::iterator window = Shell::windows().begin(); 605 window != Shell::windows().end(); 606 ++window) { 607 WebContents* web_contents = (*window)->web_contents(); 608 // Only capture the history from windows in the same process as the main 609 // window. During layout tests, we only use two processes when an 610 // devtools window is open. This should not happen during history navigation 611 // tests. 612 if (render_view_host->GetProcess() != 613 web_contents->GetRenderViewHost()->GetProcess()) { 614 NOTREACHED(); 615 continue; 616 } 617 routing_ids.push_back(web_contents->GetRenderViewHost()->GetRoutingID()); 618 current_entry_indexes.push_back( 619 web_contents->GetController().GetCurrentEntryIndex()); 620 std::vector<PageState> history; 621 for (int entry = 0; entry < web_contents->GetController().GetEntryCount(); 622 ++entry) { 623 PageState state = web_contents->GetController().GetEntryAtIndex(entry)-> 624 GetPageState(); 625 if (!state.IsValid()) { 626 state = PageState::CreateFromURL( 627 web_contents->GetController().GetEntryAtIndex(entry)->GetURL()); 628 } 629 history.push_back(state); 630 } 631 session_histories.push_back(history); 632 } 633 634 Send(new ShellViewMsg_SessionHistory(render_view_host->GetRoutingID(), 635 routing_ids, 636 session_histories, 637 current_entry_indexes)); 638 } 639 640 void WebKitTestController::OnCloseRemainingWindows() { 641 DevToolsManager::GetInstance()->CloseAllClientHosts(); 642 std::vector<Shell*> open_windows(Shell::windows()); 643 for (size_t i = 0; i < open_windows.size(); ++i) { 644 if (open_windows[i] != main_window_) 645 open_windows[i]->Close(); 646 } 647 base::MessageLoop::current()->RunUntilIdle(); 648 } 649 650 void WebKitTestController::OnResetDone() { 651 base::MessageLoop::current()->PostTask(FROM_HERE, 652 base::MessageLoop::QuitClosure()); 653 } 654 655 } // namespace content 656