• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
WebKitTestResultPrinter(std::ostream * output,std::ostream * error)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 
~WebKitTestResultPrinter()54 WebKitTestResultPrinter::~WebKitTestResultPrinter() {
55 }
56 
PrintTextHeader()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 
PrintTextBlock(const std::string & block)65 void WebKitTestResultPrinter::PrintTextBlock(const std::string& block) {
66   if (state_ != IN_TEXT_BLOCK)
67     return;
68   *output_ << block;
69 }
70 
PrintTextFooter()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 
PrintImageHeader(const std::string & actual_hash,const std::string & expected_hash)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 
PrintImageBlock(const std::vector<unsigned char> & png_image)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 
PrintImageFooter()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 
PrintAudioHeader()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 
PrintAudioBlock(const std::vector<unsigned char> & audio_data)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 
PrintAudioFooter()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 
AddMessage(const std::string & message)147 void WebKitTestResultPrinter::AddMessage(const std::string& message) {
148   AddMessageRaw(message + "\n");
149 }
150 
AddMessageRaw(const std::string & message)151 void WebKitTestResultPrinter::AddMessageRaw(const std::string& message) {
152   if (state_ != DURING_TEST)
153     return;
154   *output_ << message;
155 }
156 
AddErrorMessage(const std::string & message)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 
PrintEncodedBinaryData(const std::vector<unsigned char> & data)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 
CloseStderr()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
Get()196 WebKitTestController* WebKitTestController::Get() {
197   DCHECK(instance_);
198   return instance_;
199 }
200 
WebKitTestController()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 
~WebKitTestController()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 
PrepareForLayoutTest(const GURL & test_url,const base::FilePath & current_working_directory,bool enable_pixel_dumping,const std::string & expected_pixel_hash)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 
ResetAfterLayoutTest()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 
SetTempPath(const base::FilePath & temp_path)307 void WebKitTestController::SetTempPath(const base::FilePath& temp_path) {
308   temp_path_ = temp_path;
309 }
310 
RendererUnresponsive()311 void WebKitTestController::RendererUnresponsive() {
312   DCHECK(CalledOnValidThread());
313   LOG(WARNING) << "renderer unresponsive";
314 }
315 
WorkerCrashed()316 void WebKitTestController::WorkerCrashed() {
317   DCHECK(CalledOnValidThread());
318   printer_->AddErrorMessage("#CRASHED - worker");
319   DiscardMainWindow();
320 }
321 
OverrideWebkitPrefs(WebPreferences * prefs)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 
OpenURL(const GURL & url)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 
TestFinishedInSecondaryWindow()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 
IsMainWindow(WebContents * web_contents) const355 bool WebKitTestController::IsMainWindow(WebContents* web_contents) const {
356   return main_window_ && web_contents == main_window_->web_contents();
357 }
358 
OnMessageReceived(const IPC::Message & message)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 
PluginCrashed(const base::FilePath & plugin_path,base::ProcessId plugin_pid)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 
RenderViewCreated(RenderViewHost * render_view_host)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 
RenderProcessGone(base::TerminationStatus status)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 
WebContentsDestroyed(WebContents * web_contents)420 void WebKitTestController::WebContentsDestroyed(WebContents* web_contents) {
421   DCHECK(CalledOnValidThread());
422   printer_->AddErrorMessage("FAIL: main window was destroyed");
423   DiscardMainWindow();
424 }
425 
Observe(int type,const NotificationSource & source,const NotificationDetails & details)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 
OnGpuProcessCrashed(base::TerminationStatus exit_code)450 void WebKitTestController::OnGpuProcessCrashed(
451     base::TerminationStatus exit_code) {
452   DCHECK(CalledOnValidThread());
453   printer_->AddErrorMessage("#CRASHED - gpu");
454   DiscardMainWindow();
455 }
456 
TimeoutHandler()457 void WebKitTestController::TimeoutHandler() {
458   DCHECK(CalledOnValidThread());
459   printer_->AddErrorMessage(
460       "FAIL: Timed out waiting for notifyDone to be called");
461   DiscardMainWindow();
462 }
463 
DiscardMainWindow()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 
SendTestConfiguration()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 
OnTestFinished()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 
OnImageDump(const std::string & actual_pixel_hash,const SkBitmap & image)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 
OnAudioDump(const std::vector<unsigned char> & dump)548 void WebKitTestController::OnAudioDump(const std::vector<unsigned char>& dump) {
549   printer_->PrintAudioHeader();
550   printer_->PrintAudioBlock(dump);
551   printer_->PrintAudioFooter();
552 }
553 
OnTextDump(const std::string & dump)554 void WebKitTestController::OnTextDump(const std::string& dump) {
555   printer_->PrintTextHeader();
556   printer_->PrintTextBlock(dump);
557   printer_->PrintTextFooter();
558 }
559 
OnPrintMessage(const std::string & message)560 void WebKitTestController::OnPrintMessage(const std::string& message) {
561   printer_->AddMessageRaw(message);
562 }
563 
OnOverridePreferences(const WebPreferences & prefs)564 void WebKitTestController::OnOverridePreferences(const WebPreferences& prefs) {
565   should_override_prefs_ = true;
566   prefs_ = prefs;
567 }
568 
OnShowDevTools()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 
OnCloseDevTools()579 void WebKitTestController::OnCloseDevTools() {
580   main_window_->CloseDevTools();
581 }
582 
OnGoToOffset(int offset)583 void WebKitTestController::OnGoToOffset(int offset) {
584   main_window_->GoBackOrForward(offset);
585 }
586 
OnReload()587 void WebKitTestController::OnReload() {
588   main_window_->Reload();
589 }
590 
OnLoadURLForFrame(const GURL & url,const std::string & frame_name)591 void WebKitTestController::OnLoadURLForFrame(const GURL& url,
592                                              const std::string& frame_name) {
593   main_window_->LoadURLForFrame(url, frame_name);
594 }
595 
OnCaptureSessionHistory()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 
OnCloseRemainingWindows()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 
OnResetDone()650 void WebKitTestController::OnResetDone() {
651   base::MessageLoop::current()->PostTask(FROM_HERE,
652                                          base::MessageLoop::QuitClosure());
653 }
654 
655 }  // namespace content
656