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