1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/shell/renderer/webkit_test_runner.h"
6
7#include <algorithm>
8#include <clocale>
9#include <cmath>
10
11#include "base/base64.h"
12#include "base/debug/debugger.h"
13#include "base/files/file_path.h"
14#include "base/md5.h"
15#include "base/memory/scoped_ptr.h"
16#include "base/message_loop/message_loop.h"
17#include "base/strings/string_util.h"
18#include "base/strings/stringprintf.h"
19#include "base/strings/sys_string_conversions.h"
20#include "base/strings/utf_string_conversions.h"
21#include "base/time/time.h"
22#include "content/public/common/url_constants.h"
23#include "content/public/renderer/history_item_serialization.h"
24#include "content/public/renderer/render_view.h"
25#include "content/public/renderer/render_view_visitor.h"
26#include "content/public/test/layouttest_support.h"
27#include "content/shell/common/shell_messages.h"
28#include "content/shell/common/webkit_test_helpers.h"
29#include "content/shell/renderer/shell_render_process_observer.h"
30#include "net/base/net_errors.h"
31#include "net/base/net_util.h"
32#include "skia/ext/platform_canvas.h"
33#include "third_party/WebKit/public/platform/Platform.h"
34#include "third_party/WebKit/public/platform/WebCString.h"
35#include "third_party/WebKit/public/platform/WebPoint.h"
36#include "third_party/WebKit/public/platform/WebRect.h"
37#include "third_party/WebKit/public/platform/WebSize.h"
38#include "third_party/WebKit/public/platform/WebString.h"
39#include "third_party/WebKit/public/platform/WebURL.h"
40#include "third_party/WebKit/public/platform/WebURLError.h"
41#include "third_party/WebKit/public/platform/WebURLRequest.h"
42#include "third_party/WebKit/public/platform/WebURLResponse.h"
43#include "third_party/WebKit/public/testing/WebTask.h"
44#include "third_party/WebKit/public/testing/WebTestInterfaces.h"
45#include "third_party/WebKit/public/testing/WebTestProxy.h"
46#include "third_party/WebKit/public/testing/WebTestRunner.h"
47#include "third_party/WebKit/public/web/WebArrayBufferView.h"
48#include "third_party/WebKit/public/web/WebContextMenuData.h"
49#include "third_party/WebKit/public/web/WebDataSource.h"
50#include "third_party/WebKit/public/web/WebDevToolsAgent.h"
51#include "third_party/WebKit/public/web/WebDeviceOrientation.h"
52#include "third_party/WebKit/public/web/WebDocument.h"
53#include "third_party/WebKit/public/web/WebElement.h"
54#include "third_party/WebKit/public/web/WebFrame.h"
55#include "third_party/WebKit/public/web/WebHistoryItem.h"
56#include "third_party/WebKit/public/web/WebKit.h"
57#include "third_party/WebKit/public/web/WebScriptSource.h"
58#include "third_party/WebKit/public/web/WebTestingSupport.h"
59#include "third_party/WebKit/public/web/WebView.h"
60#include "ui/gfx/rect.h"
61#include "webkit/common/webpreferences.h"
62#include "webkit/glue/webkit_glue.h"
63
64using WebKit::Platform;
65using WebKit::WebArrayBufferView;
66using WebKit::WebContextMenuData;
67using WebKit::WebDevToolsAgent;
68using WebKit::WebDeviceMotionData;
69using WebKit::WebDeviceOrientation;
70using WebKit::WebElement;
71using WebKit::WebFrame;
72using WebKit::WebGamepads;
73using WebKit::WebHistoryItem;
74using WebKit::WebPoint;
75using WebKit::WebRect;
76using WebKit::WebScriptSource;
77using WebKit::WebSize;
78using WebKit::WebString;
79using WebKit::WebURL;
80using WebKit::WebURLError;
81using WebKit::WebURLRequest;
82using WebKit::WebTestingSupport;
83using WebKit::WebVector;
84using WebKit::WebView;
85using WebTestRunner::WebTask;
86using WebTestRunner::WebTestInterfaces;
87using WebTestRunner::WebTestProxyBase;
88
89namespace content {
90
91namespace {
92
93void InvokeTaskHelper(void* context) {
94  WebTask* task = reinterpret_cast<WebTask*>(context);
95  task->run();
96  delete task;
97}
98
99#if !defined(OS_MACOSX)
100void MakeBitmapOpaque(SkBitmap* bitmap) {
101  SkAutoLockPixels lock(*bitmap);
102  DCHECK_EQ(bitmap->config(), SkBitmap::kARGB_8888_Config);
103  for (int y = 0; y < bitmap->height(); ++y) {
104    uint32_t* row = bitmap->getAddr32(0, y);
105    for (int x = 0; x < bitmap->width(); ++x)
106      row[x] |= 0xFF000000;  // Set alpha bits to 1.
107  }
108}
109#endif
110
111void CopyCanvasToBitmap(SkCanvas* canvas,  SkBitmap* snapshot) {
112  SkDevice* device = skia::GetTopDevice(*canvas);
113  const SkBitmap& bitmap = device->accessBitmap(false);
114  const bool success = bitmap.copyTo(snapshot, SkBitmap::kARGB_8888_Config);
115  DCHECK(success);
116
117#if !defined(OS_MACOSX)
118  // Only the expected PNGs for Mac have a valid alpha channel.
119  MakeBitmapOpaque(snapshot);
120#endif
121}
122
123class SyncNavigationStateVisitor : public RenderViewVisitor {
124 public:
125  SyncNavigationStateVisitor() {}
126  virtual ~SyncNavigationStateVisitor() {}
127
128  virtual bool Visit(RenderView* render_view) OVERRIDE {
129    SyncNavigationState(render_view);
130    return true;
131  }
132 private:
133  DISALLOW_COPY_AND_ASSIGN(SyncNavigationStateVisitor);
134};
135
136class ProxyToRenderViewVisitor : public RenderViewVisitor {
137 public:
138  explicit ProxyToRenderViewVisitor(WebTestProxyBase* proxy)
139      : proxy_(proxy),
140        render_view_(NULL) {
141  }
142  virtual ~ProxyToRenderViewVisitor() {}
143
144  RenderView* render_view() const { return render_view_; }
145
146  virtual bool Visit(RenderView* render_view) OVERRIDE {
147    WebKitTestRunner* test_runner = WebKitTestRunner::Get(render_view);
148    if (!test_runner) {
149      NOTREACHED();
150      return true;
151    }
152    if (test_runner->proxy() == proxy_) {
153      render_view_ = render_view;
154      return false;
155    }
156    return true;
157  }
158
159 private:
160  WebTestProxyBase* proxy_;
161  RenderView* render_view_;
162
163  DISALLOW_COPY_AND_ASSIGN(ProxyToRenderViewVisitor);
164};
165
166class NavigateAwayVisitor : public RenderViewVisitor {
167 public:
168  explicit NavigateAwayVisitor(RenderView* main_render_view)
169      : main_render_view_(main_render_view) {}
170  virtual ~NavigateAwayVisitor() {}
171
172  virtual bool Visit(RenderView* render_view) OVERRIDE {
173    if (render_view == main_render_view_)
174      return true;
175    render_view->GetWebView()->mainFrame()->loadRequest(
176        WebURLRequest(GURL(kAboutBlankURL)));
177    return true;
178  }
179
180 private:
181  RenderView* main_render_view_;
182
183  DISALLOW_COPY_AND_ASSIGN(NavigateAwayVisitor);
184};
185
186}  // namespace
187
188WebKitTestRunner::WebKitTestRunner(RenderView* render_view)
189    : RenderViewObserver(render_view),
190      RenderViewObserverTracker<WebKitTestRunner>(render_view),
191      proxy_(NULL),
192      focused_view_(NULL),
193      is_main_window_(false),
194      focus_on_next_commit_(false) {
195  UseMockMediaStreams(render_view);
196}
197
198WebKitTestRunner::~WebKitTestRunner() {
199}
200
201// WebTestDelegate  -----------------------------------------------------------
202
203void WebKitTestRunner::clearEditCommand() {
204  render_view()->ClearEditCommands();
205}
206
207void WebKitTestRunner::setEditCommand(const std::string& name,
208                                      const std::string& value) {
209  render_view()->SetEditCommandForNextKeyEvent(name, value);
210}
211
212void WebKitTestRunner::setGamepadData(const WebGamepads& gamepads) {
213  SetMockGamepads(gamepads);
214}
215
216void WebKitTestRunner::setDeviceMotionData(const WebDeviceMotionData& data) {
217  SetMockDeviceMotionData(data);
218}
219
220void WebKitTestRunner::printMessage(const std::string& message) {
221  Send(new ShellViewHostMsg_PrintMessage(routing_id(), message));
222}
223
224void WebKitTestRunner::postTask(WebTask* task) {
225  Platform::current()->callOnMainThread(InvokeTaskHelper, task);
226}
227
228void WebKitTestRunner::postDelayedTask(WebTask* task, long long ms) {
229  base::MessageLoop::current()->PostDelayedTask(
230      FROM_HERE,
231      base::Bind(&WebTask::run, base::Owned(task)),
232      base::TimeDelta::FromMilliseconds(ms));
233}
234
235WebString WebKitTestRunner::registerIsolatedFileSystem(
236    const WebKit::WebVector<WebKit::WebString>& absolute_filenames) {
237  std::vector<base::FilePath> files;
238  for (size_t i = 0; i < absolute_filenames.size(); ++i)
239    files.push_back(base::FilePath::FromUTF16Unsafe(absolute_filenames[i]));
240  std::string filesystem_id;
241  Send(new ShellViewHostMsg_RegisterIsolatedFileSystem(
242      routing_id(), files, &filesystem_id));
243  return WebString::fromUTF8(filesystem_id);
244}
245
246long long WebKitTestRunner::getCurrentTimeInMillisecond() {
247  return base::TimeDelta(base::Time::Now() -
248                         base::Time::UnixEpoch()).ToInternalValue() /
249         base::Time::kMicrosecondsPerMillisecond;
250}
251
252WebString WebKitTestRunner::getAbsoluteWebStringFromUTF8Path(
253    const std::string& utf8_path) {
254  base::FilePath path = base::FilePath::FromUTF8Unsafe(utf8_path);
255  if (!path.IsAbsolute()) {
256    GURL base_url =
257        net::FilePathToFileURL(test_config_.current_working_directory.Append(
258            FILE_PATH_LITERAL("foo")));
259    net::FileURLToFilePath(base_url.Resolve(utf8_path), &path);
260  }
261  return path.AsUTF16Unsafe();
262}
263
264WebURL WebKitTestRunner::localFileToDataURL(const WebURL& file_url) {
265  base::FilePath local_path;
266  if (!net::FileURLToFilePath(file_url, &local_path))
267    return WebURL();
268
269  std::string contents;
270  Send(new ShellViewHostMsg_ReadFileToString(
271        routing_id(), local_path, &contents));
272
273  std::string contents_base64;
274  if (!base::Base64Encode(contents, &contents_base64))
275    return WebURL();
276
277  const char data_url_prefix[] = "data:text/css:charset=utf-8;base64,";
278  return WebURL(GURL(data_url_prefix + contents_base64));
279}
280
281WebURL WebKitTestRunner::rewriteLayoutTestsURL(const std::string& utf8_url) {
282  const char kPrefix[] = "file:///tmp/LayoutTests/";
283  const int kPrefixLen = arraysize(kPrefix) - 1;
284
285  if (utf8_url.compare(0, kPrefixLen, kPrefix, kPrefixLen))
286    return WebURL(GURL(utf8_url));
287
288  base::FilePath replace_path =
289      ShellRenderProcessObserver::GetInstance()->webkit_source_dir().Append(
290          FILE_PATH_LITERAL("LayoutTests/"));
291#if defined(OS_WIN)
292  std::string utf8_path = WideToUTF8(replace_path.value());
293#else
294  std::string utf8_path =
295      WideToUTF8(base::SysNativeMBToWide(replace_path.value()));
296#endif
297  std::string new_url =
298      std::string("file://") + utf8_path + utf8_url.substr(kPrefixLen);
299  return WebURL(GURL(new_url));
300}
301
302WebTestRunner::WebPreferences* WebKitTestRunner::preferences() {
303  return &prefs_;
304}
305
306void WebKitTestRunner::applyPreferences() {
307  WebPreferences prefs = render_view()->GetWebkitPreferences();
308  ExportLayoutTestSpecificPreferences(prefs_, &prefs);
309  render_view()->SetWebkitPreferences(prefs);
310  Send(new ShellViewHostMsg_OverridePreferences(routing_id(), prefs));
311}
312
313std::string WebKitTestRunner::makeURLErrorDescription(
314    const WebURLError& error) {
315  std::string domain = error.domain.utf8();
316  int code = error.reason;
317
318  if (domain == net::kErrorDomain) {
319    domain = "NSURLErrorDomain";
320    switch (error.reason) {
321    case net::ERR_ABORTED:
322      code = -999;  // NSURLErrorCancelled
323      break;
324    case net::ERR_UNSAFE_PORT:
325      // Our unsafe port checking happens at the network stack level, but we
326      // make this translation here to match the behavior of stock WebKit.
327      domain = "WebKitErrorDomain";
328      code = 103;
329      break;
330    case net::ERR_ADDRESS_INVALID:
331    case net::ERR_ADDRESS_UNREACHABLE:
332    case net::ERR_NETWORK_ACCESS_DENIED:
333      code = -1004;  // NSURLErrorCannotConnectToHost
334      break;
335    }
336  } else {
337    DLOG(WARNING) << "Unknown error domain";
338  }
339
340  return base::StringPrintf("<NSError domain %s, code %d, failing URL \"%s\">",
341      domain.c_str(), code, error.unreachableURL.spec().data());
342}
343
344void WebKitTestRunner::setClientWindowRect(const WebRect& rect) {
345  ForceResizeRenderView(render_view(), WebSize(rect.width, rect.height));
346}
347
348void WebKitTestRunner::enableAutoResizeMode(const WebSize& min_size,
349                                            const WebSize& max_size) {
350  EnableAutoResizeMode(render_view(), min_size, max_size);
351}
352
353void WebKitTestRunner::disableAutoResizeMode(const WebSize& new_size) {
354  DisableAutoResizeMode(render_view(), new_size);
355  if (!new_size.isEmpty())
356    ForceResizeRenderView(render_view(), new_size);
357}
358
359void WebKitTestRunner::showDevTools() {
360  Send(new ShellViewHostMsg_ShowDevTools(routing_id()));
361}
362
363void WebKitTestRunner::closeDevTools() {
364  Send(new ShellViewHostMsg_CloseDevTools(routing_id()));
365  WebDevToolsAgent* agent = render_view()->GetWebView()->devToolsAgent();
366  if (agent)
367    agent->detach();
368}
369
370void WebKitTestRunner::evaluateInWebInspector(long call_id,
371                                              const std::string& script) {
372  WebDevToolsAgent* agent = render_view()->GetWebView()->devToolsAgent();
373  if (agent)
374    agent->evaluateInWebInspector(call_id, WebString::fromUTF8(script));
375}
376
377void WebKitTestRunner::clearAllDatabases() {
378  Send(new ShellViewHostMsg_ClearAllDatabases(routing_id()));
379}
380
381void WebKitTestRunner::setDatabaseQuota(int quota) {
382  Send(new ShellViewHostMsg_SetDatabaseQuota(routing_id(), quota));
383}
384
385void WebKitTestRunner::setDeviceScaleFactor(float factor) {
386  SetDeviceScaleFactor(render_view(), factor);
387}
388
389void WebKitTestRunner::setFocus(WebTestProxyBase* proxy, bool focus) {
390  ProxyToRenderViewVisitor visitor(proxy);
391  RenderView::ForEach(&visitor);
392  if (!visitor.render_view()) {
393    NOTREACHED();
394    return;
395  }
396
397  // Check whether the focused view was closed meanwhile.
398  if (!WebKitTestRunner::Get(focused_view_))
399    focused_view_ = NULL;
400
401  if (focus) {
402    if (focused_view_ != visitor.render_view()) {
403      if (focused_view_)
404        SetFocusAndActivate(focused_view_, false);
405      SetFocusAndActivate(visitor.render_view(), true);
406      focused_view_ = visitor.render_view();
407    }
408  } else {
409    if (focused_view_ == visitor.render_view()) {
410      SetFocusAndActivate(visitor.render_view(), false);
411      focused_view_ = NULL;
412    }
413  }
414}
415
416void WebKitTestRunner::setAcceptAllCookies(bool accept) {
417  Send(new ShellViewHostMsg_AcceptAllCookies(routing_id(), accept));
418}
419
420std::string WebKitTestRunner::pathToLocalResource(const std::string& resource) {
421#if defined(OS_WIN)
422  if (resource.find("/tmp/") == 0) {
423    // We want a temp file.
424    GURL base_url = net::FilePathToFileURL(test_config_.temp_path);
425    return base_url.Resolve(resource.substr(strlen("/tmp/"))).spec();
426  }
427#endif
428
429  // Some layout tests use file://// which we resolve as a UNC path. Normalize
430  // them to just file:///.
431  std::string result = resource;
432  while (StringToLowerASCII(result).find("file:////") == 0) {
433    result = result.substr(0, strlen("file:///")) +
434             result.substr(strlen("file:////"));
435  }
436  return rewriteLayoutTestsURL(result).spec();
437}
438
439void WebKitTestRunner::setLocale(const std::string& locale) {
440  setlocale(LC_ALL, locale.c_str());
441}
442
443void WebKitTestRunner::testFinished() {
444  if (!is_main_window_) {
445    Send(new ShellViewHostMsg_TestFinishedInSecondaryWindow(routing_id()));
446    return;
447  }
448  WebTestInterfaces* interfaces =
449      ShellRenderProcessObserver::GetInstance()->test_interfaces();
450  interfaces->setTestIsRunning(false);
451  if (interfaces->testRunner()->shouldDumpBackForwardList()) {
452    SyncNavigationStateVisitor visitor;
453    RenderView::ForEach(&visitor);
454    Send(new ShellViewHostMsg_CaptureSessionHistory(routing_id()));
455  } else {
456    CaptureDump();
457  }
458}
459
460void WebKitTestRunner::closeRemainingWindows() {
461  NavigateAwayVisitor visitor(render_view());
462  RenderView::ForEach(&visitor);
463  Send(new ShellViewHostMsg_CloseRemainingWindows(routing_id()));
464}
465
466void WebKitTestRunner::deleteAllCookies() {
467  Send(new ShellViewHostMsg_DeleteAllCookies(routing_id()));
468}
469
470int WebKitTestRunner::navigationEntryCount() {
471  return GetLocalSessionHistoryLength(render_view());
472}
473
474void WebKitTestRunner::goToOffset(int offset) {
475  Send(new ShellViewHostMsg_GoToOffset(routing_id(), offset));
476}
477
478void WebKitTestRunner::reload() {
479  Send(new ShellViewHostMsg_Reload(routing_id()));
480}
481
482void WebKitTestRunner::loadURLForFrame(const WebURL& url,
483                             const std::string& frame_name) {
484  Send(new ShellViewHostMsg_LoadURLForFrame(
485      routing_id(), url, frame_name));
486}
487
488bool WebKitTestRunner::allowExternalPages() {
489  return test_config_.allow_external_pages;
490}
491
492void WebKitTestRunner::captureHistoryForWindow(
493    WebTestProxyBase* proxy,
494    WebVector<WebKit::WebHistoryItem>* history,
495    size_t* currentEntryIndex) {
496  size_t pos = 0;
497  std::vector<int>::iterator id;
498  for (id = routing_ids_.begin(); id != routing_ids_.end(); ++id, ++pos) {
499    RenderView* render_view = RenderView::FromRoutingID(*id);
500    if (!render_view) {
501      NOTREACHED();
502      continue;
503    }
504    if (WebKitTestRunner::Get(render_view)->proxy() == proxy)
505      break;
506  }
507
508  if (id == routing_ids_.end()) {
509    NOTREACHED();
510    return;
511  }
512  size_t num_entries = session_histories_[pos].size();
513  *currentEntryIndex = current_entry_indexes_[pos];
514  WebVector<WebHistoryItem> result(num_entries);
515  for (size_t entry = 0; entry < num_entries; ++entry) {
516    result[entry] =
517        PageStateToHistoryItem(session_histories_[pos][entry]);
518  }
519  history->swap(result);
520}
521
522// RenderViewObserver  --------------------------------------------------------
523
524void WebKitTestRunner::DidClearWindowObject(WebFrame* frame) {
525  WebTestingSupport::injectInternalsObject(frame);
526  ShellRenderProcessObserver::GetInstance()->test_interfaces()->bindTo(frame);
527}
528
529bool WebKitTestRunner::OnMessageReceived(const IPC::Message& message) {
530  bool handled = true;
531  IPC_BEGIN_MESSAGE_MAP(WebKitTestRunner, message)
532    IPC_MESSAGE_HANDLER(ShellViewMsg_SetTestConfiguration,
533                        OnSetTestConfiguration)
534    IPC_MESSAGE_HANDLER(ShellViewMsg_SessionHistory, OnSessionHistory)
535    IPC_MESSAGE_HANDLER(ShellViewMsg_Reset, OnReset)
536    IPC_MESSAGE_HANDLER(ShellViewMsg_NotifyDone, OnNotifyDone)
537    IPC_MESSAGE_UNHANDLED(handled = false)
538  IPC_END_MESSAGE_MAP()
539
540  return handled;
541}
542
543void WebKitTestRunner::Navigate(const GURL& url) {
544  focus_on_next_commit_ = true;
545  if (!is_main_window_ &&
546      ShellRenderProcessObserver::GetInstance()->main_test_runner() == this) {
547    WebTestInterfaces* interfaces =
548        ShellRenderProcessObserver::GetInstance()->test_interfaces();
549    interfaces->setTestIsRunning(true);
550    interfaces->configureForTestWithURL(GURL(), false);
551    ForceResizeRenderView(render_view(), WebSize(800, 600));
552  }
553}
554
555void WebKitTestRunner::DidCommitProvisionalLoad(WebFrame* frame,
556                                                bool is_new_navigation) {
557  if (!focus_on_next_commit_)
558    return;
559  focus_on_next_commit_ = false;
560  render_view()->GetWebView()->setFocusedFrame(frame);
561}
562
563void WebKitTestRunner::DidFailProvisionalLoad(WebFrame* frame,
564                                              const WebURLError& error) {
565  focus_on_next_commit_ = false;
566}
567
568// Public methods - -----------------------------------------------------------
569
570void WebKitTestRunner::Reset() {
571  // The proxy_ is always non-NULL, it is set right after construction.
572  proxy_->setWidget(render_view()->GetWebView());
573  proxy_->reset();
574  prefs_.reset();
575  routing_ids_.clear();
576  session_histories_.clear();
577  current_entry_indexes_.clear();
578
579  render_view()->ClearEditCommands();
580  render_view()->GetWebView()->mainFrame()->setName(WebString());
581  render_view()->GetWebView()->mainFrame()->clearOpener();
582  render_view()->GetWebView()->setPageScaleFactorLimits(-1, -1);
583  render_view()->GetWebView()->setPageScaleFactor(1, WebPoint(0, 0));
584  render_view()->GetWebView()->enableFixedLayoutMode(false);
585  render_view()->GetWebView()->setFixedLayoutSize(WebSize(0, 0));
586
587  // Resetting the internals object also overrides the WebPreferences, so we
588  // have to sync them to WebKit again.
589  WebTestingSupport::resetInternalsObject(
590      render_view()->GetWebView()->mainFrame());
591  render_view()->SetWebkitPreferences(render_view()->GetWebkitPreferences());
592}
593
594// Private methods  -----------------------------------------------------------
595
596void WebKitTestRunner::CaptureDump() {
597  WebTestInterfaces* interfaces =
598      ShellRenderProcessObserver::GetInstance()->test_interfaces();
599
600  if (interfaces->testRunner()->shouldDumpAsAudio()) {
601    const WebArrayBufferView* audio_data =
602        interfaces->testRunner()->audioData();
603    std::vector<unsigned char> vector_data(
604        static_cast<const unsigned char*>(audio_data->baseAddress()),
605        static_cast<const unsigned char*>(audio_data->baseAddress()) +
606            audio_data->byteLength());
607    Send(new ShellViewHostMsg_AudioDump(routing_id(), vector_data));
608  } else {
609    Send(new ShellViewHostMsg_TextDump(routing_id(),
610                                       proxy()->captureTree(false)));
611
612    if (test_config_.enable_pixel_dumping &&
613        interfaces->testRunner()->shouldGeneratePixelResults()) {
614      SkBitmap snapshot;
615      CopyCanvasToBitmap(proxy()->capturePixels(), &snapshot);
616
617      SkAutoLockPixels snapshot_lock(snapshot);
618      base::MD5Digest digest;
619      base::MD5Sum(snapshot.getPixels(), snapshot.getSize(), &digest);
620      std::string actual_pixel_hash = base::MD5DigestToBase16(digest);
621
622      if (actual_pixel_hash == test_config_.expected_pixel_hash) {
623        SkBitmap empty_image;
624        Send(new ShellViewHostMsg_ImageDump(
625            routing_id(), actual_pixel_hash, empty_image));
626      } else {
627        Send(new ShellViewHostMsg_ImageDump(
628            routing_id(), actual_pixel_hash, snapshot));
629      }
630    }
631  }
632
633  render_view()->GetWebView()->mainFrame()->stopLoading();
634
635  base::MessageLoop::current()->PostTask(
636      FROM_HERE,
637      base::Bind(base::IgnoreResult(&WebKitTestRunner::Send),
638                 base::Unretained(this),
639                 new ShellViewHostMsg_TestFinished(routing_id())));
640}
641
642void WebKitTestRunner::OnSetTestConfiguration(
643    const ShellTestConfiguration& params) {
644  test_config_ = params;
645  is_main_window_ = true;
646
647  ForceResizeRenderView(
648      render_view(),
649      WebSize(params.initial_size.width(), params.initial_size.height()));
650  setFocus(proxy_, true);
651
652  WebTestInterfaces* interfaces =
653      ShellRenderProcessObserver::GetInstance()->test_interfaces();
654  interfaces->setTestIsRunning(true);
655  interfaces->configureForTestWithURL(params.test_url,
656                                      params.enable_pixel_dumping);
657}
658
659void WebKitTestRunner::OnSessionHistory(
660    const std::vector<int>& routing_ids,
661    const std::vector<std::vector<PageState> >& session_histories,
662    const std::vector<unsigned>& current_entry_indexes) {
663  routing_ids_ = routing_ids;
664  session_histories_ = session_histories;
665  current_entry_indexes_ = current_entry_indexes;
666  CaptureDump();
667}
668
669void WebKitTestRunner::OnReset() {
670  ShellRenderProcessObserver::GetInstance()->test_interfaces()->resetAll();
671  Reset();
672  // Navigating to about:blank will make sure that no new loads are initiated
673  // by the renderer.
674  render_view()->GetWebView()->mainFrame()->loadRequest(
675      WebURLRequest(GURL(kAboutBlankURL)));
676  Send(new ShellViewHostMsg_ResetDone(routing_id()));
677}
678
679void WebKitTestRunner::OnNotifyDone() {
680  render_view()->GetWebView()->mainFrame()->executeScript(
681      WebScriptSource(WebString::fromUTF8("testRunner.notifyDone();")));
682}
683
684}  // namespace content
685