1// Copyright 2014 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/test_runner/web_test_proxy.h"
6
7#include <cctype>
8
9#include "base/callback_helpers.h"
10#include "base/command_line.h"
11#include "base/debug/trace_event.h"
12#include "base/logging.h"
13#include "base/strings/string_util.h"
14#include "base/strings/stringprintf.h"
15#include "base/strings/utf_string_conversions.h"
16#include "content/public/common/content_switches.h"
17#include "content/shell/renderer/test_runner/accessibility_controller.h"
18#include "content/shell/renderer/test_runner/event_sender.h"
19#include "content/shell/renderer/test_runner/mock_color_chooser.h"
20#include "content/shell/renderer/test_runner/mock_credential_manager_client.h"
21#include "content/shell/renderer/test_runner/mock_screen_orientation_client.h"
22#include "content/shell/renderer/test_runner/mock_web_push_client.h"
23#include "content/shell/renderer/test_runner/mock_web_speech_recognizer.h"
24#include "content/shell/renderer/test_runner/mock_web_user_media_client.h"
25#include "content/shell/renderer/test_runner/spell_check_client.h"
26#include "content/shell/renderer/test_runner/test_interfaces.h"
27#include "content/shell/renderer/test_runner/test_plugin.h"
28#include "content/shell/renderer/test_runner/test_runner.h"
29#include "content/shell/renderer/test_runner/web_test_delegate.h"
30#include "content/shell/renderer/test_runner/web_test_interfaces.h"
31#include "content/shell/renderer/test_runner/web_test_runner.h"
32// FIXME: Including platform_canvas.h here is a layering violation.
33#include "skia/ext/platform_canvas.h"
34#include "third_party/WebKit/public/platform/Platform.h"
35#include "third_party/WebKit/public/platform/WebCString.h"
36#include "third_party/WebKit/public/platform/WebClipboard.h"
37#include "third_party/WebKit/public/platform/WebCompositeAndReadbackAsyncCallback.h"
38#include "third_party/WebKit/public/platform/WebURLError.h"
39#include "third_party/WebKit/public/platform/WebURLRequest.h"
40#include "third_party/WebKit/public/platform/WebURLResponse.h"
41#include "third_party/WebKit/public/web/WebAXEnums.h"
42#include "third_party/WebKit/public/web/WebAXObject.h"
43#include "third_party/WebKit/public/web/WebCachedURLRequest.h"
44#include "third_party/WebKit/public/web/WebConsoleMessage.h"
45#include "third_party/WebKit/public/web/WebDataSource.h"
46#include "third_party/WebKit/public/web/WebDocument.h"
47#include "third_party/WebKit/public/web/WebElement.h"
48#include "third_party/WebKit/public/web/WebHistoryItem.h"
49#include "third_party/WebKit/public/web/WebLocalFrame.h"
50#include "third_party/WebKit/public/web/WebMIDIClientMock.h"
51#include "third_party/WebKit/public/web/WebNode.h"
52#include "third_party/WebKit/public/web/WebPagePopup.h"
53#include "third_party/WebKit/public/web/WebPluginParams.h"
54#include "third_party/WebKit/public/web/WebPrintParams.h"
55#include "third_party/WebKit/public/web/WebRange.h"
56#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
57#include "third_party/WebKit/public/web/WebView.h"
58#include "third_party/WebKit/public/web/WebWidgetClient.h"
59
60namespace content {
61
62namespace {
63
64class CaptureCallback : public blink::WebCompositeAndReadbackAsyncCallback {
65 public:
66  CaptureCallback(const base::Callback<void(const SkBitmap&)>& callback);
67  virtual ~CaptureCallback();
68
69  void set_wait_for_popup(bool wait) { wait_for_popup_ = wait; }
70  void set_popup_position(const gfx::Point& position) {
71    popup_position_ = position;
72  }
73
74  // WebCompositeAndReadbackAsyncCallback implementation.
75  virtual void didCompositeAndReadback(const SkBitmap& bitmap);
76
77 private:
78  base::Callback<void(const SkBitmap&)> callback_;
79  SkBitmap main_bitmap_;
80  bool wait_for_popup_;
81  gfx::Point popup_position_;
82};
83
84class HostMethodTask : public WebMethodTask<WebTestProxyBase> {
85 public:
86  typedef void (WebTestProxyBase::*CallbackMethodType)();
87  HostMethodTask(WebTestProxyBase* object, CallbackMethodType callback)
88      : WebMethodTask<WebTestProxyBase>(object), callback_(callback) {}
89
90  virtual void RunIfValid() OVERRIDE { (object_->*callback_)(); }
91
92 private:
93  CallbackMethodType callback_;
94};
95
96void PrintFrameDescription(WebTestDelegate* delegate, blink::WebFrame* frame) {
97  std::string name8 = frame->uniqueName().utf8();
98  if (frame == frame->view()->mainFrame()) {
99    if (!name8.length()) {
100      delegate->PrintMessage("main frame");
101      return;
102    }
103    delegate->PrintMessage(std::string("main frame \"") + name8 + "\"");
104    return;
105  }
106  if (!name8.length()) {
107    delegate->PrintMessage("frame (anonymous)");
108    return;
109  }
110  delegate->PrintMessage(std::string("frame \"") + name8 + "\"");
111}
112
113void PrintFrameuserGestureStatus(WebTestDelegate* delegate,
114                                 blink::WebFrame* frame,
115                                 const char* msg) {
116  bool is_user_gesture =
117      blink::WebUserGestureIndicator::isProcessingUserGesture();
118  delegate->PrintMessage(std::string("Frame with user gesture \"") +
119                         (is_user_gesture ? "true" : "false") + "\"" + msg);
120}
121
122// Used to write a platform neutral file:/// URL by taking the
123// filename and its directory. (e.g., converts
124// "file:///tmp/foo/bar.txt" to just "bar.txt").
125std::string DescriptionSuitableForTestResult(const std::string& url) {
126  if (url.empty() || std::string::npos == url.find("file://"))
127    return url;
128
129  size_t pos = url.rfind('/');
130  if (pos == std::string::npos || !pos)
131    return "ERROR:" + url;
132  pos = url.rfind('/', pos - 1);
133  if (pos == std::string::npos)
134    return "ERROR:" + url;
135
136  return url.substr(pos + 1);
137}
138
139void PrintResponseDescription(WebTestDelegate* delegate,
140                              const blink::WebURLResponse& response) {
141  if (response.isNull()) {
142    delegate->PrintMessage("(null)");
143    return;
144  }
145  delegate->PrintMessage(base::StringPrintf(
146      "<NSURLResponse %s, http status code %d>",
147      DescriptionSuitableForTestResult(response.url().spec()).c_str(),
148      response.httpStatusCode()));
149}
150
151std::string URLDescription(const GURL& url) {
152  if (url.SchemeIs(url::kFileScheme))
153    return url.ExtractFileName();
154  return url.possibly_invalid_spec();
155}
156
157std::string PriorityDescription(
158    const blink::WebURLRequest::Priority& priority) {
159  switch (priority) {
160    case blink::WebURLRequest::PriorityVeryLow:
161      return "VeryLow";
162    case blink::WebURLRequest::PriorityLow:
163      return "Low";
164    case blink::WebURLRequest::PriorityMedium:
165      return "Medium";
166    case blink::WebURLRequest::PriorityHigh:
167      return "High";
168    case blink::WebURLRequest::PriorityVeryHigh:
169      return "VeryHigh";
170    case blink::WebURLRequest::PriorityUnresolved:
171    default:
172      return "Unresolved";
173  }
174}
175
176void BlockRequest(blink::WebURLRequest& request) {
177  request.setURL(GURL("255.255.255.255"));
178}
179
180bool IsLocalHost(const std::string& host) {
181  return host == "127.0.0.1" || host == "localhost";
182}
183
184bool IsTestHost(const std::string& host) {
185  return EndsWith(host, ".test", false);
186}
187
188bool HostIsUsedBySomeTestsToGenerateError(const std::string& host) {
189  return host == "255.255.255.255";
190}
191
192// Used to write a platform neutral file:/// URL by only taking the filename
193// (e.g., converts "file:///tmp/foo.txt" to just "foo.txt").
194std::string URLSuitableForTestResult(const std::string& url) {
195  if (url.empty() || std::string::npos == url.find("file://"))
196    return url;
197
198  size_t pos = url.rfind('/');
199  if (pos == std::string::npos) {
200#ifdef WIN32
201    pos = url.rfind('\\');
202    if (pos == std::string::npos)
203      pos = 0;
204#else
205    pos = 0;
206#endif
207  }
208  std::string filename = url.substr(pos + 1);
209  if (filename.empty())
210    return "file:";  // A WebKit test has this in its expected output.
211  return filename;
212}
213
214// WebNavigationType debugging strings taken from PolicyDelegate.mm.
215const char* kLinkClickedString = "link clicked";
216const char* kFormSubmittedString = "form submitted";
217const char* kBackForwardString = "back/forward";
218const char* kReloadString = "reload";
219const char* kFormResubmittedString = "form resubmitted";
220const char* kOtherString = "other";
221const char* kIllegalString = "illegal value";
222
223// Get a debugging string from a WebNavigationType.
224const char* WebNavigationTypeToString(blink::WebNavigationType type) {
225  switch (type) {
226    case blink::WebNavigationTypeLinkClicked:
227      return kLinkClickedString;
228    case blink::WebNavigationTypeFormSubmitted:
229      return kFormSubmittedString;
230    case blink::WebNavigationTypeBackForward:
231      return kBackForwardString;
232    case blink::WebNavigationTypeReload:
233      return kReloadString;
234    case blink::WebNavigationTypeFormResubmitted:
235      return kFormResubmittedString;
236    case blink::WebNavigationTypeOther:
237      return kOtherString;
238  }
239  return kIllegalString;
240}
241
242std::string DumpFrameHeaderIfNeeded(blink::WebFrame* frame) {
243  std::string result;
244
245  // Add header for all but the main frame. Skip empty frames.
246  if (frame->parent() && !frame->document().documentElement().isNull()) {
247    result.append("\n--------\nFrame: '");
248    result.append(frame->uniqueName().utf8().data());
249    result.append("'\n--------\n");
250  }
251
252  return result;
253}
254
255std::string DumpFramesAsMarkup(blink::WebFrame* frame, bool recursive) {
256  std::string result = DumpFrameHeaderIfNeeded(frame);
257  result.append(frame->contentAsMarkup().utf8());
258  result.append("\n");
259
260  if (recursive) {
261    for (blink::WebFrame* child = frame->firstChild(); child;
262         child = child->nextSibling())
263      result.append(DumpFramesAsMarkup(child, recursive));
264  }
265
266  return result;
267}
268
269std::string DumpDocumentText(blink::WebFrame* frame) {
270  // We use the document element's text instead of the body text here because
271  // not all documents have a body, such as XML documents.
272  blink::WebElement document_element = frame->document().documentElement();
273  if (document_element.isNull())
274    return std::string();
275  return document_element.innerText().utf8();
276}
277
278std::string DumpFramesAsText(blink::WebFrame* frame, bool recursive) {
279  std::string result = DumpFrameHeaderIfNeeded(frame);
280  result.append(DumpDocumentText(frame));
281  result.append("\n");
282
283  if (recursive) {
284    for (blink::WebFrame* child = frame->firstChild(); child;
285         child = child->nextSibling())
286      result.append(DumpFramesAsText(child, recursive));
287  }
288
289  return result;
290}
291
292std::string DumpFramesAsPrintedText(blink::WebFrame* frame, bool recursive) {
293  // Cannot do printed format for anything other than HTML
294  if (!frame->document().isHTMLDocument())
295    return std::string();
296
297  std::string result = DumpFrameHeaderIfNeeded(frame);
298  result.append(
299      frame->renderTreeAsText(blink::WebFrame::RenderAsTextPrinting).utf8());
300  result.append("\n");
301
302  if (recursive) {
303    for (blink::WebFrame* child = frame->firstChild(); child;
304         child = child->nextSibling())
305      result.append(DumpFramesAsPrintedText(child, recursive));
306  }
307
308  return result;
309}
310
311std::string DumpFrameScrollPosition(blink::WebFrame* frame, bool recursive) {
312  std::string result;
313  blink::WebSize offset = frame->scrollOffset();
314  if (offset.width > 0 || offset.height > 0) {
315    if (frame->parent()) {
316      result =
317          std::string("frame '") + frame->uniqueName().utf8().data() + "' ";
318    }
319    base::StringAppendF(
320        &result, "scrolled to %d,%d\n", offset.width, offset.height);
321  }
322
323  if (!recursive)
324    return result;
325  for (blink::WebFrame* child = frame->firstChild(); child;
326       child = child->nextSibling())
327    result += DumpFrameScrollPosition(child, recursive);
328  return result;
329}
330
331std::string DumpAllBackForwardLists(TestInterfaces* interfaces,
332                                    WebTestDelegate* delegate) {
333  std::string result;
334  const std::vector<WebTestProxyBase*>& window_list =
335      interfaces->GetWindowList();
336  for (size_t i = 0; i < window_list.size(); ++i)
337    result.append(delegate->DumpHistoryForWindow(window_list.at(i)));
338  return result;
339}
340}
341
342WebTestProxyBase::WebTestProxyBase()
343    : test_interfaces_(NULL),
344      delegate_(NULL),
345      web_widget_(NULL),
346      spellcheck_(new SpellCheckClient(this)),
347      chooser_count_(0) {
348  // TODO(enne): using the scheduler introduces additional composite steps
349  // that create flakiness.  This should go away eventually.
350  base::CommandLine::ForCurrentProcess()->AppendSwitch(
351      switches::kDisableSingleThreadProxyScheduler);
352  Reset();
353}
354
355WebTestProxyBase::~WebTestProxyBase() {
356  test_interfaces_->WindowClosed(this);
357}
358
359void WebTestProxyBase::SetInterfaces(WebTestInterfaces* interfaces) {
360  test_interfaces_ = interfaces->GetTestInterfaces();
361  test_interfaces_->WindowOpened(this);
362}
363
364void WebTestProxyBase::SetDelegate(WebTestDelegate* delegate) {
365  delegate_ = delegate;
366  spellcheck_->SetDelegate(delegate);
367  if (speech_recognizer_.get())
368    speech_recognizer_->SetDelegate(delegate);
369}
370
371blink::WebView* WebTestProxyBase::GetWebView() const {
372  DCHECK(web_widget_);
373  // TestRunner does not support popup widgets. So |web_widget|_ is always a
374  // WebView.
375  return static_cast<blink::WebView*>(web_widget_);
376}
377
378void WebTestProxyBase::Reset() {
379  animate_scheduled_ = false;
380  resource_identifier_map_.clear();
381  log_console_output_ = true;
382  if (midi_client_.get())
383    midi_client_->resetMock();
384  accept_languages_ = "";
385}
386
387blink::WebSpellCheckClient* WebTestProxyBase::GetSpellCheckClient() const {
388  return spellcheck_.get();
389}
390
391blink::WebColorChooser* WebTestProxyBase::CreateColorChooser(
392    blink::WebColorChooserClient* client,
393    const blink::WebColor& color,
394    const blink::WebVector<blink::WebColorSuggestion>& suggestions) {
395  // This instance is deleted by WebCore::ColorInputType
396  return new MockColorChooser(client, delegate_, this);
397}
398
399bool WebTestProxyBase::RunFileChooser(
400    const blink::WebFileChooserParams& params,
401    blink::WebFileChooserCompletion* completion) {
402  delegate_->PrintMessage("Mock: Opening a file chooser.\n");
403  // FIXME: Add ability to set file names to a file upload control.
404  return false;
405}
406
407void WebTestProxyBase::ShowValidationMessage(
408    const base::string16& message,
409    const base::string16& sub_message) {
410  delegate_->PrintMessage("ValidationMessageClient: main-message=" +
411                          base::UTF16ToUTF8(message) + " sub-message=" +
412                          base::UTF16ToUTF8(sub_message) + "\n");
413}
414
415std::string WebTestProxyBase::CaptureTree(bool debug_render_tree) {
416  bool should_dump_custom_text =
417      test_interfaces_->GetTestRunner()->shouldDumpAsCustomText();
418  bool should_dump_as_text =
419      test_interfaces_->GetTestRunner()->shouldDumpAsText();
420  bool should_dump_as_markup =
421      test_interfaces_->GetTestRunner()->shouldDumpAsMarkup();
422  bool should_dump_as_printed = test_interfaces_->GetTestRunner()->isPrinting();
423  blink::WebFrame* frame = GetWebView()->mainFrame();
424  std::string data_utf8;
425  if (should_dump_custom_text) {
426    // Append a newline for the test driver.
427    data_utf8 = test_interfaces_->GetTestRunner()->customDumpText() + "\n";
428  } else if (should_dump_as_text) {
429    bool recursive =
430        test_interfaces_->GetTestRunner()->shouldDumpChildFramesAsText();
431    data_utf8 = should_dump_as_printed ?
432        DumpFramesAsPrintedText(frame, recursive) :
433        DumpFramesAsText(frame, recursive);
434  } else if (should_dump_as_markup) {
435    bool recursive =
436        test_interfaces_->GetTestRunner()->shouldDumpChildFramesAsMarkup();
437    // Append a newline for the test driver.
438    data_utf8 = DumpFramesAsMarkup(frame, recursive);
439  } else {
440    bool recursive = test_interfaces_->GetTestRunner()
441                         ->shouldDumpChildFrameScrollPositions();
442    blink::WebFrame::RenderAsTextControls render_text_behavior =
443        blink::WebFrame::RenderAsTextNormal;
444    if (should_dump_as_printed)
445      render_text_behavior |= blink::WebFrame::RenderAsTextPrinting;
446    if (debug_render_tree)
447      render_text_behavior |= blink::WebFrame::RenderAsTextDebug;
448    data_utf8 = frame->renderTreeAsText(render_text_behavior).utf8();
449    data_utf8 += DumpFrameScrollPosition(frame, recursive);
450  }
451
452  if (test_interfaces_->GetTestRunner()->ShouldDumpBackForwardList())
453    data_utf8 += DumpAllBackForwardLists(test_interfaces_, delegate_);
454
455  return data_utf8;
456}
457
458void WebTestProxyBase::DrawSelectionRect(SkCanvas* canvas) {
459  // See if we need to draw the selection bounds rect. Selection bounds
460  // rect is the rect enclosing the (possibly transformed) selection.
461  // The rect should be drawn after everything is laid out and painted.
462  if (!test_interfaces_->GetTestRunner()->shouldDumpSelectionRect())
463    return;
464  // If there is a selection rect - draw a red 1px border enclosing rect
465  blink::WebRect wr = GetWebView()->mainFrame()->selectionBoundsRect();
466  if (wr.isEmpty())
467    return;
468  // Render a red rectangle bounding selection rect
469  SkPaint paint;
470  paint.setColor(0xFFFF0000);  // Fully opaque red
471  paint.setStyle(SkPaint::kStroke_Style);
472  paint.setFlags(SkPaint::kAntiAlias_Flag);
473  paint.setStrokeWidth(1.0f);
474  SkIRect rect;  // Bounding rect
475  rect.set(wr.x, wr.y, wr.x + wr.width, wr.y + wr.height);
476  canvas->drawIRect(rect, paint);
477}
478
479void WebTestProxyBase::SetAcceptLanguages(const std::string& accept_languages) {
480  bool notify = accept_languages_ != accept_languages;
481  accept_languages_ = accept_languages;
482
483  if (notify)
484    GetWebView()->acceptLanguagesChanged();
485}
486
487void WebTestProxyBase::CopyImageAtAndCapturePixels(
488    int x, int y, const base::Callback<void(const SkBitmap&)>& callback) {
489  // It may happen that there is a scheduled animation and
490  // no rootGraphicsLayer yet. If so we would run it right now. Otherwise
491  // isAcceleratedCompositingActive will return false;
492  // TODO(enne): remove this: http://crbug.com/397321
493  AnimateNow();
494
495  DCHECK(!callback.is_null());
496  uint64_t sequence_number =  blink::Platform::current()->clipboard()->
497      sequenceNumber(blink::WebClipboard::Buffer());
498  GetWebView()->copyImageAt(blink::WebPoint(x, y));
499  if (sequence_number == blink::Platform::current()->clipboard()->
500      sequenceNumber(blink::WebClipboard::Buffer())) {
501    SkBitmap emptyBitmap;
502    callback.Run(emptyBitmap);
503    return;
504  }
505
506  blink::WebData data = blink::Platform::current()->clipboard()->readImage(
507      blink::WebClipboard::Buffer());
508  blink::WebImage image = blink::WebImage::fromData(data, blink::WebSize());
509  const SkBitmap& bitmap = image.getSkBitmap();
510  SkAutoLockPixels autoLock(bitmap);
511  callback.Run(bitmap);
512}
513
514void WebTestProxyBase::CapturePixelsForPrinting(
515    const base::Callback<void(const SkBitmap&)>& callback) {
516  web_widget_->layout();
517
518  blink::WebSize page_size_in_pixels = web_widget_->size();
519  blink::WebFrame* web_frame = GetWebView()->mainFrame();
520
521  int page_count = web_frame->printBegin(page_size_in_pixels);
522  int totalHeight = page_count * (page_size_in_pixels.height + 1) - 1;
523
524  bool is_opaque = false;
525  skia::RefPtr<SkCanvas> canvas(skia::AdoptRef(skia::TryCreateBitmapCanvas(
526      page_size_in_pixels.width, totalHeight, is_opaque)));
527  if (!canvas) {
528    callback.Run(SkBitmap());
529    return;
530  }
531  web_frame->printPagesWithBoundaries(canvas.get(), page_size_in_pixels);
532  web_frame->printEnd();
533
534  DrawSelectionRect(canvas.get());
535  SkBaseDevice* device = skia::GetTopDevice(*canvas);
536  const SkBitmap& bitmap = device->accessBitmap(false);
537  callback.Run(bitmap);
538}
539
540CaptureCallback::CaptureCallback(
541    const base::Callback<void(const SkBitmap&)>& callback)
542    : callback_(callback), wait_for_popup_(false) {
543}
544
545CaptureCallback::~CaptureCallback() {
546}
547
548void CaptureCallback::didCompositeAndReadback(const SkBitmap& bitmap) {
549  TRACE_EVENT2("shell",
550               "CaptureCallback::didCompositeAndReadback",
551               "x",
552               bitmap.info().fWidth,
553               "y",
554               bitmap.info().fHeight);
555  if (!wait_for_popup_) {
556    callback_.Run(bitmap);
557    delete this;
558    return;
559  }
560  if (main_bitmap_.isNull()) {
561    bitmap.deepCopyTo(&main_bitmap_);
562    return;
563  }
564  SkCanvas canvas(main_bitmap_);
565  canvas.drawBitmap(bitmap, popup_position_.x(), popup_position_.y());
566  callback_.Run(main_bitmap_);
567  delete this;
568}
569
570void WebTestProxyBase::CapturePixelsAsync(
571    const base::Callback<void(const SkBitmap&)>& callback) {
572  TRACE_EVENT0("shell", "WebTestProxyBase::CapturePixelsAsync");
573
574  // It may happen that there is a scheduled animation and
575  // no rootGraphicsLayer yet. If so we would run it right now. Otherwise
576  // isAcceleratedCompositingActive will return false;
577  // TODO(enne): remove this: http://crbug.com/397321
578  AnimateNow();
579
580  DCHECK(!callback.is_null());
581
582  if (test_interfaces_->GetTestRunner()->isPrinting()) {
583    base::MessageLoopProxy::current()->PostTask(
584        FROM_HERE,
585        base::Bind(&WebTestProxyBase::CapturePixelsForPrinting,
586                   base::Unretained(this),
587                   callback));
588    return;
589  }
590
591  CaptureCallback* capture_callback = new CaptureCallback(base::Bind(
592      &WebTestProxyBase::DidCapturePixelsAsync, base::Unretained(this),
593      callback));
594  web_widget_->compositeAndReadbackAsync(capture_callback);
595  if (blink::WebPagePopup* popup = web_widget_->pagePopup()) {
596    capture_callback->set_wait_for_popup(true);
597    capture_callback->set_popup_position(popup->positionRelativeToOwner());
598    popup->compositeAndReadbackAsync(capture_callback);
599  }
600}
601
602void WebTestProxyBase::DidCapturePixelsAsync(const base::Callback<void(const SkBitmap&)>& callback,
603                                             const SkBitmap& bitmap) {
604  SkCanvas canvas(bitmap);
605  DrawSelectionRect(&canvas);
606  if (!callback.is_null())
607    callback.Run(bitmap);
608}
609
610void WebTestProxyBase::SetLogConsoleOutput(bool enabled) {
611  log_console_output_ = enabled;
612}
613
614void WebTestProxyBase::DidDisplayAsync(const base::Closure& callback,
615                                       const SkBitmap& bitmap) {
616  // Verify we actually composited.
617  CHECK_NE(0, bitmap.info().fWidth);
618  CHECK_NE(0, bitmap.info().fHeight);
619  if (!callback.is_null())
620    callback.Run();
621}
622
623void WebTestProxyBase::DisplayAsyncThen(const base::Closure& callback) {
624  TRACE_EVENT0("shell", "WebTestProxyBase::DisplayAsyncThen");
625
626  // It may happen that there is a scheduled animation and
627  // no rootGraphicsLayer yet. If so we would run it right now. Otherwise
628  // isAcceleratedCompositingActive will return false;
629  // TODO(enne): remove this: http://crbug.com/397321
630  AnimateNow();
631
632  CapturePixelsAsync(base::Bind(
633      &WebTestProxyBase::DidDisplayAsync, base::Unretained(this), callback));
634}
635
636void WebTestProxyBase::GetScreenOrientationForTesting(
637    blink::WebScreenInfo& screen_info) {
638  if (!screen_orientation_client_)
639    return;
640  // Override screen orientation information with mock data.
641  screen_info.orientationType =
642      screen_orientation_client_->CurrentOrientationType();
643  screen_info.orientationAngle =
644      screen_orientation_client_->CurrentOrientationAngle();
645}
646
647MockScreenOrientationClient*
648WebTestProxyBase::GetScreenOrientationClientMock() {
649  if (!screen_orientation_client_.get()) {
650    screen_orientation_client_.reset(new MockScreenOrientationClient);
651  }
652  return screen_orientation_client_.get();
653}
654
655blink::WebMIDIClientMock* WebTestProxyBase::GetMIDIClientMock() {
656  if (!midi_client_.get())
657    midi_client_.reset(new blink::WebMIDIClientMock);
658  return midi_client_.get();
659}
660
661MockWebSpeechRecognizer* WebTestProxyBase::GetSpeechRecognizerMock() {
662  if (!speech_recognizer_.get()) {
663    speech_recognizer_.reset(new MockWebSpeechRecognizer());
664    speech_recognizer_->SetDelegate(delegate_);
665  }
666  return speech_recognizer_.get();
667}
668
669MockCredentialManagerClient*
670WebTestProxyBase::GetCredentialManagerClientMock() {
671  if (!credential_manager_client_.get())
672    credential_manager_client_.reset(new MockCredentialManagerClient());
673  return credential_manager_client_.get();
674}
675
676void WebTestProxyBase::ScheduleAnimation() {
677  if (!test_interfaces_->GetTestRunner()->TestIsRunning())
678    return;
679
680  if (!animate_scheduled_) {
681    animate_scheduled_ = true;
682    delegate_->PostDelayedTask(
683        new HostMethodTask(this, &WebTestProxyBase::AnimateNow), 1);
684  }
685}
686
687void WebTestProxyBase::AnimateNow() {
688  if (animate_scheduled_) {
689    animate_scheduled_ = false;
690    web_widget_->animate(0.0);
691    web_widget_->layout();
692  }
693}
694
695void WebTestProxyBase::PostAccessibilityEvent(const blink::WebAXObject& obj,
696                                              blink::WebAXEvent event) {
697  // Only hook the accessibility events occured during the test run.
698  // This check prevents false positives in WebLeakDetector.
699  // The pending tasks in browser/renderer message queue may trigger
700  // accessibility events,
701  // and AccessibilityController will hold on to their target nodes if we don't
702  // ignore them here.
703  if (!test_interfaces_->GetTestRunner()->TestIsRunning())
704    return;
705
706  if (event == blink::WebAXEventFocus)
707    test_interfaces_->GetAccessibilityController()->SetFocusedElement(obj);
708
709  const char* event_name = NULL;
710  switch (event) {
711    case blink::WebAXEventActiveDescendantChanged:
712      event_name = "ActiveDescendantChanged";
713      break;
714    case blink::WebAXEventAlert:
715      event_name = "Alert";
716      break;
717    case blink::WebAXEventAriaAttributeChanged:
718      event_name = "AriaAttributeChanged";
719      break;
720    case blink::WebAXEventAutocorrectionOccured:
721      event_name = "AutocorrectionOccured";
722      break;
723    case blink::WebAXEventBlur:
724      event_name = "Blur";
725      break;
726    case blink::WebAXEventCheckedStateChanged:
727      event_name = "CheckedStateChanged";
728      break;
729    case blink::WebAXEventChildrenChanged:
730      event_name = "ChildrenChanged";
731      break;
732    case blink::WebAXEventFocus:
733      event_name = "Focus";
734      break;
735    case blink::WebAXEventHide:
736      event_name = "Hide";
737      break;
738    case blink::WebAXEventInvalidStatusChanged:
739      event_name = "InvalidStatusChanged";
740      break;
741    case blink::WebAXEventLayoutComplete:
742      event_name = "LayoutComplete";
743      break;
744    case blink::WebAXEventLiveRegionChanged:
745      event_name = "LiveRegionChanged";
746      break;
747    case blink::WebAXEventLoadComplete:
748      event_name = "LoadComplete";
749      break;
750    case blink::WebAXEventLocationChanged:
751      event_name = "LocationChanged";
752      break;
753    case blink::WebAXEventMenuListItemSelected:
754      event_name = "MenuListItemSelected";
755      break;
756    case blink::WebAXEventMenuListValueChanged:
757      event_name = "MenuListValueChanged";
758      break;
759    case blink::WebAXEventRowCollapsed:
760      event_name = "RowCollapsed";
761      break;
762    case blink::WebAXEventRowCountChanged:
763      event_name = "RowCountChanged";
764      break;
765    case blink::WebAXEventRowExpanded:
766      event_name = "RowExpanded";
767      break;
768    case blink::WebAXEventScrollPositionChanged:
769      event_name = "ScrollPositionChanged";
770      break;
771    case blink::WebAXEventScrolledToAnchor:
772      event_name = "ScrolledToAnchor";
773      break;
774    case blink::WebAXEventSelectedChildrenChanged:
775      event_name = "SelectedChildrenChanged";
776      break;
777    case blink::WebAXEventSelectedTextChanged:
778      event_name = "SelectedTextChanged";
779      break;
780    case blink::WebAXEventShow:
781      event_name = "Show";
782      break;
783    case blink::WebAXEventTextChanged:
784      event_name = "TextChanged";
785      break;
786    case blink::WebAXEventTextInserted:
787      event_name = "TextInserted";
788      break;
789    case blink::WebAXEventTextRemoved:
790      event_name = "TextRemoved";
791      break;
792    case blink::WebAXEventValueChanged:
793      event_name = "ValueChanged";
794      break;
795    default:
796      event_name = "Unknown";
797      break;
798  }
799
800  test_interfaces_->GetAccessibilityController()->NotificationReceived(
801      obj, event_name);
802
803  if (test_interfaces_->GetAccessibilityController()
804          ->ShouldLogAccessibilityEvents()) {
805    std::string message("AccessibilityNotification - ");
806    message += event_name;
807
808    blink::WebNode node = obj.node();
809    if (!node.isNull() && node.isElementNode()) {
810      blink::WebElement element = node.to<blink::WebElement>();
811      if (element.hasAttribute("id")) {
812        message += " - id:";
813        message += element.getAttribute("id").utf8().data();
814      }
815    }
816
817    delegate_->PrintMessage(message + "\n");
818  }
819}
820
821void WebTestProxyBase::StartDragging(blink::WebLocalFrame* frame,
822                                     const blink::WebDragData& data,
823                                     blink::WebDragOperationsMask mask,
824                                     const blink::WebImage& image,
825                                     const blink::WebPoint& point) {
826  // When running a test, we need to fake a drag drop operation otherwise
827  // Windows waits for real mouse events to know when the drag is over.
828  test_interfaces_->GetEventSender()->DoDragDrop(data, mask);
829}
830
831// The output from these methods in layout test mode should match that
832// expected by the layout tests. See EditingDelegate.m in DumpRenderTree.
833
834void WebTestProxyBase::DidChangeSelection(bool is_empty_callback) {
835  if (test_interfaces_->GetTestRunner()->shouldDumpEditingCallbacks())
836    delegate_->PrintMessage(
837        "EDITING DELEGATE: "
838        "webViewDidChangeSelection:WebViewDidChangeSelectionNotification\n");
839}
840
841void WebTestProxyBase::DidChangeContents() {
842  if (test_interfaces_->GetTestRunner()->shouldDumpEditingCallbacks())
843    delegate_->PrintMessage(
844        "EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification\n");
845}
846
847bool WebTestProxyBase::CreateView(blink::WebLocalFrame* frame,
848                                  const blink::WebURLRequest& request,
849                                  const blink::WebWindowFeatures& features,
850                                  const blink::WebString& frame_name,
851                                  blink::WebNavigationPolicy policy,
852                                  bool suppress_opener) {
853  if (!test_interfaces_->GetTestRunner()->canOpenWindows())
854    return false;
855  if (test_interfaces_->GetTestRunner()->shouldDumpCreateView())
856    delegate_->PrintMessage(std::string("createView(") +
857                            URLDescription(request.url()) + ")\n");
858  return true;
859}
860
861blink::WebPlugin* WebTestProxyBase::CreatePlugin(
862    blink::WebLocalFrame* frame,
863    const blink::WebPluginParams& params) {
864  if (TestPlugin::IsSupportedMimeType(params.mimeType))
865    return TestPlugin::create(frame, params, delegate_);
866  return 0;
867}
868
869void WebTestProxyBase::SetStatusText(const blink::WebString& text) {
870  if (!test_interfaces_->GetTestRunner()->shouldDumpStatusCallbacks())
871    return;
872  delegate_->PrintMessage(
873      std::string("UI DELEGATE STATUS CALLBACK: setStatusText:") +
874      text.utf8().data() + "\n");
875}
876
877void WebTestProxyBase::DidStopLoading() {
878  if (test_interfaces_->GetTestRunner()->shouldDumpProgressFinishedCallback())
879    delegate_->PrintMessage("postProgressFinishedNotification\n");
880}
881
882void WebTestProxyBase::ShowContextMenu(
883    blink::WebLocalFrame* frame,
884    const blink::WebContextMenuData& context_menu_data) {
885  test_interfaces_->GetEventSender()->SetContextMenuData(context_menu_data);
886}
887
888blink::WebUserMediaClient* WebTestProxyBase::GetUserMediaClient() {
889  if (!user_media_client_.get())
890    user_media_client_.reset(new MockWebUserMediaClient(delegate_));
891  return user_media_client_.get();
892}
893
894// Simulate a print by going into print mode and then exit straight away.
895void WebTestProxyBase::PrintPage(blink::WebLocalFrame* frame) {
896  blink::WebSize page_size_in_pixels = web_widget_->size();
897  if (page_size_in_pixels.isEmpty())
898    return;
899  blink::WebPrintParams printParams(page_size_in_pixels);
900  frame->printBegin(printParams);
901  frame->printEnd();
902}
903
904blink::WebNotificationPresenter* WebTestProxyBase::GetNotificationPresenter() {
905  return test_interfaces_->GetTestRunner()->notification_presenter();
906}
907
908blink::WebMIDIClient* WebTestProxyBase::GetWebMIDIClient() {
909  return GetMIDIClientMock();
910}
911
912blink::WebSpeechRecognizer* WebTestProxyBase::GetSpeechRecognizer() {
913  return GetSpeechRecognizerMock();
914}
915
916bool WebTestProxyBase::RequestPointerLock() {
917  return test_interfaces_->GetTestRunner()->RequestPointerLock();
918}
919
920void WebTestProxyBase::RequestPointerUnlock() {
921  test_interfaces_->GetTestRunner()->RequestPointerUnlock();
922}
923
924bool WebTestProxyBase::IsPointerLocked() {
925  return test_interfaces_->GetTestRunner()->isPointerLocked();
926}
927
928void WebTestProxyBase::DidFocus() {
929  delegate_->SetFocus(this, true);
930}
931
932void WebTestProxyBase::DidBlur() {
933  delegate_->SetFocus(this, false);
934}
935
936void WebTestProxyBase::SetToolTipText(const blink::WebString& text,
937                                      blink::WebTextDirection direction) {
938  test_interfaces_->GetTestRunner()->setToolTipText(text);
939}
940
941void WebTestProxyBase::DidOpenChooser() {
942  chooser_count_++;
943}
944
945void WebTestProxyBase::DidCloseChooser() {
946  chooser_count_--;
947}
948
949bool WebTestProxyBase::IsChooserShown() {
950  return 0 < chooser_count_;
951}
952
953void WebTestProxyBase::LoadURLExternally(
954    blink::WebLocalFrame* frame,
955    const blink::WebURLRequest& request,
956    blink::WebNavigationPolicy policy,
957    const blink::WebString& suggested_name) {
958  if (test_interfaces_->GetTestRunner()->shouldWaitUntilExternalURLLoad()) {
959    if (policy == blink::WebNavigationPolicyDownload) {
960      delegate_->PrintMessage(
961          std::string("Downloading URL with suggested filename \"") +
962          suggested_name.utf8() + "\"\n");
963    } else {
964      delegate_->PrintMessage(std::string("Loading URL externally - \"") +
965                              URLDescription(request.url()) + "\"\n");
966    }
967    delegate_->TestFinished();
968  }
969}
970
971void WebTestProxyBase::DidStartProvisionalLoad(blink::WebLocalFrame* frame) {
972  if (!test_interfaces_->GetTestRunner()->topLoadingFrame())
973    test_interfaces_->GetTestRunner()->setTopLoadingFrame(frame, false);
974
975  if (test_interfaces_->GetTestRunner()->shouldDumpFrameLoadCallbacks()) {
976    PrintFrameDescription(delegate_, frame);
977    delegate_->PrintMessage(" - didStartProvisionalLoadForFrame\n");
978  }
979
980  if (test_interfaces_->GetTestRunner()
981          ->shouldDumpUserGestureInFrameLoadCallbacks()) {
982    PrintFrameuserGestureStatus(
983        delegate_, frame, " - in didStartProvisionalLoadForFrame\n");
984  }
985}
986
987void WebTestProxyBase::DidReceiveServerRedirectForProvisionalLoad(
988    blink::WebLocalFrame* frame) {
989  if (test_interfaces_->GetTestRunner()->shouldDumpFrameLoadCallbacks()) {
990    PrintFrameDescription(delegate_, frame);
991    delegate_->PrintMessage(
992        " - didReceiveServerRedirectForProvisionalLoadForFrame\n");
993  }
994}
995
996bool WebTestProxyBase::DidFailProvisionalLoad(blink::WebLocalFrame* frame,
997                                              const blink::WebURLError& error) {
998  if (test_interfaces_->GetTestRunner()->shouldDumpFrameLoadCallbacks()) {
999    PrintFrameDescription(delegate_, frame);
1000    delegate_->PrintMessage(" - didFailProvisionalLoadWithError\n");
1001  }
1002  CheckDone(frame, MainResourceLoadFailed);
1003  return !frame->provisionalDataSource();
1004}
1005
1006void WebTestProxyBase::DidCommitProvisionalLoad(
1007    blink::WebLocalFrame* frame,
1008    const blink::WebHistoryItem& history_item,
1009    blink::WebHistoryCommitType history_type) {
1010  if (test_interfaces_->GetTestRunner()->shouldDumpFrameLoadCallbacks()) {
1011    PrintFrameDescription(delegate_, frame);
1012    delegate_->PrintMessage(" - didCommitLoadForFrame\n");
1013  }
1014}
1015
1016void WebTestProxyBase::DidReceiveTitle(blink::WebLocalFrame* frame,
1017                                       const blink::WebString& title,
1018                                       blink::WebTextDirection direction) {
1019  blink::WebCString title8 = title.utf8();
1020
1021  if (test_interfaces_->GetTestRunner()->shouldDumpFrameLoadCallbacks()) {
1022    PrintFrameDescription(delegate_, frame);
1023    delegate_->PrintMessage(std::string(" - didReceiveTitle: ") +
1024                            title8.data() + "\n");
1025  }
1026
1027  if (test_interfaces_->GetTestRunner()->shouldDumpTitleChanges())
1028    delegate_->PrintMessage(std::string("TITLE CHANGED: '") + title8.data() +
1029                            "'\n");
1030}
1031
1032void WebTestProxyBase::DidChangeIcon(blink::WebLocalFrame* frame,
1033                                     blink::WebIconURL::Type icon_type) {
1034  if (test_interfaces_->GetTestRunner()->shouldDumpIconChanges()) {
1035    PrintFrameDescription(delegate_, frame);
1036    delegate_->PrintMessage(std::string(" - didChangeIcons\n"));
1037  }
1038}
1039
1040void WebTestProxyBase::DidFinishDocumentLoad(blink::WebLocalFrame* frame) {
1041  if (test_interfaces_->GetTestRunner()->shouldDumpFrameLoadCallbacks()) {
1042    PrintFrameDescription(delegate_, frame);
1043    delegate_->PrintMessage(" - didFinishDocumentLoadForFrame\n");
1044  } else {
1045    unsigned pendingUnloadEvents = frame->unloadListenerCount();
1046    if (pendingUnloadEvents) {
1047      PrintFrameDescription(delegate_, frame);
1048      delegate_->PrintMessage(base::StringPrintf(
1049          " - has %u onunload handler(s)\n", pendingUnloadEvents));
1050    }
1051  }
1052}
1053
1054void WebTestProxyBase::DidHandleOnloadEvents(blink::WebLocalFrame* frame) {
1055  if (test_interfaces_->GetTestRunner()->shouldDumpFrameLoadCallbacks()) {
1056    PrintFrameDescription(delegate_, frame);
1057    delegate_->PrintMessage(" - didHandleOnloadEventsForFrame\n");
1058  }
1059}
1060
1061void WebTestProxyBase::DidFailLoad(blink::WebLocalFrame* frame,
1062                                   const blink::WebURLError& error) {
1063  if (test_interfaces_->GetTestRunner()->shouldDumpFrameLoadCallbacks()) {
1064    PrintFrameDescription(delegate_, frame);
1065    delegate_->PrintMessage(" - didFailLoadWithError\n");
1066  }
1067  CheckDone(frame, MainResourceLoadFailed);
1068}
1069
1070void WebTestProxyBase::DidFinishLoad(blink::WebLocalFrame* frame) {
1071  if (test_interfaces_->GetTestRunner()->shouldDumpFrameLoadCallbacks()) {
1072    PrintFrameDescription(delegate_, frame);
1073    delegate_->PrintMessage(" - didFinishLoadForFrame\n");
1074  }
1075  CheckDone(frame, LoadFinished);
1076}
1077
1078void WebTestProxyBase::DidDetectXSS(blink::WebLocalFrame* frame,
1079                                    const blink::WebURL& insecure_url,
1080                                    bool did_block_entire_page) {
1081  if (test_interfaces_->GetTestRunner()->shouldDumpFrameLoadCallbacks())
1082    delegate_->PrintMessage("didDetectXSS\n");
1083}
1084
1085void WebTestProxyBase::DidDispatchPingLoader(blink::WebLocalFrame* frame,
1086                                             const blink::WebURL& url) {
1087  if (test_interfaces_->GetTestRunner()->shouldDumpPingLoaderCallbacks())
1088    delegate_->PrintMessage(std::string("PingLoader dispatched to '") +
1089                            URLDescription(url).c_str() + "'.\n");
1090}
1091
1092void WebTestProxyBase::WillRequestResource(
1093    blink::WebLocalFrame* frame,
1094    const blink::WebCachedURLRequest& request) {
1095  if (test_interfaces_->GetTestRunner()->shouldDumpResourceRequestCallbacks()) {
1096    PrintFrameDescription(delegate_, frame);
1097    delegate_->PrintMessage(std::string(" - ") +
1098                            request.initiatorName().utf8().data());
1099    delegate_->PrintMessage(std::string(" requested '") +
1100                            URLDescription(request.urlRequest().url()).c_str() +
1101                            "'\n");
1102  }
1103}
1104
1105void WebTestProxyBase::WillSendRequest(
1106    blink::WebLocalFrame* frame,
1107    unsigned identifier,
1108    blink::WebURLRequest& request,
1109    const blink::WebURLResponse& redirect_response) {
1110  // Need to use GURL for host() and SchemeIs()
1111  GURL url = request.url();
1112  std::string request_url = url.possibly_invalid_spec();
1113
1114  GURL main_document_url = request.firstPartyForCookies();
1115
1116  if (redirect_response.isNull() &&
1117      (test_interfaces_->GetTestRunner()->shouldDumpResourceLoadCallbacks() ||
1118       test_interfaces_->GetTestRunner()->shouldDumpResourcePriorities())) {
1119    DCHECK(resource_identifier_map_.find(identifier) ==
1120           resource_identifier_map_.end());
1121    resource_identifier_map_[identifier] =
1122        DescriptionSuitableForTestResult(request_url);
1123  }
1124
1125  if (test_interfaces_->GetTestRunner()->shouldDumpResourceLoadCallbacks()) {
1126    if (resource_identifier_map_.find(identifier) ==
1127        resource_identifier_map_.end())
1128      delegate_->PrintMessage("<unknown>");
1129    else
1130      delegate_->PrintMessage(resource_identifier_map_[identifier]);
1131    delegate_->PrintMessage(" - willSendRequest <NSURLRequest URL ");
1132    delegate_->PrintMessage(
1133        DescriptionSuitableForTestResult(request_url).c_str());
1134    delegate_->PrintMessage(", main document URL ");
1135    delegate_->PrintMessage(URLDescription(main_document_url).c_str());
1136    delegate_->PrintMessage(", http method ");
1137    delegate_->PrintMessage(request.httpMethod().utf8().data());
1138    delegate_->PrintMessage("> redirectResponse ");
1139    PrintResponseDescription(delegate_, redirect_response);
1140    delegate_->PrintMessage("\n");
1141  }
1142
1143  if (test_interfaces_->GetTestRunner()->shouldDumpResourcePriorities()) {
1144    delegate_->PrintMessage(
1145        DescriptionSuitableForTestResult(request_url).c_str());
1146    delegate_->PrintMessage(" has priority ");
1147    delegate_->PrintMessage(PriorityDescription(request.priority()));
1148    delegate_->PrintMessage("\n");
1149  }
1150
1151  if (test_interfaces_->GetTestRunner()->httpHeadersToClear()) {
1152    const std::set<std::string>* clearHeaders =
1153        test_interfaces_->GetTestRunner()->httpHeadersToClear();
1154    for (std::set<std::string>::const_iterator header = clearHeaders->begin();
1155         header != clearHeaders->end();
1156         ++header)
1157      request.clearHTTPHeaderField(blink::WebString::fromUTF8(*header));
1158  }
1159
1160  std::string host = url.host();
1161  if (!host.empty() &&
1162      (url.SchemeIs(url::kHttpScheme) || url.SchemeIs(url::kHttpsScheme))) {
1163    if (!IsLocalHost(host) && !IsTestHost(host) &&
1164        !HostIsUsedBySomeTestsToGenerateError(host) &&
1165        ((!main_document_url.SchemeIs(url::kHttpScheme) &&
1166          !main_document_url.SchemeIs(url::kHttpsScheme)) ||
1167         IsLocalHost(main_document_url.host())) &&
1168        !delegate_->AllowExternalPages()) {
1169      delegate_->PrintMessage(std::string("Blocked access to external URL ") +
1170                              request_url + "\n");
1171      BlockRequest(request);
1172      return;
1173    }
1174  }
1175
1176  // Set the new substituted URL.
1177  request.setURL(delegate_->RewriteLayoutTestsURL(request.url().spec()));
1178}
1179
1180void WebTestProxyBase::DidReceiveResponse(
1181    blink::WebLocalFrame* frame,
1182    unsigned identifier,
1183    const blink::WebURLResponse& response) {
1184  if (test_interfaces_->GetTestRunner()->shouldDumpResourceLoadCallbacks()) {
1185    if (resource_identifier_map_.find(identifier) ==
1186        resource_identifier_map_.end())
1187      delegate_->PrintMessage("<unknown>");
1188    else
1189      delegate_->PrintMessage(resource_identifier_map_[identifier]);
1190    delegate_->PrintMessage(" - didReceiveResponse ");
1191    PrintResponseDescription(delegate_, response);
1192    delegate_->PrintMessage("\n");
1193  }
1194  if (test_interfaces_->GetTestRunner()
1195          ->shouldDumpResourceResponseMIMETypes()) {
1196    GURL url = response.url();
1197    blink::WebString mime_type = response.mimeType();
1198    delegate_->PrintMessage(url.ExtractFileName());
1199    delegate_->PrintMessage(" has MIME type ");
1200    // Simulate NSURLResponse's mapping of empty/unknown MIME types to
1201    // application/octet-stream
1202    delegate_->PrintMessage(mime_type.isEmpty() ? "application/octet-stream"
1203                                                : mime_type.utf8().data());
1204    delegate_->PrintMessage("\n");
1205  }
1206}
1207
1208void WebTestProxyBase::DidChangeResourcePriority(
1209    blink::WebLocalFrame* frame,
1210    unsigned identifier,
1211    const blink::WebURLRequest::Priority& priority,
1212    int intra_priority_value) {
1213  if (test_interfaces_->GetTestRunner()->shouldDumpResourcePriorities()) {
1214    if (resource_identifier_map_.find(identifier) ==
1215        resource_identifier_map_.end())
1216      delegate_->PrintMessage("<unknown>");
1217    else
1218      delegate_->PrintMessage(resource_identifier_map_[identifier]);
1219    delegate_->PrintMessage(
1220        base::StringPrintf(" changed priority to %s, intra_priority %d\n",
1221                           PriorityDescription(priority).c_str(),
1222                           intra_priority_value));
1223  }
1224}
1225
1226void WebTestProxyBase::DidFinishResourceLoad(blink::WebLocalFrame* frame,
1227                                             unsigned identifier) {
1228  if (test_interfaces_->GetTestRunner()->shouldDumpResourceLoadCallbacks()) {
1229    if (resource_identifier_map_.find(identifier) ==
1230        resource_identifier_map_.end())
1231      delegate_->PrintMessage("<unknown>");
1232    else
1233      delegate_->PrintMessage(resource_identifier_map_[identifier]);
1234    delegate_->PrintMessage(" - didFinishLoading\n");
1235  }
1236  resource_identifier_map_.erase(identifier);
1237#if !defined(ENABLE_LOAD_COMPLETION_HACKS)
1238  CheckDone(frame, ResourceLoadCompleted);
1239#endif
1240}
1241
1242void WebTestProxyBase::DidAddMessageToConsole(
1243    const blink::WebConsoleMessage& message,
1244    const blink::WebString& source_name,
1245    unsigned source_line) {
1246  // This matches win DumpRenderTree's UIDelegate.cpp.
1247  if (!log_console_output_)
1248    return;
1249  std::string level;
1250  switch (message.level) {
1251    case blink::WebConsoleMessage::LevelDebug:
1252      level = "DEBUG";
1253      break;
1254    case blink::WebConsoleMessage::LevelLog:
1255      level = "MESSAGE";
1256      break;
1257    case blink::WebConsoleMessage::LevelInfo:
1258      level = "INFO";
1259      break;
1260    case blink::WebConsoleMessage::LevelWarning:
1261      level = "WARNING";
1262      break;
1263    case blink::WebConsoleMessage::LevelError:
1264      level = "ERROR";
1265      break;
1266  }
1267  delegate_->PrintMessage(std::string("CONSOLE ") + level + ": ");
1268  if (source_line) {
1269    delegate_->PrintMessage(base::StringPrintf("line %d: ", source_line));
1270  }
1271  if (!message.text.isEmpty()) {
1272    std::string new_message;
1273    new_message = message.text.utf8();
1274    size_t file_protocol = new_message.find("file://");
1275    if (file_protocol != std::string::npos) {
1276      new_message = new_message.substr(0, file_protocol) +
1277                    URLSuitableForTestResult(new_message.substr(file_protocol));
1278    }
1279    delegate_->PrintMessage(new_message);
1280  }
1281  delegate_->PrintMessage(std::string("\n"));
1282}
1283
1284void WebTestProxyBase::CheckDone(blink::WebLocalFrame* frame,
1285                                 CheckDoneReason reason) {
1286  if (frame != test_interfaces_->GetTestRunner()->topLoadingFrame())
1287    return;
1288
1289#if !defined(ENABLE_LOAD_COMPLETION_HACKS)
1290  // Quirk for MHTML prematurely completing on resource load completion.
1291  std::string mime_type = frame->dataSource()->response().mimeType().utf8();
1292  if (reason == ResourceLoadCompleted && mime_type == "multipart/related")
1293    return;
1294
1295  if (reason != MainResourceLoadFailed &&
1296      (frame->isResourceLoadInProgress() || frame->isLoading()))
1297    return;
1298#endif
1299  test_interfaces_->GetTestRunner()->setTopLoadingFrame(frame, true);
1300}
1301
1302blink::WebNavigationPolicy WebTestProxyBase::DecidePolicyForNavigation(
1303    const blink::WebFrameClient::NavigationPolicyInfo& info) {
1304  blink::WebNavigationPolicy result;
1305  if (!test_interfaces_->GetTestRunner()->policyDelegateEnabled())
1306    return info.defaultPolicy;
1307
1308  delegate_->PrintMessage(
1309      std::string("Policy delegate: attempt to load ") +
1310      URLDescription(info.urlRequest.url()) + " with navigation type '" +
1311      WebNavigationTypeToString(info.navigationType) + "'\n");
1312  if (test_interfaces_->GetTestRunner()->policyDelegateIsPermissive())
1313    result = blink::WebNavigationPolicyCurrentTab;
1314  else
1315    result = blink::WebNavigationPolicyIgnore;
1316
1317  if (test_interfaces_->GetTestRunner()->policyDelegateShouldNotifyDone())
1318    test_interfaces_->GetTestRunner()->policyDelegateDone();
1319  return result;
1320}
1321
1322bool WebTestProxyBase::WillCheckAndDispatchMessageEvent(
1323    blink::WebLocalFrame* source_frame,
1324    blink::WebFrame* target_frame,
1325    blink::WebSecurityOrigin target,
1326    blink::WebDOMMessageEvent event) {
1327  if (test_interfaces_->GetTestRunner()->shouldInterceptPostMessage()) {
1328    delegate_->PrintMessage("intercepted postMessage\n");
1329    return true;
1330  }
1331
1332  return false;
1333}
1334
1335void WebTestProxyBase::PostSpellCheckEvent(const blink::WebString& event_name) {
1336  if (test_interfaces_->GetTestRunner()->shouldDumpSpellCheckCallbacks()) {
1337    delegate_->PrintMessage(std::string("SpellCheckEvent: ") +
1338                            event_name.utf8().data() + "\n");
1339  }
1340}
1341
1342void WebTestProxyBase::ResetInputMethod() {
1343  // If a composition text exists, then we need to let the browser process
1344  // to cancel the input method's ongoing composition session.
1345  if (web_widget_)
1346    web_widget_->confirmComposition();
1347}
1348
1349blink::WebString WebTestProxyBase::acceptLanguages() {
1350  return blink::WebString::fromUTF8(accept_languages_);
1351}
1352
1353MockWebPushClient* WebTestProxyBase::GetPushClientMock() {
1354  if (!push_client_.get())
1355    push_client_.reset(new MockWebPushClient);
1356  return push_client_.get();
1357}
1358
1359blink::WebPushClient* WebTestProxyBase::GetWebPushClient() {
1360  return GetPushClientMock();
1361}
1362
1363}  // namespace content
1364