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/command_line.h"
13#include "base/compiler_specific.h"
14#include "base/debug/debugger.h"
15#include "base/files/file_path.h"
16#include "base/md5.h"
17#include "base/memory/scoped_ptr.h"
18#include "base/message_loop/message_loop.h"
19#include "base/strings/string_util.h"
20#include "base/strings/stringprintf.h"
21#include "base/strings/sys_string_conversions.h"
22#include "base/strings/utf_string_conversions.h"
23#include "base/time/time.h"
24#include "content/public/common/content_switches.h"
25#include "content/public/common/url_constants.h"
26#include "content/public/common/web_preferences.h"
27#include "content/public/renderer/render_view.h"
28#include "content/public/renderer/render_view_visitor.h"
29#include "content/public/renderer/renderer_gamepad_provider.h"
30#include "content/public/test/layouttest_support.h"
31#include "content/shell/common/shell_messages.h"
32#include "content/shell/common/shell_switches.h"
33#include "content/shell/common/webkit_test_helpers.h"
34#include "content/shell/renderer/gc_controller.h"
35#include "content/shell/renderer/leak_detector.h"
36#include "content/shell/renderer/shell_render_process_observer.h"
37#include "content/shell/renderer/test_runner/mock_screen_orientation_client.h"
38#include "content/shell/renderer/test_runner/web_task.h"
39#include "content/shell/renderer/test_runner/web_test_interfaces.h"
40#include "content/shell/renderer/test_runner/web_test_proxy.h"
41#include "content/shell/renderer/test_runner/web_test_runner.h"
42#include "net/base/filename_util.h"
43#include "net/base/net_errors.h"
44#include "skia/ext/platform_canvas.h"
45#include "third_party/WebKit/public/platform/Platform.h"
46#include "third_party/WebKit/public/platform/WebCString.h"
47#include "third_party/WebKit/public/platform/WebPoint.h"
48#include "third_party/WebKit/public/platform/WebRect.h"
49#include "third_party/WebKit/public/platform/WebSize.h"
50#include "third_party/WebKit/public/platform/WebString.h"
51#include "third_party/WebKit/public/platform/WebURL.h"
52#include "third_party/WebKit/public/platform/WebURLError.h"
53#include "third_party/WebKit/public/platform/WebURLRequest.h"
54#include "third_party/WebKit/public/platform/WebURLResponse.h"
55#include "third_party/WebKit/public/web/WebArrayBufferView.h"
56#include "third_party/WebKit/public/web/WebContextMenuData.h"
57#include "third_party/WebKit/public/web/WebDataSource.h"
58#include "third_party/WebKit/public/web/WebDevToolsAgent.h"
59#include "third_party/WebKit/public/web/WebDocument.h"
60#include "third_party/WebKit/public/web/WebElement.h"
61#include "third_party/WebKit/public/web/WebHistoryItem.h"
62#include "third_party/WebKit/public/web/WebKit.h"
63#include "third_party/WebKit/public/web/WebLeakDetector.h"
64#include "third_party/WebKit/public/web/WebLocalFrame.h"
65#include "third_party/WebKit/public/web/WebScriptSource.h"
66#include "third_party/WebKit/public/web/WebTestingSupport.h"
67#include "third_party/WebKit/public/web/WebView.h"
68#include "ui/gfx/rect.h"
69
70using blink::Platform;
71using blink::WebArrayBufferView;
72using blink::WebContextMenuData;
73using blink::WebDevToolsAgent;
74using blink::WebDeviceMotionData;
75using blink::WebDeviceOrientationData;
76using blink::WebElement;
77using blink::WebLocalFrame;
78using blink::WebHistoryItem;
79using blink::WebLocalFrame;
80using blink::WebPoint;
81using blink::WebRect;
82using blink::WebScriptSource;
83using blink::WebSize;
84using blink::WebString;
85using blink::WebURL;
86using blink::WebURLError;
87using blink::WebURLRequest;
88using blink::WebScreenOrientationType;
89using blink::WebTestingSupport;
90using blink::WebVector;
91using blink::WebView;
92
93namespace content {
94
95namespace {
96
97void InvokeTaskHelper(void* context) {
98  WebTask* task = reinterpret_cast<WebTask*>(context);
99  task->run();
100  delete task;
101}
102
103class SyncNavigationStateVisitor : public RenderViewVisitor {
104 public:
105  SyncNavigationStateVisitor() {}
106  virtual ~SyncNavigationStateVisitor() {}
107
108  virtual bool Visit(RenderView* render_view) OVERRIDE {
109    SyncNavigationState(render_view);
110    return true;
111  }
112 private:
113  DISALLOW_COPY_AND_ASSIGN(SyncNavigationStateVisitor);
114};
115
116class ProxyToRenderViewVisitor : public RenderViewVisitor {
117 public:
118  explicit ProxyToRenderViewVisitor(WebTestProxyBase* proxy)
119      : proxy_(proxy),
120        render_view_(NULL) {
121  }
122  virtual ~ProxyToRenderViewVisitor() {}
123
124  RenderView* render_view() const { return render_view_; }
125
126  virtual bool Visit(RenderView* render_view) OVERRIDE {
127    WebKitTestRunner* test_runner = WebKitTestRunner::Get(render_view);
128    if (!test_runner) {
129      NOTREACHED();
130      return true;
131    }
132    if (test_runner->proxy() == proxy_) {
133      render_view_ = render_view;
134      return false;
135    }
136    return true;
137  }
138
139 private:
140  WebTestProxyBase* proxy_;
141  RenderView* render_view_;
142
143  DISALLOW_COPY_AND_ASSIGN(ProxyToRenderViewVisitor);
144};
145
146class NavigateAwayVisitor : public RenderViewVisitor {
147 public:
148  explicit NavigateAwayVisitor(RenderView* main_render_view)
149      : main_render_view_(main_render_view) {}
150  virtual ~NavigateAwayVisitor() {}
151
152  virtual bool Visit(RenderView* render_view) OVERRIDE {
153    if (render_view == main_render_view_)
154      return true;
155    render_view->GetWebView()->mainFrame()->loadRequest(
156        WebURLRequest(GURL(url::kAboutBlankURL)));
157    return true;
158  }
159
160 private:
161  RenderView* main_render_view_;
162
163  DISALLOW_COPY_AND_ASSIGN(NavigateAwayVisitor);
164};
165
166class UseSynchronousResizeModeVisitor : public RenderViewVisitor {
167 public:
168  explicit UseSynchronousResizeModeVisitor(bool enable) : enable_(enable) {}
169  virtual ~UseSynchronousResizeModeVisitor() {}
170
171  virtual bool Visit(RenderView* render_view) OVERRIDE {
172    UseSynchronousResizeMode(render_view, enable_);
173    return true;
174  }
175
176 private:
177  bool enable_;
178};
179
180}  // namespace
181
182WebKitTestRunner::WebKitTestRunner(RenderView* render_view)
183    : RenderViewObserver(render_view),
184      RenderViewObserverTracker<WebKitTestRunner>(render_view),
185      proxy_(NULL),
186      focused_view_(NULL),
187      is_main_window_(false),
188      focus_on_next_commit_(false),
189      leak_detector_(new LeakDetector(this)) {
190}
191
192WebKitTestRunner::~WebKitTestRunner() {
193}
194
195// WebTestDelegate  -----------------------------------------------------------
196
197void WebKitTestRunner::ClearEditCommand() {
198  render_view()->ClearEditCommands();
199}
200
201void WebKitTestRunner::SetEditCommand(const std::string& name,
202                                      const std::string& value) {
203  render_view()->SetEditCommandForNextKeyEvent(name, value);
204}
205
206void WebKitTestRunner::SetGamepadProvider(
207    scoped_ptr<RendererGamepadProvider> provider) {
208  SetMockGamepadProvider(provider.Pass());
209}
210
211void WebKitTestRunner::SetDeviceLightData(const double data) {
212  SetMockDeviceLightData(data);
213}
214
215void WebKitTestRunner::SetDeviceMotionData(const WebDeviceMotionData& data) {
216  SetMockDeviceMotionData(data);
217}
218
219void WebKitTestRunner::SetDeviceOrientationData(
220    const WebDeviceOrientationData& data) {
221  SetMockDeviceOrientationData(data);
222}
223
224void WebKitTestRunner::SetScreenOrientation(
225    const WebScreenOrientationType& orientation) {
226  MockScreenOrientationClient* mock_client =
227      proxy()->GetScreenOrientationClientMock();
228  mock_client->UpdateDeviceOrientation(
229      render_view()->GetWebView()->mainFrame()->toWebLocalFrame(), orientation);
230}
231
232void WebKitTestRunner::ResetScreenOrientation() {
233  MockScreenOrientationClient* mock_client =
234      proxy()->GetScreenOrientationClientMock();
235  mock_client->ResetData();
236}
237
238void WebKitTestRunner::DidChangeBatteryStatus(
239    const blink::WebBatteryStatus& status) {
240  MockBatteryStatusChanged(status);
241}
242
243void WebKitTestRunner::PrintMessage(const std::string& message) {
244  Send(new ShellViewHostMsg_PrintMessage(routing_id(), message));
245}
246
247void WebKitTestRunner::PostTask(WebTask* task) {
248  Platform::current()->callOnMainThread(InvokeTaskHelper, task);
249}
250
251void WebKitTestRunner::PostDelayedTask(WebTask* task, long long ms) {
252  base::MessageLoop::current()->PostDelayedTask(
253      FROM_HERE,
254      base::Bind(&WebTask::run, base::Owned(task)),
255      base::TimeDelta::FromMilliseconds(ms));
256}
257
258WebString WebKitTestRunner::RegisterIsolatedFileSystem(
259    const blink::WebVector<blink::WebString>& absolute_filenames) {
260  std::vector<base::FilePath> files;
261  for (size_t i = 0; i < absolute_filenames.size(); ++i)
262    files.push_back(base::FilePath::FromUTF16Unsafe(absolute_filenames[i]));
263  std::string filesystem_id;
264  Send(new ShellViewHostMsg_RegisterIsolatedFileSystem(
265      routing_id(), files, &filesystem_id));
266  return WebString::fromUTF8(filesystem_id);
267}
268
269long long WebKitTestRunner::GetCurrentTimeInMillisecond() {
270  return base::TimeDelta(base::Time::Now() -
271                         base::Time::UnixEpoch()).ToInternalValue() /
272         base::Time::kMicrosecondsPerMillisecond;
273}
274
275WebString WebKitTestRunner::GetAbsoluteWebStringFromUTF8Path(
276    const std::string& utf8_path) {
277  base::FilePath path = base::FilePath::FromUTF8Unsafe(utf8_path);
278  if (!path.IsAbsolute()) {
279    GURL base_url =
280        net::FilePathToFileURL(test_config_.current_working_directory.Append(
281            FILE_PATH_LITERAL("foo")));
282    net::FileURLToFilePath(base_url.Resolve(utf8_path), &path);
283  }
284  return path.AsUTF16Unsafe();
285}
286
287WebURL WebKitTestRunner::LocalFileToDataURL(const WebURL& file_url) {
288  base::FilePath local_path;
289  if (!net::FileURLToFilePath(file_url, &local_path))
290    return WebURL();
291
292  std::string contents;
293  Send(new ShellViewHostMsg_ReadFileToString(
294        routing_id(), local_path, &contents));
295
296  std::string contents_base64;
297  base::Base64Encode(contents, &contents_base64);
298
299  const char data_url_prefix[] = "data:text/css:charset=utf-8;base64,";
300  return WebURL(GURL(data_url_prefix + contents_base64));
301}
302
303WebURL WebKitTestRunner::RewriteLayoutTestsURL(const std::string& utf8_url) {
304  const char kPrefix[] = "file:///tmp/LayoutTests/";
305  const int kPrefixLen = arraysize(kPrefix) - 1;
306
307  if (utf8_url.compare(0, kPrefixLen, kPrefix, kPrefixLen))
308    return WebURL(GURL(utf8_url));
309
310  base::FilePath replace_path =
311      ShellRenderProcessObserver::GetInstance()->webkit_source_dir().Append(
312          FILE_PATH_LITERAL("LayoutTests/"));
313#if defined(OS_WIN)
314  std::string utf8_path = base::WideToUTF8(replace_path.value());
315#else
316  std::string utf8_path =
317      base::WideToUTF8(base::SysNativeMBToWide(replace_path.value()));
318#endif
319  std::string new_url =
320      std::string("file://") + utf8_path + utf8_url.substr(kPrefixLen);
321  return WebURL(GURL(new_url));
322}
323
324TestPreferences* WebKitTestRunner::Preferences() {
325  return &prefs_;
326}
327
328void WebKitTestRunner::ApplyPreferences() {
329  WebPreferences prefs = render_view()->GetWebkitPreferences();
330  ExportLayoutTestSpecificPreferences(prefs_, &prefs);
331  render_view()->SetWebkitPreferences(prefs);
332  Send(new ShellViewHostMsg_OverridePreferences(routing_id(), prefs));
333}
334
335std::string WebKitTestRunner::makeURLErrorDescription(
336    const WebURLError& error) {
337  std::string domain = error.domain.utf8();
338  int code = error.reason;
339
340  if (domain == net::kErrorDomain) {
341    domain = "NSURLErrorDomain";
342    switch (error.reason) {
343    case net::ERR_ABORTED:
344      code = -999;  // NSURLErrorCancelled
345      break;
346    case net::ERR_UNSAFE_PORT:
347      // Our unsafe port checking happens at the network stack level, but we
348      // make this translation here to match the behavior of stock WebKit.
349      domain = "WebKitErrorDomain";
350      code = 103;
351      break;
352    case net::ERR_ADDRESS_INVALID:
353    case net::ERR_ADDRESS_UNREACHABLE:
354    case net::ERR_NETWORK_ACCESS_DENIED:
355      code = -1004;  // NSURLErrorCannotConnectToHost
356      break;
357    }
358  } else {
359    DLOG(WARNING) << "Unknown error domain";
360  }
361
362  return base::StringPrintf("<NSError domain %s, code %d, failing URL \"%s\">",
363      domain.c_str(), code, error.unreachableURL.spec().data());
364}
365
366void WebKitTestRunner::UseUnfortunateSynchronousResizeMode(bool enable) {
367  UseSynchronousResizeModeVisitor visitor(enable);
368  RenderView::ForEach(&visitor);
369}
370
371void WebKitTestRunner::EnableAutoResizeMode(const WebSize& min_size,
372                                            const WebSize& max_size) {
373  content::EnableAutoResizeMode(render_view(), min_size, max_size);
374}
375
376void WebKitTestRunner::DisableAutoResizeMode(const WebSize& new_size) {
377  content::DisableAutoResizeMode(render_view(), new_size);
378  if (!new_size.isEmpty())
379    ForceResizeRenderView(render_view(), new_size);
380}
381
382void WebKitTestRunner::ClearDevToolsLocalStorage() {
383  Send(new ShellViewHostMsg_ClearDevToolsLocalStorage(routing_id()));
384}
385
386void WebKitTestRunner::ShowDevTools(const std::string& settings,
387                                    const std::string& frontend_url) {
388  Send(new ShellViewHostMsg_ShowDevTools(
389      routing_id(), settings, frontend_url));
390}
391
392void WebKitTestRunner::CloseDevTools() {
393  Send(new ShellViewHostMsg_CloseDevTools(routing_id()));
394  WebDevToolsAgent* agent = render_view()->GetWebView()->devToolsAgent();
395  if (agent)
396    agent->detach();
397}
398
399void WebKitTestRunner::EvaluateInWebInspector(long call_id,
400                                              const std::string& script) {
401  WebDevToolsAgent* agent = render_view()->GetWebView()->devToolsAgent();
402  if (agent)
403    agent->evaluateInWebInspector(call_id, WebString::fromUTF8(script));
404}
405
406void WebKitTestRunner::ClearAllDatabases() {
407  Send(new ShellViewHostMsg_ClearAllDatabases(routing_id()));
408}
409
410void WebKitTestRunner::SetDatabaseQuota(int quota) {
411  Send(new ShellViewHostMsg_SetDatabaseQuota(routing_id(), quota));
412}
413
414blink::WebNotificationPresenter::Permission
415WebKitTestRunner::CheckWebNotificationPermission(const GURL& origin) {
416  int permission = blink::WebNotificationPresenter::PermissionNotAllowed;
417  Send(new ShellViewHostMsg_CheckWebNotificationPermission(
418          routing_id(),
419          origin,
420          &permission));
421  return static_cast<blink::WebNotificationPresenter::Permission>(permission);
422}
423
424void WebKitTestRunner::GrantWebNotificationPermission(const GURL& origin,
425                                                      bool permission_granted) {
426  Send(new ShellViewHostMsg_GrantWebNotificationPermission(
427      routing_id(), origin, permission_granted));
428}
429
430void WebKitTestRunner::ClearWebNotificationPermissions() {
431  Send(new ShellViewHostMsg_ClearWebNotificationPermissions(routing_id()));
432}
433
434void WebKitTestRunner::SetDeviceScaleFactor(float factor) {
435  content::SetDeviceScaleFactor(render_view(), factor);
436}
437
438void WebKitTestRunner::SetDeviceColorProfile(const std::string& name) {
439  content::SetDeviceColorProfile(render_view(), name);
440}
441
442void WebKitTestRunner::SetFocus(WebTestProxyBase* proxy, bool focus) {
443  ProxyToRenderViewVisitor visitor(proxy);
444  RenderView::ForEach(&visitor);
445  if (!visitor.render_view()) {
446    NOTREACHED();
447    return;
448  }
449
450  // Check whether the focused view was closed meanwhile.
451  if (!WebKitTestRunner::Get(focused_view_))
452    focused_view_ = NULL;
453
454  if (focus) {
455    if (focused_view_ != visitor.render_view()) {
456      if (focused_view_)
457        SetFocusAndActivate(focused_view_, false);
458      SetFocusAndActivate(visitor.render_view(), true);
459      focused_view_ = visitor.render_view();
460    }
461  } else {
462    if (focused_view_ == visitor.render_view()) {
463      SetFocusAndActivate(visitor.render_view(), false);
464      focused_view_ = NULL;
465    }
466  }
467}
468
469void WebKitTestRunner::SetAcceptAllCookies(bool accept) {
470  Send(new ShellViewHostMsg_AcceptAllCookies(routing_id(), accept));
471}
472
473std::string WebKitTestRunner::PathToLocalResource(const std::string& resource) {
474#if defined(OS_WIN)
475  if (resource.find("/tmp/") == 0) {
476    // We want a temp file.
477    GURL base_url = net::FilePathToFileURL(test_config_.temp_path);
478    return base_url.Resolve(resource.substr(strlen("/tmp/"))).spec();
479  }
480#endif
481
482  // Some layout tests use file://// which we resolve as a UNC path. Normalize
483  // them to just file:///.
484  std::string result = resource;
485  while (base::StringToLowerASCII(result).find("file:////") == 0) {
486    result = result.substr(0, strlen("file:///")) +
487             result.substr(strlen("file:////"));
488  }
489  return RewriteLayoutTestsURL(result).spec();
490}
491
492void WebKitTestRunner::SetLocale(const std::string& locale) {
493  setlocale(LC_ALL, locale.c_str());
494}
495
496void WebKitTestRunner::TestFinished() {
497  if (!is_main_window_) {
498    Send(new ShellViewHostMsg_TestFinishedInSecondaryWindow(routing_id()));
499    return;
500  }
501  WebTestInterfaces* interfaces =
502      ShellRenderProcessObserver::GetInstance()->test_interfaces();
503  interfaces->SetTestIsRunning(false);
504  if (interfaces->TestRunner()->ShouldDumpBackForwardList()) {
505    SyncNavigationStateVisitor visitor;
506    RenderView::ForEach(&visitor);
507    Send(new ShellViewHostMsg_CaptureSessionHistory(routing_id()));
508  } else {
509    CaptureDump();
510  }
511}
512
513void WebKitTestRunner::CloseRemainingWindows() {
514  NavigateAwayVisitor visitor(render_view());
515  RenderView::ForEach(&visitor);
516  Send(new ShellViewHostMsg_CloseRemainingWindows(routing_id()));
517}
518
519void WebKitTestRunner::DeleteAllCookies() {
520  Send(new ShellViewHostMsg_DeleteAllCookies(routing_id()));
521}
522
523int WebKitTestRunner::NavigationEntryCount() {
524  return GetLocalSessionHistoryLength(render_view());
525}
526
527void WebKitTestRunner::GoToOffset(int offset) {
528  Send(new ShellViewHostMsg_GoToOffset(routing_id(), offset));
529}
530
531void WebKitTestRunner::Reload() {
532  Send(new ShellViewHostMsg_Reload(routing_id()));
533}
534
535void WebKitTestRunner::LoadURLForFrame(const WebURL& url,
536                                       const std::string& frame_name) {
537  Send(new ShellViewHostMsg_LoadURLForFrame(
538      routing_id(), url, frame_name));
539}
540
541bool WebKitTestRunner::AllowExternalPages() {
542  return test_config_.allow_external_pages;
543}
544
545std::string WebKitTestRunner::DumpHistoryForWindow(WebTestProxyBase* proxy) {
546  size_t pos = 0;
547  std::vector<int>::iterator id;
548  for (id = routing_ids_.begin(); id != routing_ids_.end(); ++id, ++pos) {
549    RenderView* render_view = RenderView::FromRoutingID(*id);
550    if (!render_view) {
551      NOTREACHED();
552      continue;
553    }
554    if (WebKitTestRunner::Get(render_view)->proxy() == proxy)
555      break;
556  }
557
558  if (id == routing_ids_.end()) {
559    NOTREACHED();
560    return std::string();
561  }
562  return DumpBackForwardList(session_histories_[pos],
563                             current_entry_indexes_[pos]);
564}
565
566// RenderViewObserver  --------------------------------------------------------
567
568void WebKitTestRunner::DidClearWindowObject(WebLocalFrame* frame) {
569  WebTestingSupport::injectInternalsObject(frame);
570  ShellRenderProcessObserver::GetInstance()->test_interfaces()->BindTo(frame);
571  GCController::Install(frame);
572}
573
574bool WebKitTestRunner::OnMessageReceived(const IPC::Message& message) {
575  bool handled = true;
576  IPC_BEGIN_MESSAGE_MAP(WebKitTestRunner, message)
577    IPC_MESSAGE_HANDLER(ShellViewMsg_SetTestConfiguration,
578                        OnSetTestConfiguration)
579    IPC_MESSAGE_HANDLER(ShellViewMsg_SessionHistory, OnSessionHistory)
580    IPC_MESSAGE_HANDLER(ShellViewMsg_Reset, OnReset)
581    IPC_MESSAGE_HANDLER(ShellViewMsg_NotifyDone, OnNotifyDone)
582    IPC_MESSAGE_HANDLER(ShellViewMsg_TryLeakDetection, OnTryLeakDetection)
583    IPC_MESSAGE_UNHANDLED(handled = false)
584  IPC_END_MESSAGE_MAP()
585
586  return handled;
587}
588
589void WebKitTestRunner::Navigate(const GURL& url) {
590  focus_on_next_commit_ = true;
591  if (!is_main_window_ &&
592      ShellRenderProcessObserver::GetInstance()->main_test_runner() == this) {
593    WebTestInterfaces* interfaces =
594        ShellRenderProcessObserver::GetInstance()->test_interfaces();
595    interfaces->SetTestIsRunning(true);
596    interfaces->ConfigureForTestWithURL(GURL(), false);
597    ForceResizeRenderView(render_view(), WebSize(800, 600));
598  }
599}
600
601void WebKitTestRunner::DidCommitProvisionalLoad(WebLocalFrame* frame,
602                                                bool is_new_navigation) {
603  if (!focus_on_next_commit_)
604    return;
605  focus_on_next_commit_ = false;
606  render_view()->GetWebView()->setFocusedFrame(frame);
607}
608
609void WebKitTestRunner::DidFailProvisionalLoad(WebLocalFrame* frame,
610                                              const WebURLError& error) {
611  focus_on_next_commit_ = false;
612}
613
614// Public methods - -----------------------------------------------------------
615
616void WebKitTestRunner::Reset() {
617  // The proxy_ is always non-NULL, it is set right after construction.
618  proxy_->set_widget(render_view()->GetWebView());
619  proxy_->Reset();
620  prefs_.Reset();
621  routing_ids_.clear();
622  session_histories_.clear();
623  current_entry_indexes_.clear();
624
625  render_view()->ClearEditCommands();
626  render_view()->GetWebView()->mainFrame()->setName(WebString());
627  render_view()->GetWebView()->mainFrame()->clearOpener();
628  render_view()->GetWebView()->setPageScaleFactorLimits(-1, -1);
629  render_view()->GetWebView()->setPageScaleFactor(1, WebPoint(0, 0));
630
631  // Resetting the internals object also overrides the WebPreferences, so we
632  // have to sync them to WebKit again.
633  WebTestingSupport::resetInternalsObject(
634      render_view()->GetWebView()->mainFrame()->toWebLocalFrame());
635  render_view()->SetWebkitPreferences(render_view()->GetWebkitPreferences());
636}
637
638// Private methods  -----------------------------------------------------------
639
640void WebKitTestRunner::CaptureDump() {
641  WebTestInterfaces* interfaces =
642      ShellRenderProcessObserver::GetInstance()->test_interfaces();
643  TRACE_EVENT0("shell", "WebKitTestRunner::CaptureDump");
644
645  if (interfaces->TestRunner()->ShouldDumpAsAudio()) {
646    std::vector<unsigned char> vector_data;
647    interfaces->TestRunner()->GetAudioData(&vector_data);
648    Send(new ShellViewHostMsg_AudioDump(routing_id(), vector_data));
649  } else {
650    Send(new ShellViewHostMsg_TextDump(routing_id(),
651                                       proxy()->CaptureTree(false)));
652
653    if (test_config_.enable_pixel_dumping &&
654        interfaces->TestRunner()->ShouldGeneratePixelResults()) {
655      CHECK(render_view()->GetWebView()->isAcceleratedCompositingActive());
656      proxy()->CapturePixelsAsync(base::Bind(
657          &WebKitTestRunner::CaptureDumpPixels, base::Unretained(this)));
658      return;
659    }
660  }
661
662  CaptureDumpComplete();
663}
664
665void WebKitTestRunner::CaptureDumpPixels(const SkBitmap& snapshot) {
666  DCHECK_NE(0, snapshot.info().fWidth);
667  DCHECK_NE(0, snapshot.info().fHeight);
668
669  SkAutoLockPixels snapshot_lock(snapshot);
670  // The snapshot arrives from the GPU process via shared memory. Because MSan
671  // can't track initializedness across processes, we must assure it that the
672  // pixels are in fact initialized.
673  MSAN_UNPOISON(snapshot.getPixels(), snapshot.getSize());
674  base::MD5Digest digest;
675  base::MD5Sum(snapshot.getPixels(), snapshot.getSize(), &digest);
676  std::string actual_pixel_hash = base::MD5DigestToBase16(digest);
677
678  if (actual_pixel_hash == test_config_.expected_pixel_hash) {
679    SkBitmap empty_image;
680    Send(new ShellViewHostMsg_ImageDump(
681        routing_id(), actual_pixel_hash, empty_image));
682  } else {
683    Send(new ShellViewHostMsg_ImageDump(
684        routing_id(), actual_pixel_hash, snapshot));
685  }
686
687  CaptureDumpComplete();
688}
689
690void WebKitTestRunner::CaptureDumpComplete() {
691  render_view()->GetWebView()->mainFrame()->stopLoading();
692
693  base::MessageLoop::current()->PostTask(
694      FROM_HERE,
695      base::Bind(base::IgnoreResult(&WebKitTestRunner::Send),
696                 base::Unretained(this),
697                 new ShellViewHostMsg_TestFinished(routing_id())));
698}
699
700void WebKitTestRunner::OnSetTestConfiguration(
701    const ShellTestConfiguration& params) {
702  test_config_ = params;
703  is_main_window_ = true;
704
705  ForceResizeRenderView(
706      render_view(),
707      WebSize(params.initial_size.width(), params.initial_size.height()));
708  SetFocus(proxy_, true);
709
710  WebTestInterfaces* interfaces =
711      ShellRenderProcessObserver::GetInstance()->test_interfaces();
712  interfaces->SetTestIsRunning(true);
713  interfaces->ConfigureForTestWithURL(params.test_url,
714                                      params.enable_pixel_dumping);
715}
716
717void WebKitTestRunner::OnSessionHistory(
718    const std::vector<int>& routing_ids,
719    const std::vector<std::vector<PageState> >& session_histories,
720    const std::vector<unsigned>& current_entry_indexes) {
721  routing_ids_ = routing_ids;
722  session_histories_ = session_histories;
723  current_entry_indexes_ = current_entry_indexes;
724  CaptureDump();
725}
726
727void WebKitTestRunner::OnReset() {
728  ShellRenderProcessObserver::GetInstance()->test_interfaces()->ResetAll();
729  Reset();
730  // Navigating to about:blank will make sure that no new loads are initiated
731  // by the renderer.
732  render_view()->GetWebView()->mainFrame()->loadRequest(
733      WebURLRequest(GURL(url::kAboutBlankURL)));
734  Send(new ShellViewHostMsg_ResetDone(routing_id()));
735}
736
737void WebKitTestRunner::OnNotifyDone() {
738  render_view()->GetWebView()->mainFrame()->executeScript(
739      WebScriptSource(WebString::fromUTF8("testRunner.notifyDone();")));
740}
741
742void WebKitTestRunner::OnTryLeakDetection() {
743  WebLocalFrame* main_frame =
744      render_view()->GetWebView()->mainFrame()->toWebLocalFrame();
745  DCHECK_EQ(GURL(url::kAboutBlankURL), GURL(main_frame->document().url()));
746  DCHECK(!main_frame->isLoading());
747
748  leak_detector_->TryLeakDetection(main_frame);
749}
750
751void WebKitTestRunner::ReportLeakDetectionResult(
752    const LeakDetectionResult& report) {
753  Send(new ShellViewHostMsg_LeakDetectionDone(routing_id(), report));
754}
755
756}  // namespace content
757