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