Home | History | Annotate | Download | only in runner
      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 "public/testing/WebTestProxy.h"
     32 
     33 #include "AccessibilityControllerChromium.h"
     34 #include "EventSender.h"
     35 #include "MockColorChooser.h"
     36 #include "MockWebSpeechInputController.h"
     37 #include "MockWebSpeechRecognizer.h"
     38 #include "MockWebValidationMessageClient.h"
     39 #include "SpellCheckClient.h"
     40 #include "TestCommon.h"
     41 #include "TestInterfaces.h"
     42 #include "TestPlugin.h"
     43 #include "TestRunner.h"
     44 #include "WebUserMediaClientMock.h"
     45 #include "public/platform/WebCString.h"
     46 #include "public/platform/WebURLError.h"
     47 #include "public/platform/WebURLRequest.h"
     48 #include "public/platform/WebURLResponse.h"
     49 #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"
     74 
     75 using namespace WebKit;
     76 using namespace std;
     77 
     78 namespace WebTestRunner {
     79 
     80 namespace {
     81 
     82 class HostMethodTask : public WebMethodTask<WebTestProxyBase> {
     83 public:
     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 
     92 private:
     93     CallbackMethodType m_callback;
     94 };
     95 
     96 void 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 
    114 void 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 
    132 string 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 
    145 string 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 
    156 void 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 
    174 void 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").
    183 string 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 
    198 void 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 
    210 string URLDescription(const GURL& url)
    211 {
    212     if (url.SchemeIs("file"))
    213         return url.ExtractFileName();
    214     return url.possibly_invalid_spec();
    215 }
    216 
    217 string 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 
    236 void blockRequest(WebURLRequest& request)
    237 {
    238     request.setURL(GURL("255.255.255.255"));
    239 }
    240 
    241 bool isLocalhost(const string& host)
    242 {
    243     return host == "127.0.0.1" || host == "localhost";
    244 }
    245 
    246 bool 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").
    253 string 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.
    275 const char* linkClickedString = "link clicked";
    276 const char* formSubmittedString = "form submitted";
    277 const char* backForwardString = "back/forward";
    278 const char* reloadString = "reload";
    279 const char* formResubmittedString = "form resubmitted";
    280 const char* otherString = "other";
    281 const char* illegalString = "illegal value";
    282 
    283 // Get a debugging string from a WebNavigationType.
    284 const 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 
    303 string 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 
    313 string 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 
    335 string 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 
    361 string 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 
    380 struct ToLower {
    381     char16 operator()(char16 c) { return tolower(c); }
    382 };
    383 
    384 // Returns True if item1 < item2.
    385 bool 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 
    394 string 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 
    431 void 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 
    439 string 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 
    454 WebTestProxyBase::WebTestProxyBase()
    455     : m_testInterfaces(0)
    456     , m_delegate(0)
    457     , m_webWidget(0)
    458     , m_spellcheck(new SpellCheckClient)
    459     , m_chooserCount(0)
    460     , m_validationMessageClient(new MockWebValidationMessageClient())
    461 {
    462     reset();
    463 }
    464 
    465 WebTestProxyBase::~WebTestProxyBase()
    466 {
    467     m_testInterfaces->windowClosed(this);
    468 }
    469 
    470 void WebTestProxyBase::setInterfaces(WebTestInterfaces* interfaces)
    471 {
    472     m_testInterfaces = interfaces->testInterfaces();
    473     m_testInterfaces->windowOpened(this);
    474 }
    475 
    476 void WebTestProxyBase::setDelegate(WebTestDelegate* delegate)
    477 {
    478     m_delegate = delegate;
    479     m_spellcheck->setDelegate(delegate);
    480     m_validationMessageClient->setDelegate(delegate);
    481 #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);
    487 }
    488 
    489 void WebTestProxyBase::setWidget(WebWidget* widget)
    490 {
    491     m_webWidget = widget;
    492 }
    493 
    494 WebWidget* WebTestProxyBase::webWidget()
    495 {
    496     return m_webWidget;
    497 }
    498 
    499 WebView* 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 
    506 void WebTestProxyBase::reset()
    507 {
    508     m_paintRect = WebRect();
    509     m_canvas.reset();
    510     m_isPainting = false;
    511     m_animateScheduled = false;
    512     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 
    522 WebSpellCheckClient* WebTestProxyBase::spellCheckClient() const
    523 {
    524     return m_spellcheck.get();
    525 }
    526 
    527 WebValidationMessageClient* WebTestProxyBase::validationMessageClient()
    528 {
    529     return m_validationMessageClient.get();
    530 }
    531 
    532 WebColorChooser* 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 
    538 string WebTestProxyBase::captureTree(bool debugRenderTree)
    539 {
    540     WebScriptController::flushConsoleMessages();
    541 
    542     bool shouldDumpAsText = m_testInterfaces->testRunner()->shouldDumpAsText();
    543     bool shouldDumpAsPrinted = m_testInterfaces->testRunner()->isPrinting();
    544     WebFrame* frame = webView()->mainFrame();
    545     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 
    566 SkCanvas* WebTestProxyBase::capturePixels()
    567 {
    568     webWidget()->layout();
    569     if (m_testInterfaces->testRunner()->testRepaint()) {
    570         WebSize viewSize = webWidget()->size();
    571         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
    590         WebRect wr = webView()->mainFrame()->selectionBoundsRect();
    591         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 
    607 void WebTestProxyBase::setLogConsoleOutput(bool enabled)
    608 {
    609     m_logConsoleOutput = enabled;
    610 }
    611 
    612 void WebTestProxyBase::paintRect(const WebRect& rect)
    613 {
    614     WEBKIT_ASSERT(!m_isPainting);
    615     WEBKIT_ASSERT(canvas());
    616     m_isPainting = true;
    617     float deviceScaleFactor = webView()->deviceScaleFactor();
    618     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);
    623     webWidget()->paint(canvas(), deviceRect);
    624     m_isPainting = false;
    625 }
    626 
    627 void WebTestProxyBase::paintInvalidatedRegion()
    628 {
    629     webWidget()->animate(0.0);
    630     webWidget()->layout();
    631     WebSize widgetSize = webWidget()->size();
    632     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 
    658 void WebTestProxyBase::paintPagesWithBoundaries()
    659 {
    660     WEBKIT_ASSERT(!m_isPainting);
    661     WEBKIT_ASSERT(canvas());
    662     m_isPainting = true;
    663 
    664     WebSize pageSizeInPixels = webWidget()->size();
    665     WebFrame* webFrame = webView()->mainFrame();
    666 
    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 
    685 SkCanvas* WebTestProxyBase::canvas()
    686 {
    687     if (m_canvas.get())
    688         return m_canvas.get();
    689     WebSize widgetSize = webWidget()->size();
    690     float deviceScaleFactor = webView()->deviceScaleFactor();
    691     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.
    699 void WebTestProxyBase::displayRepaintMask()
    700 {
    701     canvas()->drawARGB(167, 0, 0, 0);
    702 }
    703 
    704 void WebTestProxyBase::display()
    705 {
    706     const WebKit::WebSize& size = webWidget()->size();
    707     WebRect rect(0, 0, size.width, size.height);
    708     m_paintRect = rect;
    709     paintInvalidatedRegion();
    710     displayRepaintMask();
    711 }
    712 
    713 void WebTestProxyBase::displayInvalidatedRegion()
    714 {
    715     paintInvalidatedRegion();
    716     displayRepaintMask();
    717 }
    718 
    719 void WebTestProxyBase::discardBackingStore()
    720 {
    721     m_canvas.reset();
    722 }
    723 
    724 WebGeolocationClientMock* WebTestProxyBase::geolocationClientMock()
    725 {
    726     if (!m_geolocationClient.get())
    727         m_geolocationClient.reset(WebGeolocationClientMock::create());
    728     return m_geolocationClient.get();
    729 }
    730 
    731 WebDeviceOrientationClientMock* 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
    739 MockWebSpeechInputController* WebTestProxyBase::speechInputControllerMock()
    740 {
    741     WEBKIT_ASSERT(m_speechInputController.get());
    742     return m_speechInputController.get();
    743 }
    744 #endif
    745 
    746 MockWebSpeechRecognizer* 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 
    755 void 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 
    771 void WebTestProxyBase::didScrollRect(int, int, const WebRect& clipRect)
    772 {
    773     didInvalidateRect(clipRect);
    774 }
    775 
    776 void WebTestProxyBase::invalidateAll()
    777 {
    778     m_paintRect = WebRect(0, 0, INT_MAX, INT_MAX);
    779 }
    780 
    781 void WebTestProxyBase::scheduleComposite()
    782 {
    783     invalidateAll();
    784 }
    785 
    786 void WebTestProxyBase::scheduleAnimation()
    787 {
    788     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 
    797 void WebTestProxyBase::animateNow()
    798 {
    799     if (m_animateScheduled) {
    800         m_animateScheduled = false;
    801         webWidget()->animate(0.0);
    802     }
    803 }
    804 
    805 void WebTestProxyBase::show(WebNavigationPolicy)
    806 {
    807     invalidateAll();
    808 }
    809 
    810 void WebTestProxyBase::setWindowRect(const WebRect& rect)
    811 {
    812     invalidateAll();
    813     discardBackingStore();
    814 }
    815 
    816 void WebTestProxyBase::didAutoResize(const WebSize&)
    817 {
    818     invalidateAll();
    819 }
    820 
    821 void WebTestProxyBase::postAccessibilityNotification(const WebKit::WebAccessibilityObject& obj, WebKit::WebAccessibilityNotification notification)
    822 {
    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()) {
    896         string message("AccessibilityNotification - ");
    897         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 
    912 void 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 
    922 bool 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 
    932 bool 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 
    942 bool 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 
    954 bool 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 
    964 bool 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 
    977 bool 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 
    987 bool 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 
    997 void WebTestProxyBase::didBeginEditing()
    998 {
    999     if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks())
   1000         m_delegate->printMessage("EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification\n");
   1001 }
   1002 
   1003 void WebTestProxyBase::didChangeSelection(bool isEmptySelection)
   1004 {
   1005     if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks())
   1006         m_delegate->printMessage("EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification\n");
   1007 }
   1008 
   1009 void WebTestProxyBase::didChangeContents()
   1010 {
   1011     if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks())
   1012         m_delegate->printMessage("EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification\n");
   1013 }
   1014 
   1015 void WebTestProxyBase::didEndEditing()
   1016 {
   1017     if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks())
   1018         m_delegate->printMessage("EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification\n");
   1019 }
   1020 
   1021 bool 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 
   1030 WebPlugin* 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 
   1037 void 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 
   1044 void WebTestProxyBase::didStopLoading()
   1045 {
   1046     if (m_testInterfaces->testRunner()->shouldDumpProgressFinishedCallback())
   1047         m_delegate->printMessage("postProgressFinishedNotification\n");
   1048 }
   1049 
   1050 void WebTestProxyBase::showContextMenu(WebFrame*, const WebContextMenuData& contextMenuData)
   1051 {
   1052     m_testInterfaces->eventSender()->setContextMenuData(contextMenuData);
   1053 }
   1054 
   1055 WebUserMediaClient* WebTestProxyBase::userMediaClient()
   1056 {
   1057     if (!m_userMediaClient.get())
   1058         m_userMediaClient.reset(new WebUserMediaClientMock(m_delegate));
   1059     return m_userMediaClient.get();
   1060 }
   1061 
   1062 // Simulate a print by going into print mode and then exit straight away.
   1063 void WebTestProxyBase::printPage(WebFrame* frame)
   1064 {
   1065     WebSize pageSizeInPixels = webWidget()->size();
   1066     if (pageSizeInPixels.isEmpty())
   1067         return;
   1068     WebPrintParams printParams(pageSizeInPixels);
   1069     frame->printBegin(printParams);
   1070     frame->printEnd();
   1071 }
   1072 
   1073 WebNotificationPresenter* WebTestProxyBase::notificationPresenter()
   1074 {
   1075 #if ENABLE_NOTIFICATIONS
   1076     return m_testInterfaces->testRunner()->notificationPresenter();
   1077 #else
   1078     return 0;
   1079 #endif
   1080 }
   1081 
   1082 WebGeolocationClient* WebTestProxyBase::geolocationClient()
   1083 {
   1084     return geolocationClientMock();
   1085 }
   1086 
   1087 WebSpeechInputController* WebTestProxyBase::speechInputController(WebSpeechInputListener* listener)
   1088 {
   1089 #if ENABLE_INPUT_SPEECH
   1090     if (!m_speechInputController.get()) {
   1091         m_speechInputController.reset(new MockWebSpeechInputController(listener));
   1092         m_speechInputController->setDelegate(m_delegate);
   1093     }
   1094     return m_speechInputController.get();
   1095 #else
   1096     WEBKIT_ASSERT(listener);
   1097     return 0;
   1098 #endif
   1099 }
   1100 
   1101 WebSpeechRecognizer* WebTestProxyBase::speechRecognizer()
   1102 {
   1103     return speechRecognizerMock();
   1104 }
   1105 
   1106 WebDeviceOrientationClient* WebTestProxyBase::deviceOrientationClient()
   1107 {
   1108     return deviceOrientationClientMock();
   1109 }
   1110 
   1111 bool WebTestProxyBase::requestPointerLock()
   1112 {
   1113     return m_testInterfaces->testRunner()->requestPointerLock();
   1114 }
   1115 
   1116 void WebTestProxyBase::requestPointerUnlock()
   1117 {
   1118     m_testInterfaces->testRunner()->requestPointerUnlock();
   1119 }
   1120 
   1121 bool WebTestProxyBase::isPointerLocked()
   1122 {
   1123     return m_testInterfaces->testRunner()->isPointerLocked();
   1124 }
   1125 
   1126 void WebTestProxyBase::didFocus()
   1127 {
   1128     m_delegate->setFocus(this, true);
   1129 }
   1130 
   1131 void WebTestProxyBase::didBlur()
   1132 {
   1133     m_delegate->setFocus(this, false);
   1134 }
   1135 
   1136 void WebTestProxyBase::setToolTipText(const WebString& text, WebTextDirection)
   1137 {
   1138     m_testInterfaces->testRunner()->setToolTipText(text);
   1139 }
   1140 
   1141 void WebTestProxyBase::didOpenChooser()
   1142 {
   1143     m_chooserCount++;
   1144 }
   1145 
   1146 void WebTestProxyBase::didCloseChooser()
   1147 {
   1148     m_chooserCount--;
   1149 }
   1150 
   1151 bool WebTestProxyBase::isChooserShown()
   1152 {
   1153     return 0 < m_chooserCount;
   1154 }
   1155 
   1156 void WebTestProxyBase::didStartProvisionalLoad(WebFrame* frame)
   1157 {
   1158     if (!m_testInterfaces->testRunner()->topLoadingFrame())
   1159         m_testInterfaces->testRunner()->setTopLoadingFrame(frame, false);
   1160 
   1161     if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
   1162         printFrameDescription(m_delegate, frame);
   1163         m_delegate->printMessage(" - didStartProvisionalLoadForFrame\n");
   1164     }
   1165 
   1166     if (m_testInterfaces->testRunner()->shouldDumpUserGestureInFrameLoadCallbacks())
   1167         printFrameUserGestureStatus(m_delegate, frame, " - in didStartProvisionalLoadForFrame\n");
   1168 }
   1169 
   1170 void WebTestProxyBase::didReceiveServerRedirectForProvisionalLoad(WebFrame* frame)
   1171 {
   1172     if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
   1173         printFrameDescription(m_delegate, frame);
   1174         m_delegate->printMessage(" - didReceiveServerRedirectForProvisionalLoadForFrame\n");
   1175     }
   1176 }
   1177 
   1178 bool WebTestProxyBase::didFailProvisionalLoad(WebFrame* frame, const WebURLError&)
   1179 {
   1180     if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
   1181         printFrameDescription(m_delegate, frame);
   1182         m_delegate->printMessage(" - didFailProvisionalLoadWithError\n");
   1183     }
   1184     locationChangeDone(frame);
   1185     return !frame->provisionalDataSource();
   1186 }
   1187 
   1188 void WebTestProxyBase::didCommitProvisionalLoad(WebFrame* frame, bool)
   1189 {
   1190     if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
   1191         printFrameDescription(m_delegate, frame);
   1192         m_delegate->printMessage(" - didCommitLoadForFrame\n");
   1193     }
   1194 }
   1195 
   1196 void WebTestProxyBase::didReceiveTitle(WebFrame* frame, const WebString& title, WebTextDirection direction)
   1197 {
   1198     WebCString title8 = title.utf8();
   1199 
   1200     if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
   1201         printFrameDescription(m_delegate, frame);
   1202         m_delegate->printMessage(string(" - didReceiveTitle: ") + title8.data() + "\n");
   1203     }
   1204 
   1205     if (m_testInterfaces->testRunner()->shouldDumpTitleChanges())
   1206         m_delegate->printMessage(string("TITLE CHANGED: '") + title8.data() + "'\n");
   1207 
   1208     m_testInterfaces->testRunner()->setTitleTextDirection(direction);
   1209 }
   1210 
   1211 void WebTestProxyBase::didChangeIcon(WebFrame* frame, WebIconURL::Type)
   1212 {
   1213     if (m_testInterfaces->testRunner()->shouldDumpIconChanges()) {
   1214         printFrameDescription(m_delegate, frame);
   1215         m_delegate->printMessage(string(" - didChangeIcons\n"));
   1216     }
   1217 }
   1218 
   1219 void WebTestProxyBase::didFinishDocumentLoad(WebFrame* frame)
   1220 {
   1221     if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
   1222         printFrameDescription(m_delegate, frame);
   1223         m_delegate->printMessage(" - didFinishDocumentLoadForFrame\n");
   1224     } else {
   1225         unsigned pendingUnloadEvents = frame->unloadListenerCount();
   1226         if (pendingUnloadEvents) {
   1227             printFrameDescription(m_delegate, frame);
   1228             char buffer[100];
   1229             snprintf(buffer, sizeof(buffer), " - has %u onunload handler(s)\n", pendingUnloadEvents);
   1230             m_delegate->printMessage(buffer);
   1231         }
   1232     }
   1233 }
   1234 
   1235 void WebTestProxyBase::didHandleOnloadEvents(WebFrame* frame)
   1236 {
   1237     if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
   1238         printFrameDescription(m_delegate, frame);
   1239         m_delegate->printMessage(" - didHandleOnloadEventsForFrame\n");
   1240     }
   1241 }
   1242 
   1243 void WebTestProxyBase::didFailLoad(WebFrame* frame, const WebURLError&)
   1244 {
   1245     if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
   1246         printFrameDescription(m_delegate, frame);
   1247         m_delegate->printMessage(" - didFailLoadWithError\n");
   1248     }
   1249     locationChangeDone(frame);
   1250 }
   1251 
   1252 void WebTestProxyBase::didFinishLoad(WebFrame* frame)
   1253 {
   1254     if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) {
   1255         printFrameDescription(m_delegate, frame);
   1256         m_delegate->printMessage(" - didFinishLoadForFrame\n");
   1257     }
   1258     locationChangeDone(frame);
   1259 }
   1260 
   1261 void WebTestProxyBase::didDetectXSS(WebFrame*, const WebURL&, bool)
   1262 {
   1263     if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks())
   1264         m_delegate->printMessage("didDetectXSS\n");
   1265 }
   1266 
   1267 void WebTestProxyBase::didDispatchPingLoader(WebFrame*, const WebURL& url)
   1268 {
   1269     if (m_testInterfaces->testRunner()->shouldDumpPingLoaderCallbacks())
   1270         m_delegate->printMessage(string("PingLoader dispatched to '") + URLDescription(url).c_str() + "'.\n");
   1271 }
   1272 
   1273 void WebTestProxyBase::willRequestResource(WebFrame* frame, const WebKit::WebCachedURLRequest& request)
   1274 {
   1275     if (m_testInterfaces->testRunner()->shouldDumpResourceRequestCallbacks()) {
   1276         printFrameDescription(m_delegate, frame);
   1277         m_delegate->printMessage(string(" - ") + request.initiatorName().utf8().data());
   1278         m_delegate->printMessage(string(" requested '") + URLDescription(request.urlRequest().url()).c_str() + "'\n");
   1279     }
   1280 }
   1281 
   1282 void WebTestProxyBase::didCreateDataSource(WebFrame*, WebDataSource* ds)
   1283 {
   1284     if (!m_testInterfaces->testRunner()->deferMainResourceDataLoad())
   1285         ds->setDeferMainResourceDataLoad(false);
   1286 }
   1287 
   1288 void WebTestProxyBase::willSendRequest(WebFrame*, unsigned identifier, WebKit::WebURLRequest& request, const WebKit::WebURLResponse& redirectResponse)
   1289 {
   1290     // Need to use GURL for host() and SchemeIs()
   1291     GURL url = request.url();
   1292     string requestURL = url.possibly_invalid_spec();
   1293 
   1294     GURL mainDocumentURL = request.firstPartyForCookies();
   1295 
   1296     if (redirectResponse.isNull() && (m_testInterfaces->testRunner()->shouldDumpResourceLoadCallbacks() || m_testInterfaces->testRunner()->shouldDumpResourcePriorities())) {
   1297         WEBKIT_ASSERT(m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end());
   1298         m_resourceIdentifierMap[identifier] = descriptionSuitableForTestResult(requestURL);
   1299     }
   1300 
   1301     if (m_testInterfaces->testRunner()->shouldDumpResourceLoadCallbacks()) {
   1302         if (m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end())
   1303             m_delegate->printMessage("<unknown>");
   1304         else
   1305             m_delegate->printMessage(m_resourceIdentifierMap[identifier]);
   1306         m_delegate->printMessage(" - willSendRequest <NSURLRequest URL ");
   1307         m_delegate->printMessage(descriptionSuitableForTestResult(requestURL).c_str());
   1308         m_delegate->printMessage(", main document URL ");
   1309         m_delegate->printMessage(URLDescription(mainDocumentURL).c_str());
   1310         m_delegate->printMessage(", http method ");
   1311         m_delegate->printMessage(request.httpMethod().utf8().data());
   1312         m_delegate->printMessage("> redirectResponse ");
   1313         printResponseDescription(m_delegate, redirectResponse);
   1314         m_delegate->printMessage("\n");
   1315     }
   1316 
   1317     if (m_testInterfaces->testRunner()->shouldDumpResourcePriorities()) {
   1318         m_delegate->printMessage(descriptionSuitableForTestResult(requestURL).c_str());
   1319         m_delegate->printMessage(" has priority ");
   1320         m_delegate->printMessage(PriorityDescription(request.priority()));
   1321         m_delegate->printMessage("\n");
   1322     }
   1323 
   1324     if (m_testInterfaces->testRunner()->httpHeadersToClear()) {
   1325         const set<string> *clearHeaders = m_testInterfaces->testRunner()->httpHeadersToClear();
   1326         for (set<string>::const_iterator header = clearHeaders->begin(); header != clearHeaders->end(); ++header)
   1327             request.clearHTTPHeaderField(WebString::fromUTF8(*header));
   1328     }
   1329 
   1330     string host = url.host();
   1331     if (!host.empty() && (url.SchemeIs("http") || url.SchemeIs("https"))) {
   1332         if (!isLocalhost(host) && !hostIsUsedBySomeTestsToGenerateError(host)
   1333             && ((!mainDocumentURL.SchemeIs("http") && !mainDocumentURL.SchemeIs("https")) || isLocalhost(mainDocumentURL.host()))
   1334             && !m_delegate->allowExternalPages()) {
   1335             m_delegate->printMessage(string("Blocked access to external URL ") + requestURL + "\n");
   1336             blockRequest(request);
   1337             return;
   1338         }
   1339     }
   1340 
   1341     // Set the new substituted URL.
   1342     request.setURL(m_delegate->rewriteLayoutTestsURL(request.url().spec()));
   1343 }
   1344 
   1345 void WebTestProxyBase::didReceiveResponse(WebFrame*, unsigned identifier, const WebKit::WebURLResponse& response)
   1346 {
   1347     if (m_testInterfaces->testRunner()->shouldDumpResourceLoadCallbacks()) {
   1348         if (m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end())
   1349             m_delegate->printMessage("<unknown>");
   1350         else
   1351             m_delegate->printMessage(m_resourceIdentifierMap[identifier]);
   1352         m_delegate->printMessage(" - didReceiveResponse ");
   1353         printResponseDescription(m_delegate, response);
   1354         m_delegate->printMessage("\n");
   1355     }
   1356     if (m_testInterfaces->testRunner()->shouldDumpResourceResponseMIMETypes()) {
   1357         GURL url = response.url();
   1358         WebString mimeType = response.mimeType();
   1359         m_delegate->printMessage(url.ExtractFileName());
   1360         m_delegate->printMessage(" has MIME type ");
   1361         // Simulate NSURLResponse's mapping of empty/unknown MIME types to application/octet-stream
   1362         m_delegate->printMessage(mimeType.isEmpty() ? "application/octet-stream" : mimeType.utf8().data());
   1363         m_delegate->printMessage("\n");
   1364     }
   1365 }
   1366 
   1367 void WebTestProxyBase::didChangeResourcePriority(WebFrame*, unsigned identifier, const WebKit::WebURLRequest::Priority& priority)
   1368 {
   1369     if (m_testInterfaces->testRunner()->shouldDumpResourcePriorities()) {
   1370         if (m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end())
   1371             m_delegate->printMessage("<unknown>");
   1372         else
   1373             m_delegate->printMessage(m_resourceIdentifierMap[identifier]);
   1374         m_delegate->printMessage(" changed priority to ");
   1375         m_delegate->printMessage(PriorityDescription(priority));
   1376         m_delegate->printMessage("\n");
   1377     }
   1378 }
   1379 
   1380 void WebTestProxyBase::didFinishResourceLoad(WebFrame*, unsigned identifier)
   1381 {
   1382     if (m_testInterfaces->testRunner()->shouldDumpResourceLoadCallbacks()) {
   1383         if (m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end())
   1384             m_delegate->printMessage("<unknown>");
   1385         else
   1386             m_delegate->printMessage(m_resourceIdentifierMap[identifier]);
   1387         m_delegate->printMessage(" - didFinishLoading\n");
   1388     }
   1389     m_resourceIdentifierMap.erase(identifier);
   1390 }
   1391 
   1392 void WebTestProxyBase::didAddMessageToConsole(const WebConsoleMessage& message, const WebString& sourceName, unsigned sourceLine)
   1393 {
   1394     // This matches win DumpRenderTree's UIDelegate.cpp.
   1395     if (!m_logConsoleOutput)
   1396         return;
   1397     m_delegate->printMessage(string("CONSOLE MESSAGE: "));
   1398     if (sourceLine) {
   1399         char buffer[40];
   1400         snprintf(buffer, sizeof(buffer), "line %d: ", sourceLine);
   1401         m_delegate->printMessage(buffer);
   1402     }
   1403     if (!message.text.isEmpty()) {
   1404         string newMessage;
   1405         newMessage = message.text.utf8();
   1406         size_t fileProtocol = newMessage.find("file://");
   1407         if (fileProtocol != string::npos) {
   1408             newMessage = newMessage.substr(0, fileProtocol)
   1409                 + urlSuitableForTestResult(newMessage.substr(fileProtocol));
   1410         }
   1411         m_delegate->printMessage(newMessage);
   1412     }
   1413     m_delegate->printMessage(string("\n"));
   1414 }
   1415 
   1416 void WebTestProxyBase::runModalAlertDialog(WebFrame*, const WebString& message)
   1417 {
   1418     m_delegate->printMessage(string("ALERT: ") + message.utf8().data() + "\n");
   1419 }
   1420 
   1421 bool WebTestProxyBase::runModalConfirmDialog(WebFrame*, const WebString& message)
   1422 {
   1423     m_delegate->printMessage(string("CONFIRM: ") + message.utf8().data() + "\n");
   1424     return true;
   1425 }
   1426 
   1427 bool WebTestProxyBase::runModalPromptDialog(WebFrame* frame, const WebString& message, const WebString& defaultValue, WebString*)
   1428 {
   1429     m_delegate->printMessage(string("PROMPT: ") + message.utf8().data() + ", default text: " + defaultValue.utf8().data() + "\n");
   1430     return true;
   1431 }
   1432 
   1433 bool WebTestProxyBase::runModalBeforeUnloadDialog(WebFrame*, const WebString& message)
   1434 {
   1435     m_delegate->printMessage(string("CONFIRM NAVIGATION: ") + message.utf8().data() + "\n");
   1436     return !m_testInterfaces->testRunner()->shouldStayOnPageAfterHandlingBeforeUnload();
   1437 }
   1438 
   1439 void WebTestProxyBase::locationChangeDone(WebFrame* frame)
   1440 {
   1441     if (frame != m_testInterfaces->testRunner()->topLoadingFrame())
   1442         return;
   1443     m_testInterfaces->testRunner()->setTopLoadingFrame(frame, true);
   1444 }
   1445 
   1446 WebNavigationPolicy WebTestProxyBase::decidePolicyForNavigation(WebFrame*, WebDataSource::ExtraData*, const WebURLRequest& request, WebNavigationType type, WebNavigationPolicy defaultPolicy, bool isRedirect)
   1447 {
   1448     WebNavigationPolicy result;
   1449     if (!m_testInterfaces->testRunner()->policyDelegateEnabled())
   1450         return defaultPolicy;
   1451 
   1452     m_delegate->printMessage(string("Policy delegate: attempt to load ") + URLDescription(request.url()) + " with navigation type '" + webNavigationTypeToString(type) + "'\n");
   1453     if (m_testInterfaces->testRunner()->policyDelegateIsPermissive())
   1454         result = WebKit::WebNavigationPolicyCurrentTab;
   1455     else
   1456         result = WebKit::WebNavigationPolicyIgnore;
   1457 
   1458     if (m_testInterfaces->testRunner()->policyDelegateShouldNotifyDone())
   1459         m_testInterfaces->testRunner()->policyDelegateDone();
   1460     return result;
   1461 }
   1462 
   1463 bool WebTestProxyBase::willCheckAndDispatchMessageEvent(WebFrame*, WebFrame*, WebSecurityOrigin, WebDOMMessageEvent)
   1464 {
   1465     if (m_testInterfaces->testRunner()->shouldInterceptPostMessage()) {
   1466         m_delegate->printMessage("intercepted postMessage\n");
   1467         return true;
   1468     }
   1469 
   1470     return false;
   1471 }
   1472 
   1473 void WebTestProxyBase::resetInputMethod()
   1474 {
   1475     // If a composition text exists, then we need to let the browser process
   1476     // to cancel the input method's ongoing composition session.
   1477     if (m_webWidget)
   1478         m_webWidget->confirmComposition();
   1479 }
   1480 
   1481 }
   1482