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.
5 #include "content/shell/browser/webkit_test_controller.h"
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_agent_host.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"
40 const int kTestSVGWindowWidthDip
= 480;
41 const int kTestSVGWindowHeightDip
= 360;
43 // WebKitTestResultPrinter ----------------------------------------------------
45 WebKitTestResultPrinter::WebKitTestResultPrinter(
46 std::ostream
* output
, std::ostream
* error
)
47 : state_(DURING_TEST
),
48 capture_text_only_(false),
49 encode_binary_data_(false),
54 WebKitTestResultPrinter::~WebKitTestResultPrinter() {
57 void WebKitTestResultPrinter::PrintTextHeader() {
58 if (state_
!= DURING_TEST
)
60 if (!capture_text_only_
)
61 *output_
<< "Content-Type: text/plain\n";
62 state_
= IN_TEXT_BLOCK
;
65 void WebKitTestResultPrinter::PrintTextBlock(const std::string
& block
) {
66 if (state_
!= IN_TEXT_BLOCK
)
71 void WebKitTestResultPrinter::PrintTextFooter() {
72 if (state_
!= IN_TEXT_BLOCK
)
74 if (!capture_text_only_
) {
78 state_
= IN_IMAGE_BLOCK
;
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_
)
86 *output_
<< "\nActualHash: " << actual_hash
<< "\n";
87 if (!expected_hash
.empty())
88 *output_
<< "\nExpectedHash: " << expected_hash
<< "\n";
91 void WebKitTestResultPrinter::PrintImageBlock(
92 const std::vector
<unsigned char>& png_image
) {
93 if (state_
!= IN_IMAGE_BLOCK
|| capture_text_only_
)
95 *output_
<< "Content-Type: image/png\n";
96 if (encode_binary_data_
) {
97 PrintEncodedBinaryData(png_image
);
101 *output_
<< "Content-Length: " << png_image
.size() << "\n";
103 reinterpret_cast<const char*>(&png_image
[0]), png_image
.size());
106 void WebKitTestResultPrinter::PrintImageFooter() {
107 if (state_
!= IN_IMAGE_BLOCK
)
109 if (!capture_text_only_
) {
110 *output_
<< "#EOF\n";
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
;
123 void WebKitTestResultPrinter::PrintAudioBlock(
124 const std::vector
<unsigned char>& audio_data
) {
125 if (state_
!= IN_AUDIO_BLOCK
|| capture_text_only_
)
127 if (encode_binary_data_
) {
128 PrintEncodedBinaryData(audio_data
);
132 *output_
<< "Content-Length: " << audio_data
.size() << "\n";
134 reinterpret_cast<const char*>(&audio_data
[0]), audio_data
.size());
137 void WebKitTestResultPrinter::PrintAudioFooter() {
138 if (state_
!= IN_AUDIO_BLOCK
)
140 if (!capture_text_only_
) {
141 *output_
<< "#EOF\n";
144 state_
= IN_IMAGE_BLOCK
;
147 void WebKitTestResultPrinter::AddMessage(const std::string
& message
) {
148 AddMessageRaw(message
+ "\n");
151 void WebKitTestResultPrinter::AddMessageRaw(const std::string
& message
) {
152 if (state_
!= DURING_TEST
)
157 void WebKitTestResultPrinter::AddErrorMessage(const std::string
& message
) {
158 if (!capture_text_only_
)
159 *error_
<< message
<< "\n";
160 if (state_
!= DURING_TEST
)
163 *output_
<< message
<< "\n";
168 void WebKitTestResultPrinter::PrintEncodedBinaryData(
169 const std::vector
<unsigned char>& data
) {
170 *output_
<< "Content-Transfer-Encoding: base64\n";
172 std::string data_base64
;
174 base::StringPiece(reinterpret_cast<const char*>(&data
[0]), data
.size()),
177 *output_
<< "Content-Length: " << data_base64
.length() << "\n";
178 output_
->write(data_base64
.c_str(), data_base64
.length());
181 void WebKitTestResultPrinter::CloseStderr() {
182 if (state_
!= AFTER_TEST
)
184 if (!capture_text_only_
) {
191 // WebKitTestController -------------------------------------------------------
193 WebKitTestController
* WebKitTestController::instance_
= NULL
;
196 WebKitTestController
* WebKitTestController::Get() {
201 WebKitTestController::WebKitTestController()
202 : main_window_(NULL
),
203 test_phase_(BETWEEN_TESTS
),
204 is_leak_detection_enabled_(CommandLine::ForCurrentProcess()->HasSwitch(
205 switches::kEnableLeakDetection
)),
206 crash_when_leak_found_(false) {
210 if (is_leak_detection_enabled_
) {
211 std::string switchValue
=
212 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
213 switches::kEnableLeakDetection
);
214 crash_when_leak_found_
= switchValue
== switches::kCrashOnFailure
;
217 printer_
.reset(new WebKitTestResultPrinter(&std::cout
, &std::cerr
));
218 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEncodeBinary
))
219 printer_
->set_encode_binary_data(true);
221 NOTIFICATION_RENDERER_PROCESS_CREATED
,
222 NotificationService::AllSources());
223 GpuDataManager::GetInstance()->AddObserver(this);
224 ResetAfterLayoutTest();
227 WebKitTestController::~WebKitTestController() {
228 DCHECK(CalledOnValidThread());
229 CHECK(instance_
== this);
230 CHECK(test_phase_
== BETWEEN_TESTS
);
231 GpuDataManager::GetInstance()->RemoveObserver(this);
236 bool WebKitTestController::PrepareForLayoutTest(
237 const GURL
& test_url
,
238 const base::FilePath
& current_working_directory
,
239 bool enable_pixel_dumping
,
240 const std::string
& expected_pixel_hash
) {
241 DCHECK(CalledOnValidThread());
242 test_phase_
= DURING_TEST
;
243 current_working_directory_
= current_working_directory
;
244 enable_pixel_dumping_
= enable_pixel_dumping
;
245 expected_pixel_hash_
= expected_pixel_hash
;
246 test_url_
= test_url
;
248 ShellBrowserContext
* browser_context
=
249 ShellContentBrowserClient::Get()->browser_context();
250 if (test_url
.spec().find("compositing/") != std::string::npos
)
251 is_compositing_test_
= true;
252 initial_size_
= gfx::Size(
253 Shell::kDefaultTestWindowWidthDip
, Shell::kDefaultTestWindowHeightDip
);
254 // The W3C SVG layout tests use a different size than the other layout tests.
255 if (test_url
.spec().find("W3C-SVG-1.1") != std::string::npos
)
256 initial_size_
= gfx::Size(kTestSVGWindowWidthDip
, kTestSVGWindowHeightDip
);
258 main_window_
= content::Shell::CreateNewWindow(
264 WebContentsObserver::Observe(main_window_
->web_contents());
265 send_configuration_to_next_host_
= true;
266 current_pid_
= base::kNullProcessId
;
267 main_window_
->LoadURL(test_url
);
269 #if defined(OS_MACOSX)
270 // Shell::SizeTo is not implemented on all platforms.
271 main_window_
->SizeTo(initial_size_
);
273 main_window_
->web_contents()->GetRenderViewHost()->GetView()
274 ->SetSize(initial_size_
);
275 main_window_
->web_contents()->GetRenderViewHost()->WasResized();
276 RenderViewHost
* render_view_host
=
277 main_window_
->web_contents()->GetRenderViewHost();
278 WebPreferences prefs
= render_view_host
->GetWebkitPreferences();
279 OverrideWebkitPrefs(&prefs
);
280 render_view_host
->UpdateWebkitPreferences(prefs
);
281 SendTestConfiguration();
283 NavigationController::LoadURLParams
params(test_url
);
284 params
.transition_type
= PageTransitionFromInt(
285 PAGE_TRANSITION_TYPED
| PAGE_TRANSITION_FROM_ADDRESS_BAR
);
286 params
.should_clear_history_list
= true;
287 main_window_
->web_contents()->GetController().LoadURLWithParams(params
);
288 main_window_
->web_contents()->Focus();
290 main_window_
->web_contents()->GetRenderViewHost()->SetActive(true);
291 main_window_
->web_contents()->GetRenderViewHost()->Focus();
295 bool WebKitTestController::ResetAfterLayoutTest() {
296 DCHECK(CalledOnValidThread());
297 printer_
->PrintTextFooter();
298 printer_
->PrintImageFooter();
299 printer_
->CloseStderr();
300 send_configuration_to_next_host_
= false;
301 test_phase_
= BETWEEN_TESTS
;
302 is_compositing_test_
= false;
303 enable_pixel_dumping_
= false;
304 expected_pixel_hash_
.clear();
306 prefs_
= WebPreferences();
307 should_override_prefs_
= false;
309 #if defined(OS_ANDROID)
310 // Re-using the shell's main window on Android causes issues with networking
311 // requests never succeeding. See http://crbug.com/277652.
317 void WebKitTestController::SetTempPath(const base::FilePath
& temp_path
) {
318 temp_path_
= temp_path
;
321 void WebKitTestController::RendererUnresponsive() {
322 DCHECK(CalledOnValidThread());
323 LOG(WARNING
) << "renderer unresponsive";
326 void WebKitTestController::WorkerCrashed() {
327 DCHECK(CalledOnValidThread());
328 printer_
->AddErrorMessage("#CRASHED - worker");
332 void WebKitTestController::OverrideWebkitPrefs(WebPreferences
* prefs
) {
333 if (should_override_prefs_
) {
336 ApplyLayoutTestDefaultPreferences(prefs
);
337 if (is_compositing_test_
) {
338 CommandLine
& command_line
= *CommandLine::ForCurrentProcess();
339 if (!command_line
.HasSwitch(switches::kDisableGpu
))
340 prefs
->accelerated_2d_canvas_enabled
= true;
341 prefs
->mock_scrollbars_enabled
= true;
346 void WebKitTestController::OpenURL(const GURL
& url
) {
347 if (test_phase_
!= DURING_TEST
)
350 Shell::CreateNewWindow(main_window_
->web_contents()->GetBrowserContext(),
352 main_window_
->web_contents()->GetSiteInstance(),
357 void WebKitTestController::TestFinishedInSecondaryWindow() {
358 RenderViewHost
* render_view_host
=
359 main_window_
->web_contents()->GetRenderViewHost();
360 render_view_host
->Send(
361 new ShellViewMsg_NotifyDone(render_view_host
->GetRoutingID()));
364 bool WebKitTestController::IsMainWindow(WebContents
* web_contents
) const {
365 return main_window_
&& web_contents
== main_window_
->web_contents();
368 bool WebKitTestController::OnMessageReceived(const IPC::Message
& message
) {
369 DCHECK(CalledOnValidThread());
371 IPC_BEGIN_MESSAGE_MAP(WebKitTestController
, message
)
372 IPC_MESSAGE_HANDLER(ShellViewHostMsg_PrintMessage
, OnPrintMessage
)
373 IPC_MESSAGE_HANDLER(ShellViewHostMsg_TextDump
, OnTextDump
)
374 IPC_MESSAGE_HANDLER(ShellViewHostMsg_ImageDump
, OnImageDump
)
375 IPC_MESSAGE_HANDLER(ShellViewHostMsg_AudioDump
, OnAudioDump
)
376 IPC_MESSAGE_HANDLER(ShellViewHostMsg_OverridePreferences
,
377 OnOverridePreferences
)
378 IPC_MESSAGE_HANDLER(ShellViewHostMsg_TestFinished
, OnTestFinished
)
379 IPC_MESSAGE_HANDLER(ShellViewHostMsg_ClearDevToolsLocalStorage
,
380 OnClearDevToolsLocalStorage
)
381 IPC_MESSAGE_HANDLER(ShellViewHostMsg_ShowDevTools
, OnShowDevTools
)
382 IPC_MESSAGE_HANDLER(ShellViewHostMsg_CloseDevTools
, OnCloseDevTools
)
383 IPC_MESSAGE_HANDLER(ShellViewHostMsg_GoToOffset
, OnGoToOffset
)
384 IPC_MESSAGE_HANDLER(ShellViewHostMsg_Reload
, OnReload
)
385 IPC_MESSAGE_HANDLER(ShellViewHostMsg_LoadURLForFrame
, OnLoadURLForFrame
)
386 IPC_MESSAGE_HANDLER(ShellViewHostMsg_CaptureSessionHistory
,
387 OnCaptureSessionHistory
)
388 IPC_MESSAGE_HANDLER(ShellViewHostMsg_CloseRemainingWindows
,
389 OnCloseRemainingWindows
)
390 IPC_MESSAGE_HANDLER(ShellViewHostMsg_ResetDone
, OnResetDone
)
391 IPC_MESSAGE_HANDLER(ShellViewHostMsg_LeakDetectionDone
, OnLeakDetectionDone
)
392 IPC_MESSAGE_UNHANDLED(handled
= false)
393 IPC_END_MESSAGE_MAP()
398 void WebKitTestController::PluginCrashed(const base::FilePath
& plugin_path
,
399 base::ProcessId plugin_pid
) {
400 DCHECK(CalledOnValidThread());
401 printer_
->AddErrorMessage(
402 base::StringPrintf("#CRASHED - plugin (pid %d)", plugin_pid
));
403 base::MessageLoop::current()->PostTask(
405 base::Bind(base::IgnoreResult(&WebKitTestController::DiscardMainWindow
),
406 base::Unretained(this)));
409 void WebKitTestController::RenderViewCreated(RenderViewHost
* render_view_host
) {
410 DCHECK(CalledOnValidThread());
411 // Might be kNullProcessHandle, in which case we will receive a notification
412 // later when the RenderProcessHost was created.
413 if (render_view_host
->GetProcess()->GetHandle() != base::kNullProcessHandle
)
414 current_pid_
= base::GetProcId(render_view_host
->GetProcess()->GetHandle());
415 if (!send_configuration_to_next_host_
)
417 send_configuration_to_next_host_
= false;
418 SendTestConfiguration();
421 void WebKitTestController::RenderProcessGone(base::TerminationStatus status
) {
422 DCHECK(CalledOnValidThread());
423 if (current_pid_
!= base::kNullProcessId
) {
424 printer_
->AddErrorMessage(std::string("#CRASHED - renderer (pid ") +
425 base::IntToString(current_pid_
) + ")");
427 printer_
->AddErrorMessage("#CRASHED - renderer");
432 void WebKitTestController::DevToolsProcessCrashed() {
433 DCHECK(CalledOnValidThread());
434 printer_
->AddErrorMessage("#CRASHED - devtools");
438 void WebKitTestController::WebContentsDestroyed() {
439 DCHECK(CalledOnValidThread());
440 printer_
->AddErrorMessage("FAIL: main window was destroyed");
444 void WebKitTestController::Observe(int type
,
445 const NotificationSource
& source
,
446 const NotificationDetails
& details
) {
447 DCHECK(CalledOnValidThread());
449 case NOTIFICATION_RENDERER_PROCESS_CREATED
: {
452 RenderViewHost
* render_view_host
=
453 main_window_
->web_contents()->GetRenderViewHost();
454 if (!render_view_host
)
456 RenderProcessHost
* render_process_host
=
457 Source
<RenderProcessHost
>(source
).ptr();
458 if (render_process_host
!= render_view_host
->GetProcess())
460 current_pid_
= base::GetProcId(render_process_host
->GetHandle());
468 void WebKitTestController::OnGpuProcessCrashed(
469 base::TerminationStatus exit_code
) {
470 DCHECK(CalledOnValidThread());
471 printer_
->AddErrorMessage("#CRASHED - gpu");
475 void WebKitTestController::DiscardMainWindow() {
476 // If we're running a test, we need to close all windows and exit the message
477 // loop. Otherwise, we're already outside of the message loop, and we just
478 // discard the main window.
479 WebContentsObserver::Observe(NULL
);
480 if (test_phase_
!= BETWEEN_TESTS
) {
481 Shell::CloseAllWindows();
482 base::MessageLoop::current()->PostTask(FROM_HERE
,
483 base::MessageLoop::QuitClosure());
484 test_phase_
= CLEAN_UP
;
485 } else if (main_window_
) {
486 main_window_
->Close();
489 current_pid_
= base::kNullProcessId
;
492 void WebKitTestController::SendTestConfiguration() {
493 RenderViewHost
* render_view_host
=
494 main_window_
->web_contents()->GetRenderViewHost();
495 ShellTestConfiguration params
;
496 params
.current_working_directory
= current_working_directory_
;
497 params
.temp_path
= temp_path_
;
498 params
.test_url
= test_url_
;
499 params
.enable_pixel_dumping
= enable_pixel_dumping_
;
500 params
.allow_external_pages
= CommandLine::ForCurrentProcess()->HasSwitch(
501 switches::kAllowExternalPages
);
502 params
.expected_pixel_hash
= expected_pixel_hash_
;
503 params
.initial_size
= initial_size_
;
504 render_view_host
->Send(new ShellViewMsg_SetTestConfiguration(
505 render_view_host
->GetRoutingID(), params
));
508 void WebKitTestController::OnTestFinished() {
509 test_phase_
= CLEAN_UP
;
510 if (!printer_
->output_finished())
511 printer_
->PrintImageFooter();
512 RenderViewHost
* render_view_host
=
513 main_window_
->web_contents()->GetRenderViewHost();
514 base::MessageLoop::current()->PostTask(
516 base::Bind(base::IgnoreResult(&WebKitTestController::Send
),
517 base::Unretained(this),
518 new ShellViewMsg_Reset(render_view_host
->GetRoutingID())));
521 void WebKitTestController::OnImageDump(
522 const std::string
& actual_pixel_hash
,
523 const SkBitmap
& image
) {
524 SkAutoLockPixels
image_lock(image
);
526 printer_
->PrintImageHeader(actual_pixel_hash
, expected_pixel_hash_
);
528 // Only encode and dump the png if the hashes don't match. Encoding the
529 // image is really expensive.
530 if (actual_pixel_hash
!= expected_pixel_hash_
) {
531 std::vector
<unsigned char> png
;
533 // Only the expected PNGs for Mac have a valid alpha channel.
534 #if defined(OS_MACOSX)
535 bool discard_transparency
= false;
537 bool discard_transparency
= true;
539 if (CommandLine::ForCurrentProcess()->HasSwitch(
540 switches::kEnableOverlayFullscreenVideo
))
541 discard_transparency
= false;
543 std::vector
<gfx::PNGCodec::Comment
> comments
;
544 comments
.push_back(gfx::PNGCodec::Comment("checksum", actual_pixel_hash
));
545 bool success
= gfx::PNGCodec::Encode(
546 static_cast<const unsigned char*>(image
.getPixels()),
547 gfx::PNGCodec::FORMAT_BGRA
,
548 gfx::Size(image
.width(), image
.height()),
549 static_cast<int>(image
.rowBytes()),
550 discard_transparency
,
554 printer_
->PrintImageBlock(png
);
556 printer_
->PrintImageFooter();
559 void WebKitTestController::OnAudioDump(const std::vector
<unsigned char>& dump
) {
560 printer_
->PrintAudioHeader();
561 printer_
->PrintAudioBlock(dump
);
562 printer_
->PrintAudioFooter();
565 void WebKitTestController::OnTextDump(const std::string
& dump
) {
566 printer_
->PrintTextHeader();
567 printer_
->PrintTextBlock(dump
);
568 printer_
->PrintTextFooter();
571 void WebKitTestController::OnPrintMessage(const std::string
& message
) {
572 printer_
->AddMessageRaw(message
);
575 void WebKitTestController::OnOverridePreferences(const WebPreferences
& prefs
) {
576 should_override_prefs_
= true;
580 void WebKitTestController::OnClearDevToolsLocalStorage() {
581 ShellBrowserContext
* browser_context
=
582 ShellContentBrowserClient::Get()->browser_context();
583 StoragePartition
* storage_partition
=
584 BrowserContext::GetStoragePartition(browser_context
, NULL
);
585 storage_partition
->GetDOMStorageContext()->DeleteLocalStorage(
586 content::GetDevToolsPathAsURL("", "").GetOrigin());
589 void WebKitTestController::OnShowDevTools(const std::string
& settings
,
590 const std::string
& frontend_url
) {
591 main_window_
->ShowDevToolsForTest(settings
, frontend_url
);
594 void WebKitTestController::OnCloseDevTools() {
595 main_window_
->CloseDevTools();
598 void WebKitTestController::OnGoToOffset(int offset
) {
599 main_window_
->GoBackOrForward(offset
);
602 void WebKitTestController::OnReload() {
603 main_window_
->Reload();
606 void WebKitTestController::OnLoadURLForFrame(const GURL
& url
,
607 const std::string
& frame_name
) {
608 main_window_
->LoadURLForFrame(url
, frame_name
);
611 void WebKitTestController::OnCaptureSessionHistory() {
612 std::vector
<int> routing_ids
;
613 std::vector
<std::vector
<PageState
> > session_histories
;
614 std::vector
<unsigned> current_entry_indexes
;
616 RenderViewHost
* render_view_host
=
617 main_window_
->web_contents()->GetRenderViewHost();
619 for (std::vector
<Shell
*>::iterator window
= Shell::windows().begin();
620 window
!= Shell::windows().end();
622 WebContents
* web_contents
= (*window
)->web_contents();
623 // Only capture the history from windows in the same process as the main
624 // window. During layout tests, we only use two processes when an
625 // devtools window is open. This should not happen during history navigation
627 if (render_view_host
->GetProcess() !=
628 web_contents
->GetRenderViewHost()->GetProcess()) {
632 routing_ids
.push_back(web_contents
->GetRenderViewHost()->GetRoutingID());
633 current_entry_indexes
.push_back(
634 web_contents
->GetController().GetCurrentEntryIndex());
635 std::vector
<PageState
> history
;
636 for (int entry
= 0; entry
< web_contents
->GetController().GetEntryCount();
638 PageState state
= web_contents
->GetController().GetEntryAtIndex(entry
)->
640 if (!state
.IsValid()) {
641 state
= PageState::CreateFromURL(
642 web_contents
->GetController().GetEntryAtIndex(entry
)->GetURL());
644 history
.push_back(state
);
646 session_histories
.push_back(history
);
649 Send(new ShellViewMsg_SessionHistory(render_view_host
->GetRoutingID(),
652 current_entry_indexes
));
655 void WebKitTestController::OnCloseRemainingWindows() {
656 DevToolsAgentHost::DetachAllClients();
657 std::vector
<Shell
*> open_windows(Shell::windows());
658 for (size_t i
= 0; i
< open_windows
.size(); ++i
) {
659 if (open_windows
[i
] != main_window_
)
660 open_windows
[i
]->Close();
662 base::MessageLoop::current()->RunUntilIdle();
665 void WebKitTestController::OnResetDone() {
666 if (is_leak_detection_enabled_
) {
667 if (main_window_
&& main_window_
->web_contents()) {
668 RenderViewHost
* render_view_host
=
669 main_window_
->web_contents()->GetRenderViewHost();
670 render_view_host
->Send(
671 new ShellViewMsg_TryLeakDetection(render_view_host
->GetRoutingID()));
676 base::MessageLoop::current()->PostTask(FROM_HERE
,
677 base::MessageLoop::QuitClosure());
680 void WebKitTestController::OnLeakDetectionDone(
681 const LeakDetectionResult
& result
) {
682 if (!result
.leaked
) {
683 base::MessageLoop::current()->PostTask(FROM_HERE
,
684 base::MessageLoop::QuitClosure());
688 printer_
->AddErrorMessage(
689 base::StringPrintf("#LEAK - renderer pid %d (%s)", current_pid_
,
690 result
.detail
.c_str()));
691 CHECK(!crash_when_leak_found_
);
696 } // namespace content