1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/shell/renderer/test_runner/WebTestProxy.h"
9 #include "content/shell/renderer/test_runner/AccessibilityController.h"
10 #include "content/shell/renderer/test_runner/EventSender.h"
11 #include "content/shell/renderer/test_runner/MockColorChooser.h"
12 #include "content/shell/renderer/test_runner/MockWebSpeechInputController.h"
13 #include "content/shell/renderer/test_runner/MockWebSpeechRecognizer.h"
14 #include "content/shell/renderer/test_runner/SpellCheckClient.h"
15 #include "content/shell/renderer/test_runner/TestCommon.h"
16 #include "content/shell/renderer/test_runner/TestInterfaces.h"
17 #include "content/shell/renderer/test_runner/TestPlugin.h"
18 #include "content/shell/renderer/test_runner/TestRunner.h"
19 #include "content/shell/renderer/test_runner/WebTestDelegate.h"
20 #include "content/shell/renderer/test_runner/WebTestInterfaces.h"
21 #include "content/shell/renderer/test_runner/WebTestRunner.h"
22 #include "content/shell/renderer/test_runner/WebUserMediaClientMock.h"
23 // FIXME: Including platform_canvas.h here is a layering violation.
24 #include "skia/ext/platform_canvas.h"
25 #include "third_party/WebKit/public/platform/WebCString.h"
26 #include "third_party/WebKit/public/platform/WebURLError.h"
27 #include "third_party/WebKit/public/platform/WebURLRequest.h"
28 #include "third_party/WebKit/public/platform/WebURLResponse.h"
29 #include "third_party/WebKit/public/web/WebAXEnums.h"
30 #include "third_party/WebKit/public/web/WebAXObject.h"
31 #include "third_party/WebKit/public/web/WebCachedURLRequest.h"
32 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
33 #include "third_party/WebKit/public/web/WebDataSource.h"
34 #include "third_party/WebKit/public/web/WebDocument.h"
35 #include "third_party/WebKit/public/web/WebElement.h"
36 #include "third_party/WebKit/public/web/WebFrame.h"
37 #include "third_party/WebKit/public/web/WebHistoryItem.h"
38 #include "third_party/WebKit/public/web/WebMIDIClientMock.h"
39 #include "third_party/WebKit/public/web/WebNode.h"
40 #include "third_party/WebKit/public/web/WebPluginParams.h"
41 #include "third_party/WebKit/public/web/WebPrintParams.h"
42 #include "third_party/WebKit/public/web/WebRange.h"
43 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
44 #include "third_party/WebKit/public/web/WebView.h"
46 using namespace blink;
49 namespace WebTestRunner {
53 class HostMethodTask : public WebMethodTask<WebTestProxyBase> {
55 typedef void (WebTestProxyBase::*CallbackMethodType)();
56 HostMethodTask(WebTestProxyBase* object, CallbackMethodType callback)
57 : WebMethodTask<WebTestProxyBase>(object)
58 , m_callback(callback)
61 virtual void runIfValid() OVERRIDE { (m_object->*m_callback)(); }
64 CallbackMethodType m_callback;
67 void printFrameDescription(WebTestDelegate* delegate, WebFrame* frame)
69 string name8 = frame->uniqueName().utf8();
70 if (frame == frame->view()->mainFrame()) {
71 if (!name8.length()) {
72 delegate->printMessage("main frame");
75 delegate->printMessage(string("main frame \"") + name8 + "\"");
78 if (!name8.length()) {
79 delegate->printMessage("frame (anonymous)");
82 delegate->printMessage(string("frame \"") + name8 + "\"");
85 void printFrameUserGestureStatus(WebTestDelegate* delegate, WebFrame* frame, const char* msg)
87 bool isUserGesture = WebUserGestureIndicator::isProcessingUserGesture();
88 delegate->printMessage(string("Frame with user gesture \"") + (isUserGesture ? "true" : "false") + "\"" + msg);
91 // Used to write a platform neutral file:/// URL by taking the
92 // filename and its directory. (e.g., converts
93 // "file:///tmp/foo/bar.txt" to just "bar.txt").
94 string descriptionSuitableForTestResult(const string& url)
96 if (url.empty() || string::npos == url.find("file://"))
99 size_t pos = url.rfind('/');
100 if (pos == string::npos || !pos)
101 return "ERROR:" + url;
102 pos = url.rfind('/', pos - 1);
103 if (pos == string::npos)
104 return "ERROR:" + url;
106 return url.substr(pos + 1);
109 void printResponseDescription(WebTestDelegate* delegate, const WebURLResponse& response)
111 if (response.isNull()) {
112 delegate->printMessage("(null)");
115 string url = response.url().spec();
117 snprintf(data, sizeof(data), "%d", response. httpStatusCode());
118 delegate->printMessage(string("<NSURLResponse ") + descriptionSuitableForTestResult(url) + ", http status code " + data + ">");
121 string URLDescription(const GURL& url)
123 if (url.SchemeIs("file"))
124 return url.ExtractFileName();
125 return url.possibly_invalid_spec();
128 string PriorityDescription(const WebURLRequest::Priority& priority)
131 case WebURLRequest::PriorityVeryLow:
133 case WebURLRequest::PriorityLow:
135 case WebURLRequest::PriorityMedium:
137 case WebURLRequest::PriorityHigh:
139 case WebURLRequest::PriorityVeryHigh:
141 case WebURLRequest::PriorityUnresolved:
147 void blockRequest(WebURLRequest& request)
149 request.setURL(GURL("255.255.255.255"));
152 bool isLocalhost(const string& host)
154 return host == "127.0.0.1" || host == "localhost";
157 bool hostIsUsedBySomeTestsToGenerateError(const string& host)
159 return host == "255.255.255.255";
162 // Used to write a platform neutral file:/// URL by only taking the filename
163 // (e.g., converts "file:///tmp/foo.txt" to just "foo.txt").
164 string urlSuitableForTestResult(const string& url)
166 if (url.empty() || string::npos == url.find("file://"))
169 size_t pos = url.rfind('/');
170 if (pos == string::npos) {
172 pos = url.rfind('\\');
173 if (pos == string::npos)
179 string filename = url.substr(pos + 1);
180 if (filename.empty())
181 return "file:"; // A WebKit test has this in its expected output.
185 // WebNavigationType debugging strings taken from PolicyDelegate.mm.
186 const char* linkClickedString = "link clicked";
187 const char* formSubmittedString = "form submitted";
188 const char* backForwardString = "back/forward";
189 const char* reloadString = "reload";
190 const char* formResubmittedString = "form resubmitted";
191 const char* otherString = "other";
192 const char* illegalString = "illegal value";
194 // Get a debugging string from a WebNavigationType.
195 const char* webNavigationTypeToString(WebNavigationType type)
198 case blink::WebNavigationTypeLinkClicked:
199 return linkClickedString;
200 case blink::WebNavigationTypeFormSubmitted:
201 return formSubmittedString;
202 case blink::WebNavigationTypeBackForward:
203 return backForwardString;
204 case blink::WebNavigationTypeReload:
206 case blink::WebNavigationTypeFormResubmitted:
207 return formResubmittedString;
208 case blink::WebNavigationTypeOther:
211 return illegalString;
214 string dumpDocumentText(WebFrame* frame)
216 // We use the document element's text instead of the body text here because
217 // not all documents have a body, such as XML documents.
218 WebElement documentElement = frame->document().documentElement();
219 if (documentElement.isNull())
221 return documentElement.innerText().utf8();
224 string dumpFramesAsText(WebFrame* frame, bool recursive)
228 // Add header for all but the main frame. Skip empty frames.
229 if (frame->parent() && !frame->document().documentElement().isNull()) {
230 result.append("\n--------\nFrame: '");
231 result.append(frame->uniqueName().utf8().data());
232 result.append("'\n--------\n");
235 result.append(dumpDocumentText(frame));
239 for (WebFrame* child = frame->firstChild(); child; child = child->nextSibling())
240 result.append(dumpFramesAsText(child, recursive));
246 string dumpFramesAsPrintedText(WebFrame* frame, bool recursive)
250 // Cannot do printed format for anything other than HTML
251 if (!frame->document().isHTMLDocument())
254 // Add header for all but the main frame. Skip empty frames.
255 if (frame->parent() && !frame->document().documentElement().isNull()) {
256 result.append("\n--------\nFrame: '");
257 result.append(frame->uniqueName().utf8().data());
258 result.append("'\n--------\n");
261 result.append(frame->renderTreeAsText(WebFrame::RenderAsTextPrinting).utf8());
265 for (WebFrame* child = frame->firstChild(); child; child = child->nextSibling())
266 result.append(dumpFramesAsPrintedText(child, recursive));
272 string dumpFrameScrollPosition(WebFrame* frame, bool recursive)
275 WebSize offset = frame->scrollOffset();
276 if (offset.width > 0 || offset.height > 0) {
278 result = string("frame '") + frame->uniqueName().utf8().data() + "' ";
280 snprintf(data, sizeof(data), "scrolled to %d,%d\n", offset.width, offset.height);
286 for (WebFrame* child = frame->firstChild(); child; child = child->nextSibling())
287 result += dumpFrameScrollPosition(child, recursive);
292 base::char16 operator()(base::char16 c) { return tolower(c); }
295 // Returns True if item1 < item2.
296 bool HistoryItemCompareLess(const WebHistoryItem& item1, const WebHistoryItem& item2)
298 base::string16 target1 = item1.target();
299 base::string16 target2 = item2.target();
300 std::transform(target1.begin(), target1.end(), target1.begin(), ToLower());
301 std::transform(target2.begin(), target2.end(), target2.begin(), ToLower());
302 return target1 < target2;
305 string dumpHistoryItem(const WebHistoryItem& item, int indent, bool isCurrent)
310 result.append("curr->");
311 result.append(indent - 6, ' '); // 6 == "curr->".length()
313 result.append(indent, ' ');
315 string url = normalizeLayoutTestURL(item.urlString().utf8());
317 if (!item.target().isEmpty()) {
318 result.append(" (in frame \"");
319 result.append(item.target().utf8());
320 result.append("\")");
324 const WebVector<WebHistoryItem>& children = item.children();
325 if (!children.isEmpty()) {
326 // Must sort to eliminate arbitrary result ordering which defeats
327 // reproducible testing.
328 // FIXME: WebVector should probably just be a std::vector!!
329 std::vector<WebHistoryItem> sortedChildren;
330 for (size_t i = 0; i < children.size(); ++i)
331 sortedChildren.push_back(children[i]);
332 std::sort(sortedChildren.begin(), sortedChildren.end(), HistoryItemCompareLess);
333 for (size_t i = 0; i < sortedChildren.size(); ++i)
334 result += dumpHistoryItem(sortedChildren[i], indent + 4, false);
340 void dumpBackForwardList(const WebVector<WebHistoryItem>& history, size_t currentEntryIndex, string& result)
342 result.append("\n============== Back Forward List ==============\n");
343 for (size_t index = 0; index < history.size(); ++index)
344 result.append(dumpHistoryItem(history[index], 8, index == currentEntryIndex));
345 result.append("===============================================\n");
348 string dumpAllBackForwardLists(TestInterfaces* interfaces, WebTestDelegate* delegate)
351 const vector<WebTestProxyBase*>& windowList = interfaces->windowList();
352 for (unsigned i = 0; i < windowList.size(); ++i) {
353 size_t currentEntryIndex = 0;
354 WebVector<WebHistoryItem> history;
355 delegate->captureHistoryForWindow(windowList.at(i), &history, ¤tEntryIndex);
356 dumpBackForwardList(history, currentEntryIndex, result);
363 WebTestProxyBase::WebTestProxyBase()
364 : m_testInterfaces(0)
367 , m_spellcheck(new SpellCheckClient(this))
373 WebTestProxyBase::~WebTestProxyBase()
375 m_testInterfaces->windowClosed(this);
378 void WebTestProxyBase::setInterfaces(WebTestInterfaces* interfaces)
380 m_testInterfaces = interfaces->testInterfaces();
381 m_testInterfaces->windowOpened(this);
384 void WebTestProxyBase::setDelegate(WebTestDelegate* delegate)
386 m_delegate = delegate;
387 m_spellcheck->setDelegate(delegate);
388 #if ENABLE_INPUT_SPEECH
389 if (m_speechInputController.get())
390 m_speechInputController->setDelegate(delegate);
392 if (m_speechRecognizer.get())
393 m_speechRecognizer->setDelegate(delegate);
396 void WebTestProxyBase::setWidget(WebWidget* widget)
398 m_webWidget = widget;
401 WebWidget* WebTestProxyBase::webWidget()
406 WebView* WebTestProxyBase::webView()
408 BLINK_ASSERT(m_webWidget);
409 // TestRunner does not support popup widgets. So m_webWidget is always a WebView.
410 return static_cast<WebView*>(m_webWidget);
413 void WebTestProxyBase::didForceResize()
416 discardBackingStore();
419 void WebTestProxyBase::reset()
421 m_paintRect = WebRect();
423 m_isPainting = false;
424 m_animateScheduled = false;
425 m_resourceIdentifierMap.clear();
426 m_logConsoleOutput = true;
427 if (m_midiClient.get())
428 m_midiClient->resetMock();
429 #if ENABLE_INPUT_SPEECH
430 if (m_speechInputController.get())
431 m_speechInputController->clearResults();
435 WebSpellCheckClient* WebTestProxyBase::spellCheckClient() const
437 return m_spellcheck.get();
440 WebColorChooser* WebTestProxyBase::createColorChooser(WebColorChooserClient* client, const blink::WebColor& color)
442 // This instance is deleted by WebCore::ColorInputType
443 return new MockColorChooser(client, m_delegate, this);
446 WebColorChooser* WebTestProxyBase::createColorChooser(WebColorChooserClient* client, const blink::WebColor& color, const blink::WebVector<blink::WebColorSuggestion>& suggestions)
448 // This instance is deleted by WebCore::ColorInputType
449 return new MockColorChooser(client, m_delegate, this);
452 bool WebTestProxyBase::runFileChooser(const blink::WebFileChooserParams&, blink::WebFileChooserCompletion*)
454 m_delegate->printMessage("Mock: Opening a file chooser.\n");
455 // FIXME: Add ability to set file names to a file upload control.
459 void WebTestProxyBase::showValidationMessage(const WebRect&, const WebString& message, const WebString& subMessage, WebTextDirection)
461 m_delegate->printMessage(std::string("ValidationMessageClient: main-message=") + std::string(message.utf8()) + " sub-message=" + std::string(subMessage.utf8()) + "\n");
464 void WebTestProxyBase::hideValidationMessage()
468 void WebTestProxyBase::moveValidationMessage(const WebRect&)
472 string WebTestProxyBase::captureTree(bool debugRenderTree)
474 bool shouldDumpAsText = m_testInterfaces->testRunner()->shouldDumpAsText();
475 bool shouldDumpAsMarkup = m_testInterfaces->testRunner()->shouldDumpAsMarkup();
476 bool shouldDumpAsPrinted = m_testInterfaces->testRunner()->isPrinting();
477 WebFrame* frame = webView()->mainFrame();
479 if (shouldDumpAsText) {
480 bool recursive = m_testInterfaces->testRunner()->shouldDumpChildFramesAsText();
481 dataUtf8 = shouldDumpAsPrinted ? dumpFramesAsPrintedText(frame, recursive) : dumpFramesAsText(frame, recursive);
482 } else if (shouldDumpAsMarkup) {
483 // Append a newline for the test driver.
484 dataUtf8 = frame->contentAsMarkup().utf8() + "\n";
486 bool recursive = m_testInterfaces->testRunner()->shouldDumpChildFrameScrollPositions();
487 WebFrame::RenderAsTextControls renderTextBehavior = WebFrame::RenderAsTextNormal;
488 if (shouldDumpAsPrinted)
489 renderTextBehavior |= WebFrame::RenderAsTextPrinting;
491 renderTextBehavior |= WebFrame::RenderAsTextDebug;
492 dataUtf8 = frame->renderTreeAsText(renderTextBehavior).utf8();
493 dataUtf8 += dumpFrameScrollPosition(frame, recursive);
496 if (m_testInterfaces->testRunner()->shouldDumpBackForwardList())
497 dataUtf8 += dumpAllBackForwardLists(m_testInterfaces, m_delegate);
502 SkCanvas* WebTestProxyBase::capturePixels()
504 webWidget()->layout();
505 if (m_testInterfaces->testRunner()->testRepaint()) {
506 WebSize viewSize = webWidget()->size();
507 int width = viewSize.width;
508 int height = viewSize.height;
509 if (m_testInterfaces->testRunner()->sweepHorizontally()) {
510 for (WebRect column(0, 0, 1, height); column.x < width; column.x++)
513 for (WebRect line(0, 0, width, 1); line.y < height; line.y++)
516 } else if (m_testInterfaces->testRunner()->isPrinting())
517 paintPagesWithBoundaries();
519 paintInvalidatedRegion();
521 // See if we need to draw the selection bounds rect. Selection bounds
522 // rect is the rect enclosing the (possibly transformed) selection.
523 // The rect should be drawn after everything is laid out and painted.
524 if (m_testInterfaces->testRunner()->shouldDumpSelectionRect()) {
525 // If there is a selection rect - draw a red 1px border enclosing rect
526 WebRect wr = webView()->mainFrame()->selectionBoundsRect();
528 // Render a red rectangle bounding selection rect
530 paint.setColor(0xFFFF0000); // Fully opaque red
531 paint.setStyle(SkPaint::kStroke_Style);
532 paint.setFlags(SkPaint::kAntiAlias_Flag);
533 paint.setStrokeWidth(1.0f);
534 SkIRect rect; // Bounding rect
535 rect.set(wr.x, wr.y, wr.x + wr.width, wr.y + wr.height);
536 canvas()->drawIRect(rect, paint);
543 void WebTestProxyBase::setLogConsoleOutput(bool enabled)
545 m_logConsoleOutput = enabled;
548 void WebTestProxyBase::paintRect(const WebRect& rect)
550 BLINK_ASSERT(!m_isPainting);
551 BLINK_ASSERT(canvas());
553 float deviceScaleFactor = webView()->deviceScaleFactor();
554 int scaledX = static_cast<int>(static_cast<float>(rect.x) * deviceScaleFactor);
555 int scaledY = static_cast<int>(static_cast<float>(rect.y) * deviceScaleFactor);
556 int scaledWidth = static_cast<int>(ceil(static_cast<float>(rect.width) * deviceScaleFactor));
557 int scaledHeight = static_cast<int>(ceil(static_cast<float>(rect.height) * deviceScaleFactor));
558 WebRect deviceRect(scaledX, scaledY, scaledWidth, scaledHeight);
559 webWidget()->paint(canvas(), deviceRect);
560 m_isPainting = false;
563 void WebTestProxyBase::paintInvalidatedRegion()
565 webWidget()->animate(0.0);
566 webWidget()->layout();
567 WebSize widgetSize = webWidget()->size();
568 WebRect clientRect(0, 0, widgetSize.width, widgetSize.height);
570 // Paint the canvas if necessary. Allow painting to generate extra rects
571 // for the first two calls. This is necessary because some WebCore rendering
572 // objects update their layout only when painted.
573 // Store the total area painted in total_paint. Then tell the gdk window
574 // to update that area after we're done painting it.
575 for (int i = 0; i < 3; ++i) {
576 // rect = intersect(m_paintRect , clientRect)
577 WebRect damageRect = m_paintRect;
578 int left = max(damageRect.x, clientRect.x);
579 int top = max(damageRect.y, clientRect.y);
580 int right = min(damageRect.x + damageRect.width, clientRect.x + clientRect.width);
581 int bottom = min(damageRect.y + damageRect.height, clientRect.y + clientRect.height);
583 if (left < right && top < bottom)
584 rect = WebRect(left, top, right - left, bottom - top);
586 m_paintRect = WebRect();
591 BLINK_ASSERT(m_paintRect.isEmpty());
594 void WebTestProxyBase::paintPagesWithBoundaries()
596 BLINK_ASSERT(!m_isPainting);
597 BLINK_ASSERT(canvas());
600 WebSize pageSizeInPixels = webWidget()->size();
601 WebFrame* webFrame = webView()->mainFrame();
603 int pageCount = webFrame->printBegin(pageSizeInPixels);
604 int totalHeight = pageCount * (pageSizeInPixels.height + 1) - 1;
606 SkCanvas* testCanvas = skia::TryCreateBitmapCanvas(pageSizeInPixels.width, totalHeight, false);
608 discardBackingStore();
609 m_canvas.reset(testCanvas);
611 webFrame->printEnd();
615 webFrame->printPagesWithBoundaries(canvas(), pageSizeInPixels);
616 webFrame->printEnd();
618 m_isPainting = false;
621 SkCanvas* WebTestProxyBase::canvas()
624 return m_canvas.get();
625 WebSize widgetSize = webWidget()->size();
626 float deviceScaleFactor = webView()->deviceScaleFactor();
627 int scaledWidth = static_cast<int>(ceil(static_cast<float>(widgetSize.width) * deviceScaleFactor));
628 int scaledHeight = static_cast<int>(ceil(static_cast<float>(widgetSize.height) * deviceScaleFactor));
629 // We're allocating the canvas to be non-opaque (third parameter), so we
630 // don't end up with uninitialized memory if a layout test doesn't damage
632 m_canvas.reset(skia::CreateBitmapCanvas(scaledWidth, scaledHeight, false));
633 return m_canvas.get();
636 // Paints the entire canvas a semi-transparent black (grayish). This is used
637 // by the layout tests in fast/repaint. The alpha value matches upstream.
638 void WebTestProxyBase::displayRepaintMask()
640 canvas()->drawARGB(167, 0, 0, 0);
643 void WebTestProxyBase::display()
645 const blink::WebSize& size = webWidget()->size();
646 WebRect rect(0, 0, size.width, size.height);
648 paintInvalidatedRegion();
649 displayRepaintMask();
652 void WebTestProxyBase::displayInvalidatedRegion()
654 paintInvalidatedRegion();
655 displayRepaintMask();
658 void WebTestProxyBase::discardBackingStore()
663 WebMIDIClientMock* WebTestProxyBase::midiClientMock()
665 if (!m_midiClient.get())
666 m_midiClient.reset(new WebMIDIClientMock);
667 return m_midiClient.get();
670 #if ENABLE_INPUT_SPEECH
671 MockWebSpeechInputController* WebTestProxyBase::speechInputControllerMock()
673 BLINK_ASSERT(m_speechInputController.get());
674 return m_speechInputController.get();
678 MockWebSpeechRecognizer* WebTestProxyBase::speechRecognizerMock()
680 if (!m_speechRecognizer.get()) {
681 m_speechRecognizer.reset(new MockWebSpeechRecognizer());
682 m_speechRecognizer->setDelegate(m_delegate);
684 return m_speechRecognizer.get();
687 void WebTestProxyBase::didInvalidateRect(const WebRect& rect)
689 // m_paintRect = m_paintRect U rect
692 if (m_paintRect.isEmpty()) {
696 int left = min(m_paintRect.x, rect.x);
697 int top = min(m_paintRect.y, rect.y);
698 int right = max(m_paintRect.x + m_paintRect.width, rect.x + rect.width);
699 int bottom = max(m_paintRect.y + m_paintRect.height, rect.y + rect.height);
700 m_paintRect = WebRect(left, top, right - left, bottom - top);
703 void WebTestProxyBase::didScrollRect(int, int, const WebRect& clipRect)
705 didInvalidateRect(clipRect);
708 void WebTestProxyBase::invalidateAll()
710 m_paintRect = WebRect(0, 0, INT_MAX, INT_MAX);
713 void WebTestProxyBase::scheduleComposite()
718 void WebTestProxyBase::scheduleAnimation()
720 if (!m_testInterfaces->testRunner()->testIsRunning())
723 if (!m_animateScheduled) {
724 m_animateScheduled = true;
725 m_delegate->postDelayedTask(new HostMethodTask(this, &WebTestProxyBase::animateNow), 1);
729 void WebTestProxyBase::animateNow()
731 if (m_animateScheduled) {
732 m_animateScheduled = false;
733 webWidget()->animate(0.0);
734 webWidget()->layout();
738 bool WebTestProxyBase::isCompositorFramePending() const
740 return m_animateScheduled || !m_paintRect.isEmpty();
743 void WebTestProxyBase::show(WebNavigationPolicy)
748 void WebTestProxyBase::setWindowRect(const WebRect& rect)
751 discardBackingStore();
754 void WebTestProxyBase::didAutoResize(const WebSize&)
759 void WebTestProxyBase::postAccessibilityEvent(const blink::WebAXObject& obj, blink::WebAXEvent event)
761 if (event == blink::WebAXEventFocus)
762 m_testInterfaces->accessibilityController()->setFocusedElement(obj);
764 const char* eventName = 0;
766 case blink::WebAXEventActiveDescendantChanged:
767 eventName = "ActiveDescendantChanged";
769 case blink::WebAXEventAlert:
772 case blink::WebAXEventAriaAttributeChanged:
773 eventName = "AriaAttributeChanged";
775 case blink::WebAXEventAutocorrectionOccured:
776 eventName = "AutocorrectionOccured";
778 case blink::WebAXEventBlur:
781 case blink::WebAXEventCheckedStateChanged:
782 eventName = "CheckedStateChanged";
784 case blink::WebAXEventChildrenChanged:
785 eventName = "ChildrenChanged";
787 case blink::WebAXEventFocus:
790 case blink::WebAXEventHide:
793 case blink::WebAXEventInvalidStatusChanged:
794 eventName = "InvalidStatusChanged";
796 case blink::WebAXEventLayoutComplete:
797 eventName = "LayoutComplete";
799 case blink::WebAXEventLiveRegionChanged:
800 eventName = "LiveRegionChanged";
802 case blink::WebAXEventLoadComplete:
803 eventName = "LoadComplete";
805 case blink::WebAXEventLocationChanged:
806 eventName = "LocationChanged";
808 case blink::WebAXEventMenuListItemSelected:
809 eventName = "MenuListItemSelected";
811 case blink::WebAXEventMenuListValueChanged:
812 eventName = "MenuListValueChanged";
814 case blink::WebAXEventRowCollapsed:
815 eventName = "RowCollapsed";
817 case blink::WebAXEventRowCountChanged:
818 eventName = "RowCountChanged";
820 case blink::WebAXEventRowExpanded:
821 eventName = "RowExpanded";
823 case blink::WebAXEventScrolledToAnchor:
824 eventName = "ScrolledToAnchor";
826 case blink::WebAXEventSelectedChildrenChanged:
827 eventName = "SelectedChildrenChanged";
829 case blink::WebAXEventSelectedTextChanged:
830 eventName = "SelectedTextChanged";
832 case blink::WebAXEventShow:
835 case blink::WebAXEventTextChanged:
836 eventName = "TextChanged";
838 case blink::WebAXEventTextInserted:
839 eventName = "TextInserted";
841 case blink::WebAXEventTextRemoved:
842 eventName = "TextRemoved";
844 case blink::WebAXEventValueChanged:
845 eventName = "ValueChanged";
849 m_testInterfaces->accessibilityController()->notificationReceived(obj, eventName);
851 if (m_testInterfaces->accessibilityController()->shouldLogAccessibilityEvents()) {
852 string message("AccessibilityNotification - ");
853 message += eventName;
855 blink::WebNode node = obj.node();
856 if (!node.isNull() && node.isElementNode()) {
857 blink::WebElement element = node.to<blink::WebElement>();
858 if (element.hasAttribute("id")) {
860 message += element.getAttribute("id").utf8().data();
864 m_delegate->printMessage(message + "\n");
868 void WebTestProxyBase::startDragging(WebFrame*, const WebDragData& data, WebDragOperationsMask mask, const WebImage&, const WebPoint&)
870 // When running a test, we need to fake a drag drop operation otherwise
871 // Windows waits for real mouse events to know when the drag is over.
872 m_testInterfaces->eventSender()->doDragDrop(data, mask);
875 // The output from these methods in layout test mode should match that
876 // expected by the layout tests. See EditingDelegate.m in DumpRenderTree.
878 void WebTestProxyBase::didChangeSelection(bool isEmptySelection)
880 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks())
881 m_delegate->printMessage("EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification\n");
884 void WebTestProxyBase::didChangeContents()
886 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks())
887 m_delegate->printMessage("EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification\n");
890 bool WebTestProxyBase::createView(WebFrame*, const WebURLRequest& request, const WebWindowFeatures&, const WebString&, WebNavigationPolicy, bool)
892 if (!m_testInterfaces->testRunner()->canOpenWindows())
894 if (m_testInterfaces->testRunner()->shouldDumpCreateView())
895 m_delegate->printMessage(string("createView(") + URLDescription(request.url()) + ")\n");
899 WebPlugin* WebTestProxyBase::createPlugin(WebFrame* frame, const WebPluginParams& params)
901 if (TestPlugin::isSupportedMimeType(params.mimeType))
902 return TestPlugin::create(frame, params, m_delegate);
906 void WebTestProxyBase::setStatusText(const WebString& text)
908 if (!m_testInterfaces->testRunner()->shouldDumpStatusCallbacks())
910 m_delegate->printMessage(string("UI DELEGATE STATUS CALLBACK: setStatusText:") + text.utf8().data() + "\n");
913 void WebTestProxyBase::didStopLoading()
915 if (m_testInterfaces->testRunner()->shouldDumpProgressFinishedCallback())
916 m_delegate->printMessage("postProgressFinishedNotification\n");
919 void WebTestProxyBase::showContextMenu(WebFrame*, const WebContextMenuData& contextMenuData)
921 m_testInterfaces->eventSender()->setContextMenuData(contextMenuData);
924 WebUserMediaClient* WebTestProxyBase::userMediaClient()
926 if (!m_userMediaClient.get())
927 m_userMediaClient.reset(new WebUserMediaClientMock(m_delegate));
928 return m_userMediaClient.get();
931 // Simulate a print by going into print mode and then exit straight away.
932 void WebTestProxyBase::printPage(WebFrame* frame)
934 WebSize pageSizeInPixels = webWidget()->size();
935 if (pageSizeInPixels.isEmpty())
937 WebPrintParams printParams(pageSizeInPixels);
938 frame->printBegin(printParams);
942 WebNotificationPresenter* WebTestProxyBase::notificationPresenter()
944 return m_testInterfaces->testRunner()->notificationPresenter();
947 WebMIDIClient* WebTestProxyBase::webMIDIClient()
949 return midiClientMock();
952 WebSpeechInputController* WebTestProxyBase::speechInputController(WebSpeechInputListener* listener)
954 #if ENABLE_INPUT_SPEECH
955 if (!m_speechInputController.get()) {
956 m_speechInputController.reset(new MockWebSpeechInputController(listener));
957 m_speechInputController->setDelegate(m_delegate);
959 return m_speechInputController.get();
961 BLINK_ASSERT(listener);
966 WebSpeechRecognizer* WebTestProxyBase::speechRecognizer()
968 return speechRecognizerMock();
971 bool WebTestProxyBase::requestPointerLock()
973 return m_testInterfaces->testRunner()->requestPointerLock();
976 void WebTestProxyBase::requestPointerUnlock()
978 m_testInterfaces->testRunner()->requestPointerUnlock();
981 bool WebTestProxyBase::isPointerLocked()
983 return m_testInterfaces->testRunner()->isPointerLocked();
986 void WebTestProxyBase::didFocus()
988 m_delegate->setFocus(this, true);
991 void WebTestProxyBase::didBlur()
993 m_delegate->setFocus(this, false);
996 void WebTestProxyBase::setToolTipText(const WebString& text, WebTextDirection)
998 m_testInterfaces->testRunner()->setToolTipText(text);
1001 void WebTestProxyBase::didOpenChooser()
1006 void WebTestProxyBase::didCloseChooser()
1011 bool WebTestProxyBase::isChooserShown()
1013 return 0 < m_chooserCount;
1016 void WebTestProxyBase::didStartProvisionalLoad(WebFrame* frame)
1018 if (!m_testInterfaces->testRunner()->topLoadingFrame())
1019 m_testInterfaces->testRunner()->setTopLoadingFrame(frame, false);
1021 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
1022 printFrameDescription(m_delegate, frame);
1023 m_delegate->printMessage(" - didStartProvisionalLoadForFrame\n");
1026 if (m_testInterfaces->testRunner()->shouldDumpUserGestureInFrameLoadCallbacks())
1027 printFrameUserGestureStatus(m_delegate, frame, " - in didStartProvisionalLoadForFrame\n");
1030 void WebTestProxyBase::didReceiveServerRedirectForProvisionalLoad(WebFrame* frame)
1032 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
1033 printFrameDescription(m_delegate, frame);
1034 m_delegate->printMessage(" - didReceiveServerRedirectForProvisionalLoadForFrame\n");
1038 bool WebTestProxyBase::didFailProvisionalLoad(WebFrame* frame, const WebURLError&)
1040 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
1041 printFrameDescription(m_delegate, frame);
1042 m_delegate->printMessage(" - didFailProvisionalLoadWithError\n");
1044 locationChangeDone(frame);
1045 return !frame->provisionalDataSource();
1048 void WebTestProxyBase::didCommitProvisionalLoad(WebFrame* frame, bool)
1050 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
1051 printFrameDescription(m_delegate, frame);
1052 m_delegate->printMessage(" - didCommitLoadForFrame\n");
1056 void WebTestProxyBase::didReceiveTitle(WebFrame* frame, const WebString& title, WebTextDirection direction)
1058 WebCString title8 = title.utf8();
1060 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
1061 printFrameDescription(m_delegate, frame);
1062 m_delegate->printMessage(string(" - didReceiveTitle: ") + title8.data() + "\n");
1065 if (m_testInterfaces->testRunner()->shouldDumpTitleChanges())
1066 m_delegate->printMessage(string("TITLE CHANGED: '") + title8.data() + "'\n");
1069 void WebTestProxyBase::didChangeIcon(WebFrame* frame, WebIconURL::Type)
1071 if (m_testInterfaces->testRunner()->shouldDumpIconChanges()) {
1072 printFrameDescription(m_delegate, frame);
1073 m_delegate->printMessage(string(" - didChangeIcons\n"));
1077 void WebTestProxyBase::didFinishDocumentLoad(WebFrame* frame)
1079 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
1080 printFrameDescription(m_delegate, frame);
1081 m_delegate->printMessage(" - didFinishDocumentLoadForFrame\n");
1083 unsigned pendingUnloadEvents = frame->unloadListenerCount();
1084 if (pendingUnloadEvents) {
1085 printFrameDescription(m_delegate, frame);
1087 snprintf(buffer, sizeof(buffer), " - has %u onunload handler(s)\n", pendingUnloadEvents);
1088 m_delegate->printMessage(buffer);
1093 void WebTestProxyBase::didHandleOnloadEvents(WebFrame* frame)
1095 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
1096 printFrameDescription(m_delegate, frame);
1097 m_delegate->printMessage(" - didHandleOnloadEventsForFrame\n");
1101 void WebTestProxyBase::didFailLoad(WebFrame* frame, const WebURLError&)
1103 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
1104 printFrameDescription(m_delegate, frame);
1105 m_delegate->printMessage(" - didFailLoadWithError\n");
1107 locationChangeDone(frame);
1110 void WebTestProxyBase::didFinishLoad(WebFrame* frame)
1112 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
1113 printFrameDescription(m_delegate, frame);
1114 m_delegate->printMessage(" - didFinishLoadForFrame\n");
1116 locationChangeDone(frame);
1119 void WebTestProxyBase::didDetectXSS(WebFrame*, const WebURL&, bool)
1121 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks())
1122 m_delegate->printMessage("didDetectXSS\n");
1125 void WebTestProxyBase::didDispatchPingLoader(WebFrame*, const WebURL& url)
1127 if (m_testInterfaces->testRunner()->shouldDumpPingLoaderCallbacks())
1128 m_delegate->printMessage(string("PingLoader dispatched to '") + URLDescription(url).c_str() + "'.\n");
1131 void WebTestProxyBase::willRequestResource(WebFrame* frame, const blink::WebCachedURLRequest& request)
1133 if (m_testInterfaces->testRunner()->shouldDumpResourceRequestCallbacks()) {
1134 printFrameDescription(m_delegate, frame);
1135 m_delegate->printMessage(string(" - ") + request.initiatorName().utf8().data());
1136 m_delegate->printMessage(string(" requested '") + URLDescription(request.urlRequest().url()).c_str() + "'\n");
1140 void WebTestProxyBase::willSendRequest(WebFrame*, unsigned identifier, blink::WebURLRequest& request, const blink::WebURLResponse& redirectResponse)
1142 // Need to use GURL for host() and SchemeIs()
1143 GURL url = request.url();
1144 string requestURL = url.possibly_invalid_spec();
1146 GURL mainDocumentURL = request.firstPartyForCookies();
1148 if (redirectResponse.isNull() && (m_testInterfaces->testRunner()->shouldDumpResourceLoadCallbacks() || m_testInterfaces->testRunner()->shouldDumpResourcePriorities())) {
1149 BLINK_ASSERT(m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end());
1150 m_resourceIdentifierMap[identifier] = descriptionSuitableForTestResult(requestURL);
1153 if (m_testInterfaces->testRunner()->shouldDumpResourceLoadCallbacks()) {
1154 if (m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end())
1155 m_delegate->printMessage("<unknown>");
1157 m_delegate->printMessage(m_resourceIdentifierMap[identifier]);
1158 m_delegate->printMessage(" - willSendRequest <NSURLRequest URL ");
1159 m_delegate->printMessage(descriptionSuitableForTestResult(requestURL).c_str());
1160 m_delegate->printMessage(", main document URL ");
1161 m_delegate->printMessage(URLDescription(mainDocumentURL).c_str());
1162 m_delegate->printMessage(", http method ");
1163 m_delegate->printMessage(request.httpMethod().utf8().data());
1164 m_delegate->printMessage("> redirectResponse ");
1165 printResponseDescription(m_delegate, redirectResponse);
1166 m_delegate->printMessage("\n");
1169 if (m_testInterfaces->testRunner()->shouldDumpResourcePriorities()) {
1170 m_delegate->printMessage(descriptionSuitableForTestResult(requestURL).c_str());
1171 m_delegate->printMessage(" has priority ");
1172 m_delegate->printMessage(PriorityDescription(request.priority()));
1173 m_delegate->printMessage("\n");
1176 if (m_testInterfaces->testRunner()->httpHeadersToClear()) {
1177 const set<string> *clearHeaders = m_testInterfaces->testRunner()->httpHeadersToClear();
1178 for (set<string>::const_iterator header = clearHeaders->begin(); header != clearHeaders->end(); ++header)
1179 request.clearHTTPHeaderField(WebString::fromUTF8(*header));
1182 string host = url.host();
1183 if (!host.empty() && (url.SchemeIs("http") || url.SchemeIs("https"))) {
1184 if (!isLocalhost(host) && !hostIsUsedBySomeTestsToGenerateError(host)
1185 && ((!mainDocumentURL.SchemeIs("http") && !mainDocumentURL.SchemeIs("https")) || isLocalhost(mainDocumentURL.host()))
1186 && !m_delegate->allowExternalPages()) {
1187 m_delegate->printMessage(string("Blocked access to external URL ") + requestURL + "\n");
1188 blockRequest(request);
1193 // Set the new substituted URL.
1194 request.setURL(m_delegate->rewriteLayoutTestsURL(request.url().spec()));
1197 void WebTestProxyBase::didReceiveResponse(WebFrame*, unsigned identifier, const blink::WebURLResponse& response)
1199 if (m_testInterfaces->testRunner()->shouldDumpResourceLoadCallbacks()) {
1200 if (m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end())
1201 m_delegate->printMessage("<unknown>");
1203 m_delegate->printMessage(m_resourceIdentifierMap[identifier]);
1204 m_delegate->printMessage(" - didReceiveResponse ");
1205 printResponseDescription(m_delegate, response);
1206 m_delegate->printMessage("\n");
1208 if (m_testInterfaces->testRunner()->shouldDumpResourceResponseMIMETypes()) {
1209 GURL url = response.url();
1210 WebString mimeType = response.mimeType();
1211 m_delegate->printMessage(url.ExtractFileName());
1212 m_delegate->printMessage(" has MIME type ");
1213 // Simulate NSURLResponse's mapping of empty/unknown MIME types to application/octet-stream
1214 m_delegate->printMessage(mimeType.isEmpty() ? "application/octet-stream" : mimeType.utf8().data());
1215 m_delegate->printMessage("\n");
1219 void WebTestProxyBase::didChangeResourcePriority(WebFrame*, unsigned identifier, const blink::WebURLRequest::Priority& priority)
1221 if (m_testInterfaces->testRunner()->shouldDumpResourcePriorities()) {
1222 if (m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end())
1223 m_delegate->printMessage("<unknown>");
1225 m_delegate->printMessage(m_resourceIdentifierMap[identifier]);
1226 m_delegate->printMessage(" changed priority to ");
1227 m_delegate->printMessage(PriorityDescription(priority));
1228 m_delegate->printMessage("\n");
1232 void WebTestProxyBase::didFinishResourceLoad(WebFrame*, unsigned identifier)
1234 if (m_testInterfaces->testRunner()->shouldDumpResourceLoadCallbacks()) {
1235 if (m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end())
1236 m_delegate->printMessage("<unknown>");
1238 m_delegate->printMessage(m_resourceIdentifierMap[identifier]);
1239 m_delegate->printMessage(" - didFinishLoading\n");
1241 m_resourceIdentifierMap.erase(identifier);
1244 void WebTestProxyBase::didAddMessageToConsole(const WebConsoleMessage& message, const WebString& sourceName, unsigned sourceLine)
1246 // This matches win DumpRenderTree's UIDelegate.cpp.
1247 if (!m_logConsoleOutput)
1250 switch (message.level) {
1251 case WebConsoleMessage::LevelDebug:
1254 case WebConsoleMessage::LevelLog:
1257 case WebConsoleMessage::LevelInfo:
1260 case WebConsoleMessage::LevelWarning:
1263 case WebConsoleMessage::LevelError:
1267 m_delegate->printMessage(string("CONSOLE ") + level + ": ");
1270 snprintf(buffer, sizeof(buffer), "line %d: ", sourceLine);
1271 m_delegate->printMessage(buffer);
1273 if (!message.text.isEmpty()) {
1275 newMessage = message.text.utf8();
1276 size_t fileProtocol = newMessage.find("file://");
1277 if (fileProtocol != string::npos) {
1278 newMessage = newMessage.substr(0, fileProtocol)
1279 + urlSuitableForTestResult(newMessage.substr(fileProtocol));
1281 m_delegate->printMessage(newMessage);
1283 m_delegate->printMessage(string("\n"));
1286 void WebTestProxyBase::runModalAlertDialog(WebFrame*, const WebString& message)
1288 m_delegate->printMessage(string("ALERT: ") + message.utf8().data() + "\n");
1291 bool WebTestProxyBase::runModalConfirmDialog(WebFrame*, const WebString& message)
1293 m_delegate->printMessage(string("CONFIRM: ") + message.utf8().data() + "\n");
1297 bool WebTestProxyBase::runModalPromptDialog(WebFrame* frame, const WebString& message, const WebString& defaultValue, WebString*)
1299 m_delegate->printMessage(string("PROMPT: ") + message.utf8().data() + ", default text: " + defaultValue.utf8().data() + "\n");
1303 bool WebTestProxyBase::runModalBeforeUnloadDialog(WebFrame*, const WebString& message)
1305 m_delegate->printMessage(string("CONFIRM NAVIGATION: ") + message.utf8().data() + "\n");
1306 return !m_testInterfaces->testRunner()->shouldStayOnPageAfterHandlingBeforeUnload();
1309 void WebTestProxyBase::locationChangeDone(WebFrame* frame)
1311 if (frame != m_testInterfaces->testRunner()->topLoadingFrame())
1313 m_testInterfaces->testRunner()->setTopLoadingFrame(frame, true);
1316 WebNavigationPolicy WebTestProxyBase::decidePolicyForNavigation(WebFrame*, WebDataSource::ExtraData*, const WebURLRequest& request, WebNavigationType type, WebNavigationPolicy defaultPolicy, bool isRedirect)
1318 WebNavigationPolicy result;
1319 if (!m_testInterfaces->testRunner()->policyDelegateEnabled())
1320 return defaultPolicy;
1322 m_delegate->printMessage(string("Policy delegate: attempt to load ") + URLDescription(request.url()) + " with navigation type '" + webNavigationTypeToString(type) + "'\n");
1323 if (m_testInterfaces->testRunner()->policyDelegateIsPermissive())
1324 result = blink::WebNavigationPolicyCurrentTab;
1326 result = blink::WebNavigationPolicyIgnore;
1328 if (m_testInterfaces->testRunner()->policyDelegateShouldNotifyDone())
1329 m_testInterfaces->testRunner()->policyDelegateDone();
1333 bool WebTestProxyBase::willCheckAndDispatchMessageEvent(WebFrame*, WebFrame*, WebSecurityOrigin, WebDOMMessageEvent)
1335 if (m_testInterfaces->testRunner()->shouldInterceptPostMessage()) {
1336 m_delegate->printMessage("intercepted postMessage\n");
1343 void WebTestProxyBase::postSpellCheckEvent(const WebString& eventName)
1345 if (m_testInterfaces->testRunner()->shouldDumpSpellCheckCallbacks()) {
1346 m_delegate->printMessage(string("SpellCheckEvent: ") + eventName.utf8().data() + "\n");
1350 void WebTestProxyBase::resetInputMethod()
1352 // If a composition text exists, then we need to let the browser process
1353 // to cancel the input method's ongoing composition session.
1355 m_webWidget->confirmComposition();