blob: 0610585a6bac72541358e2d9d706476c1b8ff6a9 [file] [log] [blame]
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +00001/*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
Ben Murdoch591b9582013-07-10 11:41:44 +010031#include "public/testing/WebTestProxy.h"
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +000032
Torne (Richard Coles)926b0012013-03-28 15:32:48 +000033#include "AccessibilityControllerChromium.h"
34#include "EventSender.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010035#include "MockColorChooser.h"
Torne (Richard Coles)926b0012013-03-28 15:32:48 +000036#include "MockWebSpeechInputController.h"
37#include "MockWebSpeechRecognizer.h"
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +010038#include "MockWebValidationMessageClient.h"
Torne (Richard Coles)926b0012013-03-28 15:32:48 +000039#include "SpellCheckClient.h"
40#include "TestCommon.h"
41#include "TestInterfaces.h"
42#include "TestPlugin.h"
43#include "TestRunner.h"
Torne (Richard Coles)926b0012013-03-28 15:32:48 +000044#include "WebUserMediaClientMock.h"
Torne (Richard Coles)5267f702013-06-11 10:57:24 +010045#include "public/platform/WebCString.h"
46#include "public/platform/WebURLError.h"
47#include "public/platform/WebURLRequest.h"
48#include "public/platform/WebURLResponse.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010049#include "public/testing/WebTestDelegate.h"
50#include "public/testing/WebTestInterfaces.h"
51#include "public/testing/WebTestRunner.h"
52#include "public/web/WebAccessibilityNotification.h"
53#include "public/web/WebAccessibilityObject.h"
54#include "public/web/WebCachedURLRequest.h"
55#include "public/web/WebConsoleMessage.h"
56#include "public/web/WebDataSource.h"
57#include "public/web/WebDeviceOrientationClientMock.h"
58#include "public/web/WebDocument.h"
59#include "public/web/WebElement.h"
60#include "public/web/WebFrame.h"
61#include "public/web/WebGeolocationClientMock.h"
62#include "public/web/WebHistoryItem.h"
63#include "public/web/WebNode.h"
64#include "public/web/WebPluginParams.h"
65#include "public/web/WebPrintParams.h"
66#include "public/web/WebRange.h"
67#include "public/web/WebScriptController.h"
68#include "public/web/WebUserGestureIndicator.h"
69#include "public/web/WebView.h"
70
71// FIXME: Including platform_canvas.h here is a layering violation.
72#include <cctype>
73#include "skia/ext/platform_canvas.h"
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +000074
75using namespace WebKit;
Torne (Richard Coles)926b0012013-03-28 15:32:48 +000076using namespace std;
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +000077
78namespace WebTestRunner {
79
Torne (Richard Coles)926b0012013-03-28 15:32:48 +000080namespace {
81
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +010082class HostMethodTask : public WebMethodTask<WebTestProxyBase> {
83public:
84 typedef void (WebTestProxyBase::*CallbackMethodType)();
85 HostMethodTask(WebTestProxyBase* object, CallbackMethodType callback)
86 : WebMethodTask<WebTestProxyBase>(object)
87 , m_callback(callback)
88 { }
89
90 virtual void runIfValid() { (m_object->*m_callback)(); }
91
92private:
93 CallbackMethodType m_callback;
94};
95
Torne (Richard Coles)926b0012013-03-28 15:32:48 +000096void printNodeDescription(WebTestDelegate* delegate, const WebNode& node, int exception)
97{
98 if (exception) {
99 delegate->printMessage("ERROR");
100 return;
101 }
102 if (node.isNull()) {
103 delegate->printMessage("(null)");
104 return;
105 }
106 delegate->printMessage(node.nodeName().utf8().data());
107 const WebNode& parent = node.parentNode();
108 if (!parent.isNull()) {
109 delegate->printMessage(" > ");
110 printNodeDescription(delegate, parent, 0);
111 }
112}
113
114void printRangeDescription(WebTestDelegate* delegate, const WebRange& range)
115{
116 if (range.isNull()) {
117 delegate->printMessage("(null)");
118 return;
119 }
120 char buffer[100];
121 snprintf(buffer, sizeof(buffer), "range from %d of ", range.startOffset());
122 delegate->printMessage(buffer);
123 int exception = 0;
124 WebNode startNode = range.startContainer(exception);
125 printNodeDescription(delegate, startNode, exception);
126 snprintf(buffer, sizeof(buffer), " to %d of ", range.endOffset());
127 delegate->printMessage(buffer);
128 WebNode endNode = range.endContainer(exception);
129 printNodeDescription(delegate, endNode, exception);
130}
131
132string editingActionDescription(WebEditingAction action)
133{
134 switch (action) {
135 case WebKit::WebEditingActionTyped:
136 return "WebViewInsertActionTyped";
137 case WebKit::WebEditingActionPasted:
138 return "WebViewInsertActionPasted";
139 case WebKit::WebEditingActionDropped:
140 return "WebViewInsertActionDropped";
141 }
142 return "(UNKNOWN ACTION)";
143}
144
145string textAffinityDescription(WebTextAffinity affinity)
146{
147 switch (affinity) {
148 case WebKit::WebTextAffinityUpstream:
149 return "NSSelectionAffinityUpstream";
150 case WebKit::WebTextAffinityDownstream:
151 return "NSSelectionAffinityDownstream";
152 }
153 return "(UNKNOWN AFFINITY)";
154}
155
156void printFrameDescription(WebTestDelegate* delegate, WebFrame* frame)
157{
158 string name8 = frame->uniqueName().utf8();
159 if (frame == frame->view()->mainFrame()) {
160 if (!name8.length()) {
161 delegate->printMessage("main frame");
162 return;
163 }
164 delegate->printMessage(string("main frame \"") + name8 + "\"");
165 return;
166 }
167 if (!name8.length()) {
168 delegate->printMessage("frame (anonymous)");
169 return;
170 }
171 delegate->printMessage(string("frame \"") + name8 + "\"");
172}
173
174void printFrameUserGestureStatus(WebTestDelegate* delegate, WebFrame* frame, const char* msg)
175{
176 bool isUserGesture = WebUserGestureIndicator::isProcessingUserGesture();
177 delegate->printMessage(string("Frame with user gesture \"") + (isUserGesture ? "true" : "false") + "\"" + msg);
178}
179
180// Used to write a platform neutral file:/// URL by taking the
181// filename and its directory. (e.g., converts
182// "file:///tmp/foo/bar.txt" to just "bar.txt").
183string descriptionSuitableForTestResult(const string& url)
184{
185 if (url.empty() || string::npos == url.find("file://"))
186 return url;
187
188 size_t pos = url.rfind('/');
189 if (pos == string::npos || !pos)
190 return "ERROR:" + url;
191 pos = url.rfind('/', pos - 1);
192 if (pos == string::npos)
193 return "ERROR:" + url;
194
195 return url.substr(pos + 1);
196}
197
198void printResponseDescription(WebTestDelegate* delegate, const WebURLResponse& response)
199{
200 if (response.isNull()) {
201 delegate->printMessage("(null)");
202 return;
203 }
204 string url = response.url().spec();
205 char data[100];
206 snprintf(data, sizeof(data), "%d", response. httpStatusCode());
207 delegate->printMessage(string("<NSURLResponse ") + descriptionSuitableForTestResult(url) + ", http status code " + data + ">");
208}
209
210string URLDescription(const GURL& url)
211{
212 if (url.SchemeIs("file"))
213 return url.ExtractFileName();
214 return url.possibly_invalid_spec();
215}
216
217string PriorityDescription(const WebURLRequest::Priority& priority)
218{
219 switch (priority) {
220 case WebURLRequest::PriorityVeryLow:
221 return "VeryLow";
222 case WebURLRequest::PriorityLow:
223 return "Low";
224 case WebURLRequest::PriorityMedium:
225 return "Medium";
226 case WebURLRequest::PriorityHigh:
227 return "High";
228 case WebURLRequest::PriorityVeryHigh:
229 return "VeryHigh";
230 case WebURLRequest::PriorityUnresolved:
231 default:
232 return "Unresolved";
233 }
234}
235
236void blockRequest(WebURLRequest& request)
237{
238 request.setURL(WebURL());
239}
240
241bool isLocalhost(const string& host)
242{
243 return host == "127.0.0.1" || host == "localhost";
244}
245
246bool hostIsUsedBySomeTestsToGenerateError(const string& host)
247{
248 return host == "255.255.255.255";
249}
250
251// Used to write a platform neutral file:/// URL by only taking the filename
252// (e.g., converts "file:///tmp/foo.txt" to just "foo.txt").
253string urlSuitableForTestResult(const string& url)
254{
255 if (url.empty() || string::npos == url.find("file://"))
256 return url;
257
258 size_t pos = url.rfind('/');
259 if (pos == string::npos) {
260#ifdef WIN32
261 pos = url.rfind('\\');
262 if (pos == string::npos)
263 pos = 0;
264#else
265 pos = 0;
266#endif
267 }
268 string filename = url.substr(pos + 1);
269 if (filename.empty())
270 return "file:"; // A WebKit test has this in its expected output.
271 return filename;
272}
273
274// WebNavigationType debugging strings taken from PolicyDelegate.mm.
275const char* linkClickedString = "link clicked";
276const char* formSubmittedString = "form submitted";
277const char* backForwardString = "back/forward";
278const char* reloadString = "reload";
279const char* formResubmittedString = "form resubmitted";
280const char* otherString = "other";
281const char* illegalString = "illegal value";
282
283// Get a debugging string from a WebNavigationType.
284const char* webNavigationTypeToString(WebNavigationType type)
285{
286 switch (type) {
287 case WebKit::WebNavigationTypeLinkClicked:
288 return linkClickedString;
289 case WebKit::WebNavigationTypeFormSubmitted:
290 return formSubmittedString;
291 case WebKit::WebNavigationTypeBackForward:
292 return backForwardString;
293 case WebKit::WebNavigationTypeReload:
294 return reloadString;
295 case WebKit::WebNavigationTypeFormResubmitted:
296 return formResubmittedString;
297 case WebKit::WebNavigationTypeOther:
298 return otherString;
299 }
300 return illegalString;
301}
302
303string dumpDocumentText(WebFrame* frame)
304{
305 // We use the document element's text instead of the body text here because
306 // not all documents have a body, such as XML documents.
307 WebElement documentElement = frame->document().documentElement();
308 if (documentElement.isNull())
309 return string();
310 return documentElement.innerText().utf8();
311}
312
313string dumpFramesAsText(WebFrame* frame, bool recursive)
314{
315 string result;
316
317 // Add header for all but the main frame. Skip empty frames.
318 if (frame->parent() && !frame->document().documentElement().isNull()) {
319 result.append("\n--------\nFrame: '");
320 result.append(frame->uniqueName().utf8().data());
321 result.append("'\n--------\n");
322 }
323
324 result.append(dumpDocumentText(frame));
325 result.append("\n");
326
327 if (recursive) {
328 for (WebFrame* child = frame->firstChild(); child; child = child->nextSibling())
329 result.append(dumpFramesAsText(child, recursive));
330 }
331
332 return result;
333}
334
335string dumpFramesAsPrintedText(WebFrame* frame, bool recursive)
336{
337 string result;
338
339 // Cannot do printed format for anything other than HTML
340 if (!frame->document().isHTMLDocument())
341 return string();
342
343 // Add header for all but the main frame. Skip empty frames.
344 if (frame->parent() && !frame->document().documentElement().isNull()) {
345 result.append("\n--------\nFrame: '");
346 result.append(frame->uniqueName().utf8().data());
347 result.append("'\n--------\n");
348 }
349
350 result.append(frame->renderTreeAsText(WebFrame::RenderAsTextPrinting).utf8());
351 result.append("\n");
352
353 if (recursive) {
354 for (WebFrame* child = frame->firstChild(); child; child = child->nextSibling())
355 result.append(dumpFramesAsPrintedText(child, recursive));
356 }
357
358 return result;
359}
360
361string dumpFrameScrollPosition(WebFrame* frame, bool recursive)
362{
363 string result;
364 WebSize offset = frame->scrollOffset();
365 if (offset.width > 0 || offset.height > 0) {
366 if (frame->parent())
367 result = string("frame '") + frame->uniqueName().utf8().data() + "' ";
368 char data[100];
369 snprintf(data, sizeof(data), "scrolled to %d,%d\n", offset.width, offset.height);
370 result += data;
371 }
372
373 if (!recursive)
374 return result;
375 for (WebFrame* child = frame->firstChild(); child; child = child->nextSibling())
376 result += dumpFrameScrollPosition(child, recursive);
377 return result;
378}
379
380struct ToLower {
381 char16 operator()(char16 c) { return tolower(c); }
382};
383
384// Returns True if item1 < item2.
385bool HistoryItemCompareLess(const WebHistoryItem& item1, const WebHistoryItem& item2)
386{
387 string16 target1 = item1.target();
388 string16 target2 = item2.target();
389 std::transform(target1.begin(), target1.end(), target1.begin(), ToLower());
390 std::transform(target2.begin(), target2.end(), target2.begin(), ToLower());
391 return target1 < target2;
392}
393
394string dumpHistoryItem(const WebHistoryItem& item, int indent, bool isCurrent)
395{
396 string result;
397
398 if (isCurrent) {
399 result.append("curr->");
400 result.append(indent - 6, ' '); // 6 == "curr->".length()
401 } else
402 result.append(indent, ' ');
403
404 string url = normalizeLayoutTestURL(item.urlString().utf8());
405 result.append(url);
406 if (!item.target().isEmpty()) {
407 result.append(" (in frame \"");
408 result.append(item.target().utf8());
409 result.append("\")");
410 }
411 if (item.isTargetItem())
412 result.append(" **nav target**");
413 result.append("\n");
414
415 const WebVector<WebHistoryItem>& children = item.children();
416 if (!children.isEmpty()) {
417 // Must sort to eliminate arbitrary result ordering which defeats
418 // reproducible testing.
419 // FIXME: WebVector should probably just be a std::vector!!
420 std::vector<WebHistoryItem> sortedChildren;
421 for (size_t i = 0; i < children.size(); ++i)
422 sortedChildren.push_back(children[i]);
423 std::sort(sortedChildren.begin(), sortedChildren.end(), HistoryItemCompareLess);
424 for (size_t i = 0; i < sortedChildren.size(); ++i)
425 result += dumpHistoryItem(sortedChildren[i], indent + 4, false);
426 }
427
428 return result;
429}
430
431void dumpBackForwardList(const WebVector<WebHistoryItem>& history, size_t currentEntryIndex, string& result)
432{
433 result.append("\n============== Back Forward List ==============\n");
434 for (size_t index = 0; index < history.size(); ++index)
435 result.append(dumpHistoryItem(history[index], 8, index == currentEntryIndex));
436 result.append("===============================================\n");
437}
438
439string dumpAllBackForwardLists(TestInterfaces* interfaces, WebTestDelegate* delegate)
440{
441 string result;
442 const vector<WebTestProxyBase*>& windowList = interfaces->windowList();
443 for (unsigned i = 0; i < windowList.size(); ++i) {
444 size_t currentEntryIndex = 0;
445 WebVector<WebHistoryItem> history;
446 delegate->captureHistoryForWindow(windowList.at(i), &history, &currentEntryIndex);
447 dumpBackForwardList(history, currentEntryIndex, result);
448 }
449 return result;
450}
451
452}
453
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000454WebTestProxyBase::WebTestProxyBase()
455 : m_testInterfaces(0)
456 , m_delegate(0)
Torne (Richard Coles)5267f702013-06-11 10:57:24 +0100457 , m_webWidget(0)
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000458 , m_spellcheck(new SpellCheckClient)
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100459 , m_chooserCount(0)
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100460 , m_validationMessageClient(new MockWebValidationMessageClient())
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000461{
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000462 reset();
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000463}
464
465WebTestProxyBase::~WebTestProxyBase()
466{
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000467 m_testInterfaces->windowClosed(this);
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000468}
469
470void WebTestProxyBase::setInterfaces(WebTestInterfaces* interfaces)
471{
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000472 m_testInterfaces = interfaces->testInterfaces();
473 m_testInterfaces->windowOpened(this);
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000474}
475
476void WebTestProxyBase::setDelegate(WebTestDelegate* delegate)
477{
478 m_delegate = delegate;
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000479 m_spellcheck->setDelegate(delegate);
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100480 m_validationMessageClient->setDelegate(delegate);
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000481#if ENABLE_INPUT_SPEECH
482 if (m_speechInputController.get())
483 m_speechInputController->setDelegate(delegate);
484#endif
485 if (m_speechRecognizer.get())
486 m_speechRecognizer->setDelegate(delegate);
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000487}
488
Torne (Richard Coles)5267f702013-06-11 10:57:24 +0100489void WebTestProxyBase::setWidget(WebWidget* widget)
490{
491 m_webWidget = widget;
492}
493
494WebWidget* WebTestProxyBase::webWidget()
495{
496 return m_webWidget;
497}
498
499WebView* WebTestProxyBase::webView()
500{
501 WEBKIT_ASSERT(m_webWidget);
502 // TestRunner does not support popup widgets. So m_webWidget is always a WebView.
503 return static_cast<WebView*>(m_webWidget);
504}
505
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000506void WebTestProxyBase::reset()
507{
508 m_paintRect = WebRect();
509 m_canvas.reset();
510 m_isPainting = false;
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100511 m_animateScheduled = false;
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000512 m_resourceIdentifierMap.clear();
513 m_logConsoleOutput = true;
514 if (m_geolocationClient.get())
515 m_geolocationClient->resetMock();
516#if ENABLE_INPUT_SPEECH
517 if (m_speechInputController.get())
518 m_speechInputController->clearResults();
519#endif
520}
521
522WebSpellCheckClient* WebTestProxyBase::spellCheckClient() const
523{
524 return m_spellcheck.get();
525}
526
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100527WebValidationMessageClient* WebTestProxyBase::validationMessageClient()
528{
529 return m_validationMessageClient.get();
530}
531
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100532WebColorChooser* WebTestProxyBase::createColorChooser(WebColorChooserClient* client, const WebKit::WebColor& color)
533{
534 // This instance is deleted by WebCore::ColorInputType
535 return new MockColorChooser(client, m_delegate, this);
536}
537
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000538string WebTestProxyBase::captureTree(bool debugRenderTree)
539{
540 WebScriptController::flushConsoleMessages();
541
542 bool shouldDumpAsText = m_testInterfaces->testRunner()->shouldDumpAsText();
543 bool shouldDumpAsPrinted = m_testInterfaces->testRunner()->isPrinting();
Torne (Richard Coles)5267f702013-06-11 10:57:24 +0100544 WebFrame* frame = webView()->mainFrame();
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000545 string dataUtf8;
546 if (shouldDumpAsText) {
547 bool recursive = m_testInterfaces->testRunner()->shouldDumpChildFramesAsText();
548 dataUtf8 = shouldDumpAsPrinted ? dumpFramesAsPrintedText(frame, recursive) : dumpFramesAsText(frame, recursive);
549 } else {
550 bool recursive = m_testInterfaces->testRunner()->shouldDumpChildFrameScrollPositions();
551 WebFrame::RenderAsTextControls renderTextBehavior = WebFrame::RenderAsTextNormal;
552 if (shouldDumpAsPrinted)
553 renderTextBehavior |= WebFrame::RenderAsTextPrinting;
554 if (debugRenderTree)
555 renderTextBehavior |= WebFrame::RenderAsTextDebug;
556 dataUtf8 = frame->renderTreeAsText(renderTextBehavior).utf8();
557 dataUtf8 += dumpFrameScrollPosition(frame, recursive);
558 }
559
560 if (m_testInterfaces->testRunner()->shouldDumpBackForwardList())
561 dataUtf8 += dumpAllBackForwardLists(m_testInterfaces, m_delegate);
562
563 return dataUtf8;
564}
565
566SkCanvas* WebTestProxyBase::capturePixels()
567{
Torne (Richard Coles)5267f702013-06-11 10:57:24 +0100568 webWidget()->layout();
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000569 if (m_testInterfaces->testRunner()->testRepaint()) {
Torne (Richard Coles)5267f702013-06-11 10:57:24 +0100570 WebSize viewSize = webWidget()->size();
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000571 int width = viewSize.width;
572 int height = viewSize.height;
573 if (m_testInterfaces->testRunner()->sweepHorizontally()) {
574 for (WebRect column(0, 0, 1, height); column.x < width; column.x++)
575 paintRect(column);
576 } else {
577 for (WebRect line(0, 0, width, 1); line.y < height; line.y++)
578 paintRect(line);
579 }
580 } else if (m_testInterfaces->testRunner()->isPrinting())
581 paintPagesWithBoundaries();
582 else
583 paintInvalidatedRegion();
584
585 // See if we need to draw the selection bounds rect. Selection bounds
586 // rect is the rect enclosing the (possibly transformed) selection.
587 // The rect should be drawn after everything is laid out and painted.
588 if (m_testInterfaces->testRunner()->shouldDumpSelectionRect()) {
589 // If there is a selection rect - draw a red 1px border enclosing rect
Torne (Richard Coles)5267f702013-06-11 10:57:24 +0100590 WebRect wr = webView()->mainFrame()->selectionBoundsRect();
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000591 if (!wr.isEmpty()) {
592 // Render a red rectangle bounding selection rect
593 SkPaint paint;
594 paint.setColor(0xFFFF0000); // Fully opaque red
595 paint.setStyle(SkPaint::kStroke_Style);
596 paint.setFlags(SkPaint::kAntiAlias_Flag);
597 paint.setStrokeWidth(1.0f);
598 SkIRect rect; // Bounding rect
599 rect.set(wr.x, wr.y, wr.x + wr.width, wr.y + wr.height);
600 canvas()->drawIRect(rect, paint);
601 }
602 }
603
604 return canvas();
605}
606
607void WebTestProxyBase::setLogConsoleOutput(bool enabled)
608{
609 m_logConsoleOutput = enabled;
610}
611
612void WebTestProxyBase::paintRect(const WebRect& rect)
613{
614 WEBKIT_ASSERT(!m_isPainting);
615 WEBKIT_ASSERT(canvas());
616 m_isPainting = true;
Torne (Richard Coles)5267f702013-06-11 10:57:24 +0100617 float deviceScaleFactor = webView()->deviceScaleFactor();
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000618 int scaledX = static_cast<int>(static_cast<float>(rect.x) * deviceScaleFactor);
619 int scaledY = static_cast<int>(static_cast<float>(rect.y) * deviceScaleFactor);
620 int scaledWidth = static_cast<int>(ceil(static_cast<float>(rect.width) * deviceScaleFactor));
621 int scaledHeight = static_cast<int>(ceil(static_cast<float>(rect.height) * deviceScaleFactor));
622 WebRect deviceRect(scaledX, scaledY, scaledWidth, scaledHeight);
Torne (Richard Coles)5267f702013-06-11 10:57:24 +0100623 webWidget()->paint(canvas(), deviceRect);
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000624 m_isPainting = false;
625}
626
627void WebTestProxyBase::paintInvalidatedRegion()
628{
Torne (Richard Coles)5267f702013-06-11 10:57:24 +0100629 webWidget()->animate(0.0);
630 webWidget()->layout();
631 WebSize widgetSize = webWidget()->size();
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000632 WebRect clientRect(0, 0, widgetSize.width, widgetSize.height);
633
634 // Paint the canvas if necessary. Allow painting to generate extra rects
635 // for the first two calls. This is necessary because some WebCore rendering
636 // objects update their layout only when painted.
637 // Store the total area painted in total_paint. Then tell the gdk window
638 // to update that area after we're done painting it.
639 for (int i = 0; i < 3; ++i) {
640 // rect = intersect(m_paintRect , clientRect)
641 WebRect damageRect = m_paintRect;
642 int left = max(damageRect.x, clientRect.x);
643 int top = max(damageRect.y, clientRect.y);
644 int right = min(damageRect.x + damageRect.width, clientRect.x + clientRect.width);
645 int bottom = min(damageRect.y + damageRect.height, clientRect.y + clientRect.height);
646 WebRect rect;
647 if (left < right && top < bottom)
648 rect = WebRect(left, top, right - left, bottom - top);
649
650 m_paintRect = WebRect();
651 if (rect.isEmpty())
652 continue;
653 paintRect(rect);
654 }
655 WEBKIT_ASSERT(m_paintRect.isEmpty());
656}
657
658void WebTestProxyBase::paintPagesWithBoundaries()
659{
660 WEBKIT_ASSERT(!m_isPainting);
661 WEBKIT_ASSERT(canvas());
662 m_isPainting = true;
663
Torne (Richard Coles)5267f702013-06-11 10:57:24 +0100664 WebSize pageSizeInPixels = webWidget()->size();
665 WebFrame* webFrame = webView()->mainFrame();
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000666
667 int pageCount = webFrame->printBegin(pageSizeInPixels);
668 int totalHeight = pageCount * (pageSizeInPixels.height + 1) - 1;
669
670 SkCanvas* testCanvas = skia::TryCreateBitmapCanvas(pageSizeInPixels.width, totalHeight, true);
671 if (testCanvas) {
672 discardBackingStore();
673 m_canvas.reset(testCanvas);
674 } else {
675 webFrame->printEnd();
676 return;
677 }
678
679 webFrame->printPagesWithBoundaries(canvas(), pageSizeInPixels);
680 webFrame->printEnd();
681
682 m_isPainting = false;
683}
684
685SkCanvas* WebTestProxyBase::canvas()
686{
687 if (m_canvas.get())
688 return m_canvas.get();
Torne (Richard Coles)5267f702013-06-11 10:57:24 +0100689 WebSize widgetSize = webWidget()->size();
690 float deviceScaleFactor = webView()->deviceScaleFactor();
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000691 int scaledWidth = static_cast<int>(ceil(static_cast<float>(widgetSize.width) * deviceScaleFactor));
692 int scaledHeight = static_cast<int>(ceil(static_cast<float>(widgetSize.height) * deviceScaleFactor));
693 m_canvas.reset(skia::CreateBitmapCanvas(scaledWidth, scaledHeight, true));
694 return m_canvas.get();
695}
696
697// Paints the entire canvas a semi-transparent black (grayish). This is used
698// by the layout tests in fast/repaint. The alpha value matches upstream.
699void WebTestProxyBase::displayRepaintMask()
700{
701 canvas()->drawARGB(167, 0, 0, 0);
702}
703
704void WebTestProxyBase::display()
705{
Torne (Richard Coles)5267f702013-06-11 10:57:24 +0100706 const WebKit::WebSize& size = webWidget()->size();
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000707 WebRect rect(0, 0, size.width, size.height);
708 m_paintRect = rect;
709 paintInvalidatedRegion();
710 displayRepaintMask();
711}
712
713void WebTestProxyBase::displayInvalidatedRegion()
714{
715 paintInvalidatedRegion();
716 displayRepaintMask();
717}
718
719void WebTestProxyBase::discardBackingStore()
720{
721 m_canvas.reset();
722}
723
724WebGeolocationClientMock* WebTestProxyBase::geolocationClientMock()
725{
726 if (!m_geolocationClient.get())
727 m_geolocationClient.reset(WebGeolocationClientMock::create());
728 return m_geolocationClient.get();
729}
730
731WebDeviceOrientationClientMock* WebTestProxyBase::deviceOrientationClientMock()
732{
733 if (!m_deviceOrientationClient.get())
734 m_deviceOrientationClient.reset(WebDeviceOrientationClientMock::create());
735 return m_deviceOrientationClient.get();
736}
737
738#if ENABLE_INPUT_SPEECH
739MockWebSpeechInputController* WebTestProxyBase::speechInputControllerMock()
740{
741 WEBKIT_ASSERT(m_speechInputController.get());
742 return m_speechInputController.get();
743}
744#endif
745
746MockWebSpeechRecognizer* WebTestProxyBase::speechRecognizerMock()
747{
748 if (!m_speechRecognizer.get()) {
749 m_speechRecognizer.reset(new MockWebSpeechRecognizer());
750 m_speechRecognizer->setDelegate(m_delegate);
751 }
752 return m_speechRecognizer.get();
753}
754
755void WebTestProxyBase::didInvalidateRect(const WebRect& rect)
756{
757 // m_paintRect = m_paintRect U rect
758 if (rect.isEmpty())
759 return;
760 if (m_paintRect.isEmpty()) {
761 m_paintRect = rect;
762 return;
763 }
764 int left = min(m_paintRect.x, rect.x);
765 int top = min(m_paintRect.y, rect.y);
766 int right = max(m_paintRect.x + m_paintRect.width, rect.x + rect.width);
767 int bottom = max(m_paintRect.y + m_paintRect.height, rect.y + rect.height);
768 m_paintRect = WebRect(left, top, right - left, bottom - top);
769}
770
771void WebTestProxyBase::didScrollRect(int, int, const WebRect& clipRect)
772{
773 didInvalidateRect(clipRect);
774}
775
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100776void WebTestProxyBase::invalidateAll()
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000777{
778 m_paintRect = WebRect(0, 0, INT_MAX, INT_MAX);
779}
780
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100781void WebTestProxyBase::scheduleComposite()
782{
783 invalidateAll();
784}
785
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000786void WebTestProxyBase::scheduleAnimation()
787{
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100788 if (!m_testInterfaces->testRunner()->testIsRunning())
789 return;
790
791 if (!m_animateScheduled) {
792 m_animateScheduled = true;
793 m_delegate->postDelayedTask(new HostMethodTask(this, &WebTestProxyBase::animateNow), 1);
794 }
795}
796
797void WebTestProxyBase::animateNow()
798{
799 if (m_animateScheduled) {
800 m_animateScheduled = false;
801 webWidget()->animate(0.0);
802 }
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000803}
804
805void WebTestProxyBase::show(WebNavigationPolicy)
806{
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100807 invalidateAll();
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000808}
809
810void WebTestProxyBase::setWindowRect(const WebRect& rect)
811{
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100812 invalidateAll();
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000813 discardBackingStore();
814}
815
816void WebTestProxyBase::didAutoResize(const WebSize&)
817{
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100818 invalidateAll();
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000819}
820
821void WebTestProxyBase::postAccessibilityNotification(const WebKit::WebAccessibilityObject& obj, WebKit::WebAccessibilityNotification notification)
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000822{
823 if (notification == WebKit::WebAccessibilityNotificationFocusedUIElementChanged)
824 m_testInterfaces->accessibilityController()->setFocusedElement(obj);
825
826 const char* notificationName;
827 switch (notification) {
828 case WebKit::WebAccessibilityNotificationActiveDescendantChanged:
829 notificationName = "ActiveDescendantChanged";
830 break;
831 case WebKit::WebAccessibilityNotificationAutocorrectionOccured:
832 notificationName = "AutocorrectionOccured";
833 break;
834 case WebKit::WebAccessibilityNotificationCheckedStateChanged:
835 notificationName = "CheckedStateChanged";
836 break;
837 case WebKit::WebAccessibilityNotificationChildrenChanged:
838 notificationName = "ChildrenChanged";
839 break;
840 case WebKit::WebAccessibilityNotificationFocusedUIElementChanged:
841 notificationName = "FocusedUIElementChanged";
842 break;
843 case WebKit::WebAccessibilityNotificationLayoutComplete:
844 notificationName = "LayoutComplete";
845 break;
846 case WebKit::WebAccessibilityNotificationLoadComplete:
847 notificationName = "LoadComplete";
848 break;
849 case WebKit::WebAccessibilityNotificationSelectedChildrenChanged:
850 notificationName = "SelectedChildrenChanged";
851 break;
852 case WebKit::WebAccessibilityNotificationSelectedTextChanged:
853 notificationName = "SelectedTextChanged";
854 break;
855 case WebKit::WebAccessibilityNotificationValueChanged:
856 notificationName = "ValueChanged";
857 break;
858 case WebKit::WebAccessibilityNotificationScrolledToAnchor:
859 notificationName = "ScrolledToAnchor";
860 break;
861 case WebKit::WebAccessibilityNotificationLiveRegionChanged:
862 notificationName = "LiveRegionChanged";
863 break;
864 case WebKit::WebAccessibilityNotificationMenuListItemSelected:
865 notificationName = "MenuListItemSelected";
866 break;
867 case WebKit::WebAccessibilityNotificationMenuListValueChanged:
868 notificationName = "MenuListValueChanged";
869 break;
870 case WebKit::WebAccessibilityNotificationRowCountChanged:
871 notificationName = "RowCountChanged";
872 break;
873 case WebKit::WebAccessibilityNotificationRowCollapsed:
874 notificationName = "RowCollapsed";
875 break;
876 case WebKit::WebAccessibilityNotificationRowExpanded:
877 notificationName = "RowExpanded";
878 break;
879 case WebKit::WebAccessibilityNotificationInvalidStatusChanged:
880 notificationName = "InvalidStatusChanged";
881 break;
882 case WebKit::WebAccessibilityNotificationTextChanged:
883 notificationName = "TextChanged";
884 break;
885 case WebKit::WebAccessibilityNotificationAriaAttributeChanged:
886 notificationName = "AriaAttributeChanged";
887 break;
888 default:
889 notificationName = "UnknownNotification";
890 break;
891 }
892
893 m_testInterfaces->accessibilityController()->notificationReceived(obj, notificationName);
894
895 if (m_testInterfaces->accessibilityController()->shouldLogAccessibilityEvents()) {
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000896 string message("AccessibilityNotification - ");
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +0000897 message += notificationName;
898
899 WebKit::WebNode node = obj.node();
900 if (!node.isNull() && node.isElementNode()) {
901 WebKit::WebElement element = node.to<WebKit::WebElement>();
902 if (element.hasAttribute("id")) {
903 message += " - id:";
904 message += element.getAttribute("id").utf8().data();
905 }
906 }
907
908 m_delegate->printMessage(message + "\n");
909 }
910}
911
Torne (Richard Coles)926b0012013-03-28 15:32:48 +0000912void WebTestProxyBase::startDragging(WebFrame*, const WebDragData& data, WebDragOperationsMask mask, const WebImage&, const WebPoint&)
913{
914 // When running a test, we need to fake a drag drop operation otherwise
915 // Windows waits for real mouse events to know when the drag is over.
916 m_testInterfaces->eventSender()->doDragDrop(data, mask);
917}
918
919// The output from these methods in layout test mode should match that
920// expected by the layout tests. See EditingDelegate.m in DumpRenderTree.
921
922bool WebTestProxyBase::shouldBeginEditing(const WebRange& range)
923{
924 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks()) {
925 m_delegate->printMessage("EDITING DELEGATE: shouldBeginEditingInDOMRange:");
926 printRangeDescription(m_delegate, range);
927 m_delegate->printMessage("\n");
928 }
929 return true;
930}
931
932bool WebTestProxyBase::shouldEndEditing(const WebRange& range)
933{
934 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks()) {
935 m_delegate->printMessage("EDITING DELEGATE: shouldEndEditingInDOMRange:");
936 printRangeDescription(m_delegate, range);
937 m_delegate->printMessage("\n");
938 }
939 return true;
940}
941
942bool WebTestProxyBase::shouldInsertNode(const WebNode& node, const WebRange& range, WebEditingAction action)
943{
944 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks()) {
945 m_delegate->printMessage("EDITING DELEGATE: shouldInsertNode:");
946 printNodeDescription(m_delegate, node, 0);
947 m_delegate->printMessage(" replacingDOMRange:");
948 printRangeDescription(m_delegate, range);
949 m_delegate->printMessage(string(" givenAction:") + editingActionDescription(action) + "\n");
950 }
951 return true;
952}
953
954bool WebTestProxyBase::shouldInsertText(const WebString& text, const WebRange& range, WebEditingAction action)
955{
956 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks()) {
957 m_delegate->printMessage(string("EDITING DELEGATE: shouldInsertText:") + text.utf8().data() + " replacingDOMRange:");
958 printRangeDescription(m_delegate, range);
959 m_delegate->printMessage(string(" givenAction:") + editingActionDescription(action) + "\n");
960 }
961 return true;
962}
963
964bool WebTestProxyBase::shouldChangeSelectedRange(
965 const WebRange& fromRange, const WebRange& toRange, WebTextAffinity affinity, bool stillSelecting)
966{
967 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks()) {
968 m_delegate->printMessage("EDITING DELEGATE: shouldChangeSelectedDOMRange:");
969 printRangeDescription(m_delegate, fromRange);
970 m_delegate->printMessage(" toDOMRange:");
971 printRangeDescription(m_delegate, toRange);
972 m_delegate->printMessage(string(" affinity:") + textAffinityDescription(affinity) + " stillSelecting:" + (stillSelecting ? "TRUE" : "FALSE") + "\n");
973 }
974 return true;
975}
976
977bool WebTestProxyBase::shouldDeleteRange(const WebRange& range)
978{
979 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks()) {
980 m_delegate->printMessage("EDITING DELEGATE: shouldDeleteDOMRange:");
981 printRangeDescription(m_delegate, range);
982 m_delegate->printMessage("\n");
983 }
984 return true;
985}
986
987bool WebTestProxyBase::shouldApplyStyle(const WebString& style, const WebRange& range)
988{
989 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks()) {
990 m_delegate->printMessage(string("EDITING DELEGATE: shouldApplyStyle:") + style.utf8().data() + " toElementsInDOMRange:");
991 printRangeDescription(m_delegate, range);
992 m_delegate->printMessage("\n");
993 }
994 return true;
995}
996
997void WebTestProxyBase::didBeginEditing()
998{
999 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks())
1000 m_delegate->printMessage("EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification\n");
1001}
1002
1003void WebTestProxyBase::didChangeSelection(bool isEmptySelection)
1004{
1005 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks())
1006 m_delegate->printMessage("EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification\n");
1007}
1008
1009void WebTestProxyBase::didChangeContents()
1010{
1011 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks())
1012 m_delegate->printMessage("EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification\n");
1013}
1014
1015void WebTestProxyBase::didEndEditing()
1016{
1017 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks())
1018 m_delegate->printMessage("EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification\n");
1019}
1020
1021bool WebTestProxyBase::createView(WebFrame*, const WebURLRequest& request, const WebWindowFeatures&, const WebString&, WebNavigationPolicy)
1022{
1023 if (!m_testInterfaces->testRunner()->canOpenWindows())
1024 return false;
1025 if (m_testInterfaces->testRunner()->shouldDumpCreateView())
1026 m_delegate->printMessage(string("createView(") + URLDescription(request.url()) + ")\n");
1027 return true;
1028}
1029
1030WebPlugin* WebTestProxyBase::createPlugin(WebFrame* frame, const WebPluginParams& params)
1031{
1032 if (params.mimeType == TestPlugin::mimeType())
1033 return TestPlugin::create(frame, params, m_delegate);
1034 return 0;
1035}
1036
1037void WebTestProxyBase::setStatusText(const WebString& text)
1038{
1039 if (!m_testInterfaces->testRunner()->shouldDumpStatusCallbacks())
1040 return;
1041 m_delegate->printMessage(string("UI DELEGATE STATUS CALLBACK: setStatusText:") + text.utf8().data() + "\n");
1042}
1043
1044void WebTestProxyBase::didStopLoading()
1045{
1046 if (m_testInterfaces->testRunner()->shouldDumpProgressFinishedCallback())
1047 m_delegate->printMessage("postProgressFinishedNotification\n");
1048}
1049
1050void WebTestProxyBase::showContextMenu(WebFrame*, const WebContextMenuData& contextMenuData)
1051{
1052 m_testInterfaces->eventSender()->setContextMenuData(contextMenuData);
1053}
1054
1055WebUserMediaClient* WebTestProxyBase::userMediaClient()
1056{
Torne (Richard Coles)926b0012013-03-28 15:32:48 +00001057 if (!m_userMediaClient.get())
1058 m_userMediaClient.reset(new WebUserMediaClientMock(m_delegate));
1059 return m_userMediaClient.get();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001060}
1061
Torne (Richard Coles)926b0012013-03-28 15:32:48 +00001062// Simulate a print by going into print mode and then exit straight away.
1063void WebTestProxyBase::printPage(WebFrame* frame)
1064{
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001065 WebSize pageSizeInPixels = webWidget()->size();
Torne (Richard Coles)926b0012013-03-28 15:32:48 +00001066 WebPrintParams printParams(pageSizeInPixels);
1067 frame->printBegin(printParams);
1068 frame->printEnd();
1069}
1070
1071WebNotificationPresenter* WebTestProxyBase::notificationPresenter()
1072{
1073#if ENABLE_NOTIFICATIONS
1074 return m_testInterfaces->testRunner()->notificationPresenter();
1075#else
1076 return 0;
1077#endif
1078}
1079
1080WebGeolocationClient* WebTestProxyBase::geolocationClient()
1081{
1082 return geolocationClientMock();
1083}
1084
1085WebSpeechInputController* WebTestProxyBase::speechInputController(WebSpeechInputListener* listener)
1086{
1087#if ENABLE_INPUT_SPEECH
1088 if (!m_speechInputController.get()) {
1089 m_speechInputController.reset(new MockWebSpeechInputController(listener));
1090 m_speechInputController->setDelegate(m_delegate);
1091 }
1092 return m_speechInputController.get();
1093#else
1094 WEBKIT_ASSERT(listener);
1095 return 0;
1096#endif
1097}
1098
1099WebSpeechRecognizer* WebTestProxyBase::speechRecognizer()
1100{
1101 return speechRecognizerMock();
1102}
1103
1104WebDeviceOrientationClient* WebTestProxyBase::deviceOrientationClient()
1105{
1106 return deviceOrientationClientMock();
1107}
1108
1109bool WebTestProxyBase::requestPointerLock()
1110{
1111 return m_testInterfaces->testRunner()->requestPointerLock();
1112}
1113
1114void WebTestProxyBase::requestPointerUnlock()
1115{
1116 m_testInterfaces->testRunner()->requestPointerUnlock();
1117}
1118
1119bool WebTestProxyBase::isPointerLocked()
1120{
1121 return m_testInterfaces->testRunner()->isPointerLocked();
1122}
1123
1124void WebTestProxyBase::didFocus()
1125{
1126 m_delegate->setFocus(this, true);
1127}
1128
1129void WebTestProxyBase::didBlur()
1130{
1131 m_delegate->setFocus(this, false);
1132}
1133
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001134void WebTestProxyBase::setToolTipText(const WebString& text, WebTextDirection)
1135{
1136 m_testInterfaces->testRunner()->setToolTipText(text);
1137}
1138
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01001139void WebTestProxyBase::didOpenChooser()
1140{
1141 m_chooserCount++;
1142}
1143
1144void WebTestProxyBase::didCloseChooser()
1145{
1146 m_chooserCount--;
1147}
1148
1149bool WebTestProxyBase::isChooserShown()
1150{
1151 return 0 < m_chooserCount;
1152}
1153
Torne (Richard Coles)926b0012013-03-28 15:32:48 +00001154void WebTestProxyBase::didStartProvisionalLoad(WebFrame* frame)
1155{
1156 if (!m_testInterfaces->testRunner()->topLoadingFrame())
1157 m_testInterfaces->testRunner()->setTopLoadingFrame(frame, false);
1158
1159 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
1160 printFrameDescription(m_delegate, frame);
1161 m_delegate->printMessage(" - didStartProvisionalLoadForFrame\n");
1162 }
1163
1164 if (m_testInterfaces->testRunner()->shouldDumpUserGestureInFrameLoadCallbacks())
1165 printFrameUserGestureStatus(m_delegate, frame, " - in didStartProvisionalLoadForFrame\n");
Torne (Richard Coles)926b0012013-03-28 15:32:48 +00001166}
1167
1168void WebTestProxyBase::didReceiveServerRedirectForProvisionalLoad(WebFrame* frame)
1169{
1170 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
1171 printFrameDescription(m_delegate, frame);
1172 m_delegate->printMessage(" - didReceiveServerRedirectForProvisionalLoadForFrame\n");
1173 }
1174}
1175
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001176bool WebTestProxyBase::didFailProvisionalLoad(WebFrame* frame, const WebURLError&)
Torne (Richard Coles)926b0012013-03-28 15:32:48 +00001177{
1178 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
1179 printFrameDescription(m_delegate, frame);
1180 m_delegate->printMessage(" - didFailProvisionalLoadWithError\n");
1181 }
1182 locationChangeDone(frame);
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001183 return !frame->provisionalDataSource();
Torne (Richard Coles)926b0012013-03-28 15:32:48 +00001184}
1185
1186void WebTestProxyBase::didCommitProvisionalLoad(WebFrame* frame, bool)
1187{
1188 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
1189 printFrameDescription(m_delegate, frame);
1190 m_delegate->printMessage(" - didCommitLoadForFrame\n");
1191 }
1192}
1193
1194void WebTestProxyBase::didReceiveTitle(WebFrame* frame, const WebString& title, WebTextDirection direction)
1195{
1196 WebCString title8 = title.utf8();
1197
1198 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
1199 printFrameDescription(m_delegate, frame);
1200 m_delegate->printMessage(string(" - didReceiveTitle: ") + title8.data() + "\n");
1201 }
1202
1203 if (m_testInterfaces->testRunner()->shouldDumpTitleChanges())
1204 m_delegate->printMessage(string("TITLE CHANGED: '") + title8.data() + "'\n");
1205
1206 m_testInterfaces->testRunner()->setTitleTextDirection(direction);
1207}
1208
1209void WebTestProxyBase::didChangeIcon(WebFrame* frame, WebIconURL::Type)
1210{
1211 if (m_testInterfaces->testRunner()->shouldDumpIconChanges()) {
1212 printFrameDescription(m_delegate, frame);
1213 m_delegate->printMessage(string(" - didChangeIcons\n"));
1214 }
1215}
1216
1217void WebTestProxyBase::didFinishDocumentLoad(WebFrame* frame)
1218{
1219 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
1220 printFrameDescription(m_delegate, frame);
1221 m_delegate->printMessage(" - didFinishDocumentLoadForFrame\n");
1222 } else {
1223 unsigned pendingUnloadEvents = frame->unloadListenerCount();
1224 if (pendingUnloadEvents) {
1225 printFrameDescription(m_delegate, frame);
1226 char buffer[100];
1227 snprintf(buffer, sizeof(buffer), " - has %u onunload handler(s)\n", pendingUnloadEvents);
1228 m_delegate->printMessage(buffer);
1229 }
1230 }
1231}
1232
1233void WebTestProxyBase::didHandleOnloadEvents(WebFrame* frame)
1234{
1235 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
1236 printFrameDescription(m_delegate, frame);
1237 m_delegate->printMessage(" - didHandleOnloadEventsForFrame\n");
1238 }
1239}
1240
1241void WebTestProxyBase::didFailLoad(WebFrame* frame, const WebURLError&)
1242{
1243 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
1244 printFrameDescription(m_delegate, frame);
1245 m_delegate->printMessage(" - didFailLoadWithError\n");
1246 }
1247 locationChangeDone(frame);
1248}
1249
1250void WebTestProxyBase::didFinishLoad(WebFrame* frame)
1251{
1252 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
1253 printFrameDescription(m_delegate, frame);
1254 m_delegate->printMessage(" - didFinishLoadForFrame\n");
1255 }
1256 locationChangeDone(frame);
1257}
1258
1259void WebTestProxyBase::didChangeLocationWithinPage(WebFrame* frame)
1260{
1261 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
1262 printFrameDescription(m_delegate, frame);
1263 m_delegate->printMessage(" - didChangeLocationWithinPageForFrame\n");
1264 }
1265}
1266
1267void WebTestProxyBase::didDisplayInsecureContent(WebFrame*)
1268{
1269 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks())
1270 m_delegate->printMessage("didDisplayInsecureContent\n");
1271}
1272
1273void WebTestProxyBase::didRunInsecureContent(WebFrame*, const WebSecurityOrigin&, const WebURL&)
1274{
1275 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks())
1276 m_delegate->printMessage("didRunInsecureContent\n");
1277}
1278
1279void WebTestProxyBase::didDetectXSS(WebFrame*, const WebURL&, bool)
1280{
1281 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks())
1282 m_delegate->printMessage("didDetectXSS\n");
1283}
1284
Torne (Richard Coles)926b0012013-03-28 15:32:48 +00001285void WebTestProxyBase::willRequestResource(WebFrame* frame, const WebKit::WebCachedURLRequest& request)
1286{
1287 if (m_testInterfaces->testRunner()->shouldDumpResourceRequestCallbacks()) {
1288 printFrameDescription(m_delegate, frame);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01001289 m_delegate->printMessage(string(" - ") + request.initiatorName().utf8().data());
Torne (Richard Coles)926b0012013-03-28 15:32:48 +00001290 m_delegate->printMessage(string(" requested '") + URLDescription(request.urlRequest().url()).c_str() + "'\n");
1291 }
1292}
1293
Torne (Richard Coles)926b0012013-03-28 15:32:48 +00001294WebURLError WebTestProxyBase::cannotHandleRequestError(WebFrame*, const WebURLRequest& request)
1295{
1296 WebURLError error;
1297 // A WebKit layout test expects the following values.
1298 // unableToImplementPolicyWithError() below prints them.
1299 error.domain = WebString::fromUTF8("WebKitErrorDomain");
1300 error.reason = 101;
1301 error.unreachableURL = request.url();
1302 return error;
1303}
1304
1305void WebTestProxyBase::didCreateDataSource(WebFrame*, WebDataSource* ds)
1306{
1307 if (!m_testInterfaces->testRunner()->deferMainResourceDataLoad())
1308 ds->setDeferMainResourceDataLoad(false);
1309}
1310
1311void WebTestProxyBase::willSendRequest(WebFrame*, unsigned identifier, WebKit::WebURLRequest& request, const WebKit::WebURLResponse& redirectResponse)
1312{
1313 // Need to use GURL for host() and SchemeIs()
1314 GURL url = request.url();
1315 string requestURL = url.possibly_invalid_spec();
1316
1317 GURL mainDocumentURL = request.firstPartyForCookies();
1318
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001319 if (redirectResponse.isNull() && (m_testInterfaces->testRunner()->shouldDumpResourceLoadCallbacks() || m_testInterfaces->testRunner()->shouldDumpResourcePriorities())) {
1320 WEBKIT_ASSERT(m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end());
1321 m_resourceIdentifierMap[identifier] = descriptionSuitableForTestResult(requestURL);
1322 }
1323
Torne (Richard Coles)926b0012013-03-28 15:32:48 +00001324 if (m_testInterfaces->testRunner()->shouldDumpResourceLoadCallbacks()) {
1325 if (m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end())
1326 m_delegate->printMessage("<unknown>");
1327 else
1328 m_delegate->printMessage(m_resourceIdentifierMap[identifier]);
1329 m_delegate->printMessage(" - willSendRequest <NSURLRequest URL ");
1330 m_delegate->printMessage(descriptionSuitableForTestResult(requestURL).c_str());
1331 m_delegate->printMessage(", main document URL ");
1332 m_delegate->printMessage(URLDescription(mainDocumentURL).c_str());
1333 m_delegate->printMessage(", http method ");
1334 m_delegate->printMessage(request.httpMethod().utf8().data());
1335 m_delegate->printMessage("> redirectResponse ");
1336 printResponseDescription(m_delegate, redirectResponse);
1337 m_delegate->printMessage("\n");
1338 }
1339
1340 if (m_testInterfaces->testRunner()->shouldDumpResourcePriorities()) {
1341 m_delegate->printMessage(descriptionSuitableForTestResult(requestURL).c_str());
1342 m_delegate->printMessage(" has priority ");
1343 m_delegate->printMessage(PriorityDescription(request.priority()));
1344 m_delegate->printMessage("\n");
1345 }
1346
1347 if (!redirectResponse.isNull() && m_testInterfaces->testRunner()->shouldBlockRedirects()) {
1348 m_delegate->printMessage("Returning null for this redirect\n");
1349 blockRequest(request);
1350 return;
1351 }
1352
1353 if (m_testInterfaces->testRunner()->willSendRequestShouldReturnNull()) {
1354 blockRequest(request);
1355 return;
1356 }
1357
1358 if (m_testInterfaces->testRunner()->httpHeadersToClear()) {
1359 const set<string> *clearHeaders = m_testInterfaces->testRunner()->httpHeadersToClear();
1360 for (set<string>::const_iterator header = clearHeaders->begin(); header != clearHeaders->end(); ++header)
1361 request.clearHTTPHeaderField(WebString::fromUTF8(*header));
1362 }
1363
1364 string host = url.host();
1365 if (!host.empty() && (url.SchemeIs("http") || url.SchemeIs("https"))) {
1366 if (!isLocalhost(host) && !hostIsUsedBySomeTestsToGenerateError(host)
1367 && ((!mainDocumentURL.SchemeIs("http") && !mainDocumentURL.SchemeIs("https")) || isLocalhost(mainDocumentURL.host()))
1368 && !m_delegate->allowExternalPages()) {
1369 m_delegate->printMessage(string("Blocked access to external URL ") + requestURL + "\n");
1370 blockRequest(request);
1371 return;
1372 }
1373 }
1374
1375 // Set the new substituted URL.
1376 request.setURL(m_delegate->rewriteLayoutTestsURL(request.url().spec()));
1377}
1378
1379void WebTestProxyBase::didReceiveResponse(WebFrame*, unsigned identifier, const WebKit::WebURLResponse& response)
1380{
1381 if (m_testInterfaces->testRunner()->shouldDumpResourceLoadCallbacks()) {
1382 if (m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end())
1383 m_delegate->printMessage("<unknown>");
1384 else
1385 m_delegate->printMessage(m_resourceIdentifierMap[identifier]);
1386 m_delegate->printMessage(" - didReceiveResponse ");
1387 printResponseDescription(m_delegate, response);
1388 m_delegate->printMessage("\n");
1389 }
1390 if (m_testInterfaces->testRunner()->shouldDumpResourceResponseMIMETypes()) {
1391 GURL url = response.url();
1392 WebString mimeType = response.mimeType();
1393 m_delegate->printMessage(url.ExtractFileName());
1394 m_delegate->printMessage(" has MIME type ");
1395 // Simulate NSURLResponse's mapping of empty/unknown MIME types to application/octet-stream
1396 m_delegate->printMessage(mimeType.isEmpty() ? "application/octet-stream" : mimeType.utf8().data());
1397 m_delegate->printMessage("\n");
1398 }
1399}
1400
1401void WebTestProxyBase::didChangeResourcePriority(WebFrame*, unsigned identifier, const WebKit::WebURLRequest::Priority& priority)
1402{
1403 if (m_testInterfaces->testRunner()->shouldDumpResourcePriorities()) {
1404 if (m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end())
1405 m_delegate->printMessage("<unknown>");
1406 else
1407 m_delegate->printMessage(m_resourceIdentifierMap[identifier]);
1408 m_delegate->printMessage(" changed priority to ");
1409 m_delegate->printMessage(PriorityDescription(priority));
1410 m_delegate->printMessage("\n");
1411 }
1412}
1413
1414void WebTestProxyBase::didFinishResourceLoad(WebFrame*, unsigned identifier)
1415{
1416 if (m_testInterfaces->testRunner()->shouldDumpResourceLoadCallbacks()) {
1417 if (m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end())
1418 m_delegate->printMessage("<unknown>");
1419 else
1420 m_delegate->printMessage(m_resourceIdentifierMap[identifier]);
1421 m_delegate->printMessage(" - didFinishLoading\n");
1422 }
1423 m_resourceIdentifierMap.erase(identifier);
1424}
1425
1426void WebTestProxyBase::didFailResourceLoad(WebFrame*, unsigned identifier, const WebKit::WebURLError& error)
1427{
1428 if (m_testInterfaces->testRunner()->shouldDumpResourceLoadCallbacks()) {
1429 if (m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end())
1430 m_delegate->printMessage("<unknown>");
1431 else
1432 m_delegate->printMessage(m_resourceIdentifierMap[identifier]);
1433 m_delegate->printMessage(" - didFailLoadingWithError: ");
1434 m_delegate->printMessage(m_delegate->makeURLErrorDescription(error));
1435 m_delegate->printMessage("\n");
1436 }
1437 m_resourceIdentifierMap.erase(identifier);
1438}
1439
1440void WebTestProxyBase::unableToImplementPolicyWithError(WebKit::WebFrame* frame, const WebKit::WebURLError& error)
1441{
1442 char errorBuffer[40];
1443 snprintf(errorBuffer, sizeof(errorBuffer), "%d", error.reason);
1444 m_delegate->printMessage(string("Policy delegate: unable to implement policy with error domain '") + error.domain.utf8().data() +
1445 "', error code " + errorBuffer +
1446 ", in frame '" + frame->uniqueName().utf8().data() + "'\n");
1447}
1448
1449void WebTestProxyBase::didAddMessageToConsole(const WebConsoleMessage& message, const WebString& sourceName, unsigned sourceLine)
1450{
1451 // This matches win DumpRenderTree's UIDelegate.cpp.
1452 if (!m_logConsoleOutput)
1453 return;
1454 m_delegate->printMessage(string("CONSOLE MESSAGE: "));
1455 if (sourceLine) {
1456 char buffer[40];
1457 snprintf(buffer, sizeof(buffer), "line %d: ", sourceLine);
1458 m_delegate->printMessage(buffer);
1459 }
1460 if (!message.text.isEmpty()) {
1461 string newMessage;
1462 newMessage = message.text.utf8();
1463 size_t fileProtocol = newMessage.find("file://");
1464 if (fileProtocol != string::npos) {
1465 newMessage = newMessage.substr(0, fileProtocol)
1466 + urlSuitableForTestResult(newMessage.substr(fileProtocol));
1467 }
1468 m_delegate->printMessage(newMessage);
1469 }
1470 m_delegate->printMessage(string("\n"));
1471}
1472
1473void WebTestProxyBase::runModalAlertDialog(WebFrame*, const WebString& message)
1474{
1475 m_delegate->printMessage(string("ALERT: ") + message.utf8().data() + "\n");
1476}
1477
1478bool WebTestProxyBase::runModalConfirmDialog(WebFrame*, const WebString& message)
1479{
1480 m_delegate->printMessage(string("CONFIRM: ") + message.utf8().data() + "\n");
1481 return true;
1482}
1483
1484bool WebTestProxyBase::runModalPromptDialog(WebFrame* frame, const WebString& message, const WebString& defaultValue, WebString*)
1485{
1486 m_delegate->printMessage(string("PROMPT: ") + message.utf8().data() + ", default text: " + defaultValue.utf8().data() + "\n");
1487 return true;
1488}
1489
1490bool WebTestProxyBase::runModalBeforeUnloadDialog(WebFrame*, const WebString& message)
1491{
1492 m_delegate->printMessage(string("CONFIRM NAVIGATION: ") + message.utf8().data() + "\n");
1493 return !m_testInterfaces->testRunner()->shouldStayOnPageAfterHandlingBeforeUnload();
1494}
1495
1496void WebTestProxyBase::locationChangeDone(WebFrame* frame)
1497{
1498 if (frame != m_testInterfaces->testRunner()->topLoadingFrame())
1499 return;
1500 m_testInterfaces->testRunner()->setTopLoadingFrame(frame, true);
1501}
1502
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001503WebNavigationPolicy WebTestProxyBase::decidePolicyForNavigation(WebFrame*, const WebURLRequest& request, WebNavigationType type, WebNavigationPolicy defaultPolicy, bool isRedirect)
Torne (Richard Coles)926b0012013-03-28 15:32:48 +00001504{
1505 WebNavigationPolicy result;
1506 if (!m_testInterfaces->testRunner()->policyDelegateEnabled())
1507 return defaultPolicy;
1508
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001509 m_delegate->printMessage(string("Policy delegate: attempt to load ") + URLDescription(request.url()) + " with navigation type '" + webNavigationTypeToString(type) + "'\n");
Torne (Richard Coles)926b0012013-03-28 15:32:48 +00001510 if (m_testInterfaces->testRunner()->policyDelegateIsPermissive())
1511 result = WebKit::WebNavigationPolicyCurrentTab;
1512 else
1513 result = WebKit::WebNavigationPolicyIgnore;
1514
1515 if (m_testInterfaces->testRunner()->policyDelegateShouldNotifyDone())
1516 m_testInterfaces->testRunner()->policyDelegateDone();
1517 return result;
1518}
1519
1520bool WebTestProxyBase::willCheckAndDispatchMessageEvent(WebFrame*, WebFrame*, WebSecurityOrigin, WebDOMMessageEvent)
1521{
1522 if (m_testInterfaces->testRunner()->shouldInterceptPostMessage()) {
1523 m_delegate->printMessage("intercepted postMessage\n");
1524 return true;
1525 }
1526
1527 return false;
1528}
1529
Ben Murdoch591b9582013-07-10 11:41:44 +01001530void WebTestProxyBase::resetInputMethod()
1531{
1532 // If a composition text exists, then we need to let the browser process
1533 // to cancel the input method's ongoing composition session.
1534 if (m_webWidget)
1535 m_webWidget->confirmComposition();
1536}
1537
Torne (Richard Coles)5c87bf82012-11-14 11:46:17 +00001538}