Home | History | Annotate | Download | only in chromium
      1 /*
      2  * Copyright (C) 2010 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "WebViewHost.h"
     33 
     34 #include "LayoutTestController.h"
     35 #include "TestNavigationController.h"
     36 #include "TestShell.h"
     37 #include "TestWebWorker.h"
     38 #include "WebCString.h"
     39 #include "WebConsoleMessage.h"
     40 #include "WebContextMenuData.h"
     41 #include "WebDataSource.h"
     42 #include "WebDeviceOrientationClientMock.h"
     43 #include "WebDragData.h"
     44 #include "WebElement.h"
     45 #include "WebFrame.h"
     46 #include "WebGeolocationClientMock.h"
     47 #include "WebHistoryItem.h"
     48 #include "WebNode.h"
     49 #include "WebRange.h"
     50 #include "WebRect.h"
     51 #include "WebScreenInfo.h"
     52 #include "WebSize.h"
     53 #include "WebSpeechInputControllerMock.h"
     54 #include "WebStorageNamespace.h"
     55 #include "WebTextCheckingCompletion.h"
     56 #include "WebTextCheckingResult.h"
     57 #include "WebURLRequest.h"
     58 #include "WebURLResponse.h"
     59 #include "WebView.h"
     60 #include "WebWindowFeatures.h"
     61 #include "skia/ext/platform_canvas.h"
     62 #include "webkit/support/webkit_support.h"
     63 #include <wtf/Assertions.h>
     64 #include <wtf/PassOwnPtr.h>
     65 #include <wtf/Vector.h>
     66 
     67 using namespace WebCore;
     68 using namespace WebKit;
     69 using namespace std;
     70 
     71 static const int screenWidth = 1920;
     72 static const int screenHeight = 1080;
     73 static const int screenUnavailableBorder = 8;
     74 
     75 // WebNavigationType debugging strings taken from PolicyDelegate.mm.
     76 static const char* linkClickedString = "link clicked";
     77 static const char* formSubmittedString = "form submitted";
     78 static const char* backForwardString = "back/forward";
     79 static const char* reloadString = "reload";
     80 static const char* formResubmittedString = "form resubmitted";
     81 static const char* otherString = "other";
     82 static const char* illegalString = "illegal value";
     83 
     84 static int nextPageID = 1;
     85 
     86 // Used to write a platform neutral file:/// URL by only taking the filename
     87 // (e.g., converts "file:///tmp/foo.txt" to just "foo.txt").
     88 static string urlSuitableForTestResult(const string& url)
     89 {
     90     if (url.empty() || string::npos == url.find("file://"))
     91         return url;
     92 
     93     size_t pos = url.rfind('/');
     94     if (pos == string::npos) {
     95 #if OS(WINDOWS)
     96         pos = url.rfind('\\');
     97         if (pos == string::npos)
     98             pos = 0;
     99 #else
    100         pos = 0;
    101 #endif
    102     }
    103     string filename = url.substr(pos + 1);
    104     if (filename.empty())
    105         return "file:"; // A WebKit test has this in its expected output.
    106     return filename;
    107 }
    108 
    109 // Used to write a platform neutral file:/// URL by taking the
    110 // filename and its directory. (e.g., converts
    111 // "file:///tmp/foo/bar.txt" to just "bar.txt").
    112 static string descriptionSuitableForTestResult(const string& url)
    113 {
    114     if (url.empty() || string::npos == url.find("file://"))
    115         return url;
    116 
    117     size_t pos = url.rfind('/');
    118     if (pos == string::npos || !pos)
    119         return "ERROR:" + url;
    120     pos = url.rfind('/', pos - 1);
    121     if (pos == string::npos)
    122         return "ERROR:" + url;
    123 
    124     return url.substr(pos + 1);
    125 }
    126 
    127 // Adds a file called "DRTFakeFile" to |data_object| (CF_HDROP).  Use to fake
    128 // dragging a file.
    129 static void addDRTFakeFileToDataObject(WebDragData* dragData)
    130 {
    131     dragData->appendToFilenames(WebString::fromUTF8("DRTFakeFile"));
    132 }
    133 
    134 // Get a debugging string from a WebNavigationType.
    135 static const char* webNavigationTypeToString(WebNavigationType type)
    136 {
    137     switch (type) {
    138     case WebKit::WebNavigationTypeLinkClicked:
    139         return linkClickedString;
    140     case WebKit::WebNavigationTypeFormSubmitted:
    141         return formSubmittedString;
    142     case WebKit::WebNavigationTypeBackForward:
    143         return backForwardString;
    144     case WebKit::WebNavigationTypeReload:
    145         return reloadString;
    146     case WebKit::WebNavigationTypeFormResubmitted:
    147         return formResubmittedString;
    148     case WebKit::WebNavigationTypeOther:
    149         return otherString;
    150     }
    151     return illegalString;
    152 }
    153 
    154 static string URLDescription(const GURL& url)
    155 {
    156     if (url.SchemeIs("file"))
    157         return url.ExtractFileName();
    158     return url.possibly_invalid_spec();
    159 }
    160 
    161 static void printResponseDescription(const WebURLResponse& response)
    162 {
    163     if (response.isNull()) {
    164         fputs("(null)", stdout);
    165         return;
    166     }
    167     string url = response.url().spec();
    168     printf("<NSURLResponse %s, http status code %d>",
    169            descriptionSuitableForTestResult(url).c_str(),
    170            response.httpStatusCode());
    171 }
    172 
    173 static void printNodeDescription(const WebNode& node, int exception)
    174 {
    175     if (exception) {
    176         fputs("ERROR", stdout);
    177         return;
    178     }
    179     if (node.isNull()) {
    180         fputs("(null)", stdout);
    181         return;
    182     }
    183     fputs(node.nodeName().utf8().data(), stdout);
    184     const WebNode& parent = node.parentNode();
    185     if (!parent.isNull()) {
    186         fputs(" > ", stdout);
    187         printNodeDescription(parent, 0);
    188     }
    189 }
    190 
    191 static void printRangeDescription(const WebRange& range)
    192 {
    193     if (range.isNull()) {
    194         fputs("(null)", stdout);
    195         return;
    196     }
    197     printf("range from %d of ", range.startOffset());
    198     int exception = 0;
    199     WebNode startNode = range.startContainer(exception);
    200     printNodeDescription(startNode, exception);
    201     printf(" to %d of ", range.endOffset());
    202     WebNode endNode = range.endContainer(exception);
    203     printNodeDescription(endNode, exception);
    204 }
    205 
    206 static string editingActionDescription(WebEditingAction action)
    207 {
    208     switch (action) {
    209     case WebKit::WebEditingActionTyped:
    210         return "WebViewInsertActionTyped";
    211     case WebKit::WebEditingActionPasted:
    212         return "WebViewInsertActionPasted";
    213     case WebKit::WebEditingActionDropped:
    214         return "WebViewInsertActionDropped";
    215     }
    216     return "(UNKNOWN ACTION)";
    217 }
    218 
    219 static string textAffinityDescription(WebTextAffinity affinity)
    220 {
    221     switch (affinity) {
    222     case WebKit::WebTextAffinityUpstream:
    223         return "NSSelectionAffinityUpstream";
    224     case WebKit::WebTextAffinityDownstream:
    225         return "NSSelectionAffinityDownstream";
    226     }
    227     return "(UNKNOWN AFFINITY)";
    228 }
    229 
    230 // WebViewClient -------------------------------------------------------------
    231 
    232 WebView* WebViewHost::createView(WebFrame*, const WebURLRequest&, const WebWindowFeatures&, const WebString&)
    233 {
    234     if (!layoutTestController()->canOpenWindows())
    235         return 0;
    236     return m_shell->createNewWindow(WebURL())->webView();
    237 }
    238 
    239 WebWidget* WebViewHost::createPopupMenu(WebPopupType)
    240 {
    241     return 0;
    242 }
    243 
    244 WebWidget* WebViewHost::createPopupMenu(const WebPopupMenuInfo&)
    245 {
    246     return 0;
    247 }
    248 
    249 WebStorageNamespace* WebViewHost::createSessionStorageNamespace(unsigned quota)
    250 {
    251     return WebKit::WebStorageNamespace::createSessionStorageNamespace(quota);
    252 }
    253 
    254 void WebViewHost::didAddMessageToConsole(const WebConsoleMessage& message, const WebString& sourceName, unsigned sourceLine)
    255 {
    256     // This matches win DumpRenderTree's UIDelegate.cpp.
    257     string newMessage;
    258     if (!message.text.isEmpty()) {
    259         newMessage = message.text.utf8();
    260         size_t fileProtocol = newMessage.find("file://");
    261         if (fileProtocol != string::npos) {
    262             newMessage = newMessage.substr(0, fileProtocol)
    263                 + urlSuitableForTestResult(newMessage.substr(fileProtocol));
    264         }
    265     }
    266     printf("CONSOLE MESSAGE: line %d: %s\n", sourceLine, newMessage.data());
    267 }
    268 
    269 void WebViewHost::didStartLoading()
    270 {
    271     m_shell->setIsLoading(true);
    272 }
    273 
    274 void WebViewHost::didStopLoading()
    275 {
    276     m_shell->setIsLoading(false);
    277 }
    278 
    279 // The output from these methods in layout test mode should match that
    280 // expected by the layout tests.  See EditingDelegate.m in DumpRenderTree.
    281 
    282 bool WebViewHost::shouldBeginEditing(const WebRange& range)
    283 {
    284     if (layoutTestController()->shouldDumpEditingCallbacks()) {
    285         fputs("EDITING DELEGATE: shouldBeginEditingInDOMRange:", stdout);
    286         printRangeDescription(range);
    287         fputs("\n", stdout);
    288     }
    289     return layoutTestController()->acceptsEditing();
    290 }
    291 
    292 bool WebViewHost::shouldEndEditing(const WebRange& range)
    293 {
    294     if (layoutTestController()->shouldDumpEditingCallbacks()) {
    295         fputs("EDITING DELEGATE: shouldEndEditingInDOMRange:", stdout);
    296         printRangeDescription(range);
    297         fputs("\n", stdout);
    298     }
    299     return layoutTestController()->acceptsEditing();
    300 }
    301 
    302 bool WebViewHost::shouldInsertNode(const WebNode& node, const WebRange& range, WebEditingAction action)
    303 {
    304     if (layoutTestController()->shouldDumpEditingCallbacks()) {
    305         fputs("EDITING DELEGATE: shouldInsertNode:", stdout);
    306         printNodeDescription(node, 0);
    307         fputs(" replacingDOMRange:", stdout);
    308         printRangeDescription(range);
    309         printf(" givenAction:%s\n", editingActionDescription(action).c_str());
    310     }
    311     return layoutTestController()->acceptsEditing();
    312 }
    313 
    314 bool WebViewHost::shouldInsertText(const WebString& text, const WebRange& range, WebEditingAction action)
    315 {
    316     if (layoutTestController()->shouldDumpEditingCallbacks()) {
    317         printf("EDITING DELEGATE: shouldInsertText:%s replacingDOMRange:", text.utf8().data());
    318         printRangeDescription(range);
    319         printf(" givenAction:%s\n", editingActionDescription(action).c_str());
    320     }
    321     return layoutTestController()->acceptsEditing();
    322 }
    323 
    324 bool WebViewHost::shouldChangeSelectedRange(
    325     const WebRange& fromRange, const WebRange& toRange, WebTextAffinity affinity, bool stillSelecting)
    326 {
    327     if (layoutTestController()->shouldDumpEditingCallbacks()) {
    328         fputs("EDITING DELEGATE: shouldChangeSelectedDOMRange:", stdout);
    329         printRangeDescription(fromRange);
    330         fputs(" toDOMRange:", stdout);
    331         printRangeDescription(toRange);
    332         printf(" affinity:%s stillSelecting:%s\n",
    333                textAffinityDescription(affinity).c_str(),
    334                (stillSelecting ? "TRUE" : "FALSE"));
    335     }
    336     return layoutTestController()->acceptsEditing();
    337 }
    338 
    339 bool WebViewHost::shouldDeleteRange(const WebRange& range)
    340 {
    341     if (layoutTestController()->shouldDumpEditingCallbacks()) {
    342         fputs("EDITING DELEGATE: shouldDeleteDOMRange:", stdout);
    343         printRangeDescription(range);
    344         fputs("\n", stdout);
    345     }
    346     return layoutTestController()->acceptsEditing();
    347 }
    348 
    349 bool WebViewHost::shouldApplyStyle(const WebString& style, const WebRange& range)
    350 {
    351     if (layoutTestController()->shouldDumpEditingCallbacks()) {
    352         printf("EDITING DELEGATE: shouldApplyStyle:%s toElementsInDOMRange:", style.utf8().data());
    353         printRangeDescription(range);
    354         fputs("\n", stdout);
    355     }
    356     return layoutTestController()->acceptsEditing();
    357 }
    358 
    359 bool WebViewHost::isSmartInsertDeleteEnabled()
    360 {
    361     return m_smartInsertDeleteEnabled;
    362 }
    363 
    364 bool WebViewHost::isSelectTrailingWhitespaceEnabled()
    365 {
    366     return m_selectTrailingWhitespaceEnabled;
    367 }
    368 
    369 void WebViewHost::didBeginEditing()
    370 {
    371     if (!layoutTestController()->shouldDumpEditingCallbacks())
    372         return;
    373     fputs("EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification\n", stdout);
    374 }
    375 
    376 void WebViewHost::didChangeSelection(bool isEmptySelection)
    377 {
    378     if (layoutTestController()->shouldDumpEditingCallbacks())
    379         fputs("EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification\n", stdout);
    380     // No need to update clipboard with the selected text in DRT.
    381 }
    382 
    383 void WebViewHost::didChangeContents()
    384 {
    385     if (!layoutTestController()->shouldDumpEditingCallbacks())
    386         return;
    387     fputs("EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification\n", stdout);
    388 }
    389 
    390 void WebViewHost::didEndEditing()
    391 {
    392     if (!layoutTestController()->shouldDumpEditingCallbacks())
    393         return;
    394     fputs("EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification\n", stdout);
    395 }
    396 
    397 bool WebViewHost::handleCurrentKeyboardEvent()
    398 {
    399     if (m_editCommandName.empty())
    400         return false;
    401     WebFrame* frame = webView()->focusedFrame();
    402     if (!frame)
    403         return false;
    404 
    405     return frame->executeCommand(WebString::fromUTF8(m_editCommandName), WebString::fromUTF8(m_editCommandValue));
    406 }
    407 
    408 void WebViewHost::spellCheck(const WebString& text, int& misspelledOffset, int& misspelledLength, WebVector<WebString>* optionalSuggestions)
    409 {
    410     // Check the spelling of the given text.
    411     m_spellcheck.spellCheckWord(text, &misspelledOffset, &misspelledLength);
    412 }
    413 
    414 void WebViewHost::requestCheckingOfText(const WebString& text, WebTextCheckingCompletion* completion)
    415 {
    416     m_lastRequestedTextCheckingCompletion = completion;
    417     m_lastRequestedTextCheckString = text;
    418     postDelayedTask(new HostMethodTask(this, &WebViewHost::finishLastTextCheck), 0);
    419 }
    420 
    421 void WebViewHost::finishLastTextCheck()
    422 {
    423     Vector<WebTextCheckingResult> results;
    424     // FIXME: Do the grammar check.
    425     int offset = 0;
    426     String text(m_lastRequestedTextCheckString.data(), m_lastRequestedTextCheckString.length());
    427     while (text.length()) {
    428         int misspelledPosition = 0;
    429         int misspelledLength = 0;
    430         m_spellcheck.spellCheckWord(WebString(text.characters(), text.length()), &misspelledPosition, &misspelledLength);
    431         if (!misspelledLength)
    432             break;
    433         results.append(WebTextCheckingResult(WebTextCheckingResult::ErrorSpelling, offset + misspelledPosition, misspelledLength));
    434         text = text.substring(misspelledPosition + misspelledLength);
    435         offset += misspelledPosition;
    436     }
    437 
    438     m_lastRequestedTextCheckingCompletion->didFinishCheckingText(results);
    439     m_lastRequestedTextCheckingCompletion = 0;
    440 }
    441 
    442 
    443 WebString WebViewHost::autoCorrectWord(const WebString&)
    444 {
    445     // Returns an empty string as Mac WebKit ('WebKitSupport/WebEditorClient.mm')
    446     // does. (If this function returns a non-empty string, WebKit replaces the
    447     // given misspelled string with the result one. This process executes some
    448     // editor commands and causes layout-test failures.)
    449     return WebString();
    450 }
    451 
    452 void WebViewHost::runModalAlertDialog(WebFrame*, const WebString& message)
    453 {
    454     printf("ALERT: %s\n", message.utf8().data());
    455 }
    456 
    457 bool WebViewHost::runModalConfirmDialog(WebFrame*, const WebString& message)
    458 {
    459     printf("CONFIRM: %s\n", message.utf8().data());
    460     return true;
    461 }
    462 
    463 bool WebViewHost::runModalPromptDialog(WebFrame* frame, const WebString& message,
    464                                        const WebString& defaultValue, WebString*)
    465 {
    466     printf("PROMPT: %s, default text: %s\n", message.utf8().data(), defaultValue.utf8().data());
    467     return true;
    468 }
    469 
    470 bool WebViewHost::runModalBeforeUnloadDialog(WebFrame*, const WebString&)
    471 {
    472     return true; // Allow window closure.
    473 }
    474 
    475 void WebViewHost::showContextMenu(WebFrame*, const WebContextMenuData& contextMenuData)
    476 {
    477     m_lastContextMenuData = adoptPtr(new WebContextMenuData(contextMenuData));
    478 }
    479 
    480 void WebViewHost::clearContextMenuData()
    481 {
    482     m_lastContextMenuData.clear();
    483 }
    484 
    485 WebContextMenuData* WebViewHost::lastContextMenuData() const
    486 {
    487     return m_lastContextMenuData.get();
    488 }
    489 
    490 void WebViewHost::setStatusText(const WebString& text)
    491 {
    492     if (!layoutTestController()->shouldDumpStatusCallbacks())
    493         return;
    494     // When running tests, write to stdout.
    495     printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", text.utf8().data());
    496 }
    497 
    498 void WebViewHost::startDragging(const WebDragData& data, WebDragOperationsMask mask, const WebImage&, const WebPoint&)
    499 {
    500     WebDragData mutableDragData = data;
    501     if (layoutTestController()->shouldAddFileToPasteboard()) {
    502         // Add a file called DRTFakeFile to the drag&drop clipboard.
    503         addDRTFakeFileToDataObject(&mutableDragData);
    504     }
    505 
    506     // When running a test, we need to fake a drag drop operation otherwise
    507     // Windows waits for real mouse events to know when the drag is over.
    508     m_shell->eventSender()->doDragDrop(mutableDragData, mask);
    509 }
    510 
    511 void WebViewHost::navigateBackForwardSoon(int offset)
    512 {
    513     navigationController()->goToOffset(offset);
    514 }
    515 
    516 int WebViewHost::historyBackListCount()
    517 {
    518     return navigationController()->lastCommittedEntryIndex();
    519 }
    520 
    521 int WebViewHost::historyForwardListCount()
    522 {
    523     int currentIndex =navigationController()->lastCommittedEntryIndex();
    524     return navigationController()->entryCount() - currentIndex - 1;
    525 }
    526 
    527 void WebViewHost::postAccessibilityNotification(const WebAccessibilityObject& obj, WebAccessibilityNotification notification)
    528 {
    529     if (notification == WebAccessibilityNotificationFocusedUIElementChanged)
    530         m_shell->accessibilityController()->setFocusedElement(obj);
    531 
    532     if (m_shell->accessibilityController()->shouldDumpAccessibilityNotifications()) {
    533         printf("AccessibilityNotification - ");
    534 
    535         switch (notification) {
    536         case WebAccessibilityNotificationActiveDescendantChanged:
    537             printf("ActiveDescendantChanged");
    538             break;
    539         case WebAccessibilityNotificationCheckedStateChanged:
    540             printf("CheckedStateChanged");
    541             break;
    542         case WebAccessibilityNotificationChildrenChanged:
    543             printf("ChildrenChanged");
    544             break;
    545         case WebAccessibilityNotificationFocusedUIElementChanged:
    546             printf("FocusedUIElementChanged");
    547             break;
    548         case WebAccessibilityNotificationLayoutComplete:
    549             printf("LayoutComplete");
    550             break;
    551         case WebAccessibilityNotificationLoadComplete:
    552             printf("LoadComplete");
    553             break;
    554         case WebAccessibilityNotificationSelectedChildrenChanged:
    555             printf("SelectedChildrenChanged");
    556             break;
    557         case WebAccessibilityNotificationSelectedTextChanged:
    558             printf("SelectedTextChanged");
    559             break;
    560         case WebAccessibilityNotificationValueChanged:
    561             printf("ValueChanged");
    562             break;
    563         case WebAccessibilityNotificationScrolledToAnchor:
    564             printf("ScrolledToAnchor");
    565             break;
    566         case WebAccessibilityNotificationLiveRegionChanged:
    567             printf("LiveRegionChanged");
    568             break;
    569         case WebAccessibilityNotificationMenuListValueChanged:
    570             printf("MenuListValueChanged");
    571             break;
    572         case WebAccessibilityNotificationRowCountChanged:
    573             printf("RowCountChanged");
    574             break;
    575         case WebAccessibilityNotificationRowCollapsed:
    576             printf("RowCollapsed");
    577             break;
    578         case WebAccessibilityNotificationRowExpanded:
    579             printf("RowExpanded");
    580             break;
    581         default:
    582             break;
    583         }
    584 
    585         WebKit::WebNode node = obj.node();
    586         if (!node.isNull() && node.isElementNode()) {
    587             WebKit::WebElement element = node.to<WebKit::WebElement>();
    588             if (element.hasAttribute("id"))
    589                 printf(" - id:%s", element.getAttribute("id").utf8().data());
    590         }
    591 
    592         printf("\n");
    593     }
    594 }
    595 
    596 WebNotificationPresenter* WebViewHost::notificationPresenter()
    597 {
    598     return m_shell->notificationPresenter();
    599 }
    600 
    601 WebKit::WebGeolocationClient* WebViewHost::geolocationClient()
    602 {
    603     return geolocationClientMock();
    604 }
    605 
    606 WebKit::WebGeolocationClientMock* WebViewHost::geolocationClientMock()
    607 {
    608     if (!m_geolocationClientMock)
    609         m_geolocationClientMock.set(WebGeolocationClientMock::create());
    610     return m_geolocationClientMock.get();
    611 }
    612 
    613 WebSpeechInputController* WebViewHost::speechInputController(WebKit::WebSpeechInputListener* listener)
    614 {
    615     if (!m_speechInputControllerMock)
    616         m_speechInputControllerMock.set(WebSpeechInputControllerMock::create(listener));
    617     return m_speechInputControllerMock.get();
    618 }
    619 
    620 WebDeviceOrientationClientMock* WebViewHost::deviceOrientationClientMock()
    621 {
    622     if (!m_deviceOrientationClientMock.get())
    623         m_deviceOrientationClientMock.set(WebDeviceOrientationClientMock::create());
    624     return m_deviceOrientationClientMock.get();
    625 }
    626 
    627 MockSpellCheck* WebViewHost::mockSpellCheck()
    628 {
    629     return &m_spellcheck;
    630 }
    631 
    632 WebDeviceOrientationClient* WebViewHost::deviceOrientationClient()
    633 {
    634     return deviceOrientationClientMock();
    635 }
    636 
    637 // WebWidgetClient -----------------------------------------------------------
    638 
    639 void WebViewHost::didInvalidateRect(const WebRect& rect)
    640 {
    641     updatePaintRect(rect);
    642 }
    643 
    644 void WebViewHost::didScrollRect(int, int, const WebRect& clipRect)
    645 {
    646     // This is used for optimizing painting when the renderer is scrolled. We're
    647     // currently not doing any optimizations so just invalidate the region.
    648     didInvalidateRect(clipRect);
    649 }
    650 
    651 void WebViewHost::scheduleComposite()
    652 {
    653     WebSize widgetSize = webWidget()->size();
    654     WebRect clientRect(0, 0, widgetSize.width, widgetSize.height);
    655     didInvalidateRect(clientRect);
    656 }
    657 
    658 #if ENABLE(REQUEST_ANIMATION_FRAME)
    659 void WebViewHost::scheduleAnimation()
    660 {
    661     postDelayedTask(new HostMethodTask(this, &WebViewHost::scheduleComposite), 0);
    662 }
    663 #endif
    664 
    665 void WebViewHost::didFocus()
    666 {
    667     m_shell->setFocus(webWidget(), true);
    668 }
    669 
    670 void WebViewHost::didBlur()
    671 {
    672     m_shell->setFocus(webWidget(), false);
    673 }
    674 
    675 WebScreenInfo WebViewHost::screenInfo()
    676 {
    677     // We don't need to set actual values.
    678     WebScreenInfo info;
    679     info.depth = 24;
    680     info.depthPerComponent = 8;
    681     info.isMonochrome = false;
    682     info.rect = WebRect(0, 0, screenWidth, screenHeight);
    683     // Use values different from info.rect for testing.
    684     info.availableRect = WebRect(screenUnavailableBorder, screenUnavailableBorder,
    685                                  screenWidth - screenUnavailableBorder * 2,
    686                                  screenHeight - screenUnavailableBorder * 2);
    687     return info;
    688 }
    689 
    690 void WebViewHost::show(WebNavigationPolicy)
    691 {
    692     m_hasWindow = true;
    693     WebSize size = webWidget()->size();
    694     updatePaintRect(WebRect(0, 0, size.width, size.height));
    695 }
    696 
    697 
    698 
    699 void WebViewHost::closeWidget()
    700 {
    701     m_hasWindow = false;
    702     m_shell->closeWindow(this);
    703     // No more code here, we should be deleted at this point.
    704 }
    705 
    706 void WebViewHost::closeWidgetSoon()
    707 {
    708     postDelayedTask(new HostMethodTask(this, &WebViewHost::closeWidget), 0);
    709 }
    710 
    711 void WebViewHost::didChangeCursor(const WebCursorInfo& cursorInfo)
    712 {
    713     if (!hasWindow())
    714         return;
    715     m_currentCursor = cursorInfo;
    716 }
    717 
    718 WebRect WebViewHost::windowRect()
    719 {
    720     return m_windowRect;
    721 }
    722 
    723 void WebViewHost::setWindowRect(const WebRect& rect)
    724 {
    725     m_windowRect = rect;
    726     const int border2 = TestShell::virtualWindowBorder * 2;
    727     if (m_windowRect.width <= border2)
    728         m_windowRect.width = 1 + border2;
    729     if (m_windowRect.height <= border2)
    730         m_windowRect.height = 1 + border2;
    731     int width = m_windowRect.width - border2;
    732     int height = m_windowRect.height - border2;
    733     discardBackingStore();
    734     webWidget()->resize(WebSize(width, height));
    735     updatePaintRect(WebRect(0, 0, width, height));
    736 }
    737 
    738 WebRect WebViewHost::rootWindowRect()
    739 {
    740     return windowRect();
    741 }
    742 
    743 WebRect WebViewHost::windowResizerRect()
    744 {
    745     // Not necessary.
    746     return WebRect();
    747 }
    748 
    749 void WebViewHost::runModal()
    750 {
    751     bool oldState = webkit_support::MessageLoopNestableTasksAllowed();
    752     webkit_support::MessageLoopSetNestableTasksAllowed(true);
    753     m_inModalLoop = true;
    754     webkit_support::RunMessageLoop();
    755     webkit_support::MessageLoopSetNestableTasksAllowed(oldState);
    756 }
    757 
    758 // WebFrameClient ------------------------------------------------------------
    759 
    760 WebPlugin* WebViewHost::createPlugin(WebFrame* frame, const WebPluginParams& params)
    761 {
    762     return webkit_support::CreateWebPlugin(frame, params);
    763 }
    764 
    765 WebWorker* WebViewHost::createWorker(WebFrame*, WebWorkerClient*)
    766 {
    767     return new TestWebWorker();
    768 }
    769 
    770 WebMediaPlayer* WebViewHost::createMediaPlayer(WebFrame* frame, WebMediaPlayerClient* client)
    771 {
    772     return webkit_support::CreateMediaPlayer(frame, client);
    773 }
    774 
    775 WebApplicationCacheHost* WebViewHost::createApplicationCacheHost(WebFrame* frame, WebApplicationCacheHostClient* client)
    776 {
    777     return webkit_support::CreateApplicationCacheHost(frame, client);
    778 }
    779 
    780 bool WebViewHost::allowPlugins(WebFrame* frame, bool enabledPerSettings)
    781 {
    782     return enabledPerSettings;
    783 }
    784 
    785 bool WebViewHost::allowImages(WebFrame* frame, bool enabledPerSettings)
    786 {
    787     return enabledPerSettings;
    788 }
    789 
    790 void WebViewHost::loadURLExternally(WebFrame*, const WebURLRequest& request, WebNavigationPolicy policy)
    791 {
    792     ASSERT(policy !=  WebKit::WebNavigationPolicyCurrentTab);
    793     WebViewHost* another = m_shell->createNewWindow(request.url());
    794     if (another)
    795         another->show(policy);
    796 }
    797 
    798 WebNavigationPolicy WebViewHost::decidePolicyForNavigation(
    799     WebFrame*, const WebURLRequest& request,
    800     WebNavigationType type, const WebNode& originatingNode,
    801     WebNavigationPolicy defaultPolicy, bool isRedirect)
    802 {
    803     WebNavigationPolicy result;
    804     if (!m_policyDelegateEnabled)
    805         return defaultPolicy;
    806 
    807     printf("Policy delegate: attempt to load %s with navigation type '%s'",
    808            URLDescription(request.url()).c_str(), webNavigationTypeToString(type));
    809     if (!originatingNode.isNull()) {
    810         fputs(" originating from ", stdout);
    811         printNodeDescription(originatingNode, 0);
    812     }
    813     fputs("\n", stdout);
    814     if (m_policyDelegateIsPermissive)
    815         result = WebKit::WebNavigationPolicyCurrentTab;
    816     else
    817         result = WebKit::WebNavigationPolicyIgnore;
    818 
    819     if (m_policyDelegateShouldNotifyDone)
    820         layoutTestController()->policyDelegateDone();
    821     return result;
    822 }
    823 
    824 bool WebViewHost::canHandleRequest(WebFrame*, const WebURLRequest& request)
    825 {
    826     GURL url = request.url();
    827     // Just reject the scheme used in
    828     // LayoutTests/http/tests/misc/redirect-to-external-url.html
    829     return !url.SchemeIs("spaceballs");
    830 }
    831 
    832 WebURLError WebViewHost::cannotHandleRequestError(WebFrame*, const WebURLRequest& request)
    833 {
    834     WebURLError error;
    835     // A WebKit layout test expects the following values.
    836     // unableToImplementPolicyWithError() below prints them.
    837     error.domain = WebString::fromUTF8("WebKitErrorDomain");
    838     error.reason = 101;
    839     error.unreachableURL = request.url();
    840     return error;
    841 }
    842 
    843 WebURLError WebViewHost::cancelledError(WebFrame*, const WebURLRequest& request)
    844 {
    845     return webkit_support::CreateCancelledError(request);
    846 }
    847 
    848 void WebViewHost::unableToImplementPolicyWithError(WebFrame* frame, const WebURLError& error)
    849 {
    850     printf("Policy delegate: unable to implement policy with error domain '%s', "
    851            "error code %d, in frame '%s'\n",
    852            error.domain.utf8().data(), error.reason, frame->name().utf8().data());
    853 }
    854 
    855 void WebViewHost::willPerformClientRedirect(WebFrame* frame, const WebURL& from, const WebURL& to,
    856                                             double interval, double fire_time)
    857 {
    858     if (!m_shell->shouldDumpFrameLoadCallbacks())
    859         return;
    860     printFrameDescription(frame);
    861     printf(" - willPerformClientRedirectToURL: %s \n", to.spec().data());
    862 }
    863 
    864 void WebViewHost::didCancelClientRedirect(WebFrame* frame)
    865 {
    866     if (!m_shell->shouldDumpFrameLoadCallbacks())
    867         return;
    868     printFrameDescription(frame);
    869     fputs(" - didCancelClientRedirectForFrame\n", stdout);
    870 }
    871 
    872 void WebViewHost::didCreateDataSource(WebFrame*, WebDataSource* ds)
    873 {
    874     ds->setExtraData(m_pendingExtraData.leakPtr());
    875     if (!layoutTestController()->deferMainResourceDataLoad())
    876         ds->setDeferMainResourceDataLoad(false);
    877 }
    878 
    879 void WebViewHost::didStartProvisionalLoad(WebFrame* frame)
    880 {
    881     if (m_shell->shouldDumpUserGestureInFrameLoadCallbacks())
    882         printFrameUserGestureStatus(frame, " - in didStartProvisionalLoadForFrame\n");
    883     if (m_shell->shouldDumpFrameLoadCallbacks()) {
    884         printFrameDescription(frame);
    885         fputs(" - didStartProvisionalLoadForFrame\n", stdout);
    886     }
    887 
    888     if (!m_topLoadingFrame)
    889         m_topLoadingFrame = frame;
    890 
    891     if (layoutTestController()->stopProvisionalFrameLoads()) {
    892         printFrameDescription(frame);
    893         fputs(" - stopping load in didStartProvisionalLoadForFrame callback\n", stdout);
    894         frame->stopLoading();
    895     }
    896     updateAddressBar(frame->view());
    897 }
    898 
    899 void WebViewHost::didReceiveServerRedirectForProvisionalLoad(WebFrame* frame)
    900 {
    901     if (m_shell->shouldDumpFrameLoadCallbacks()) {
    902         printFrameDescription(frame);
    903         fputs(" - didReceiveServerRedirectForProvisionalLoadForFrame\n", stdout);
    904     }
    905     updateAddressBar(frame->view());
    906 }
    907 
    908 void WebViewHost::didFailProvisionalLoad(WebFrame* frame, const WebURLError& error)
    909 {
    910     if (m_shell->shouldDumpFrameLoadCallbacks()) {
    911         printFrameDescription(frame);
    912         fputs(" - didFailProvisionalLoadWithError\n", stdout);
    913     }
    914 
    915     locationChangeDone(frame);
    916 
    917     // Don't display an error page if we're running layout tests, because
    918     // DumpRenderTree doesn't.
    919 }
    920 
    921 void WebViewHost::didCommitProvisionalLoad(WebFrame* frame, bool isNewNavigation)
    922 {
    923     if (m_shell->shouldDumpFrameLoadCallbacks()) {
    924         printFrameDescription(frame);
    925         fputs(" - didCommitLoadForFrame\n", stdout);
    926     }
    927     updateForCommittedLoad(frame, isNewNavigation);
    928 }
    929 
    930 void WebViewHost::didClearWindowObject(WebFrame* frame)
    931 {
    932     m_shell->bindJSObjectsToWindow(frame);
    933 }
    934 
    935 void WebViewHost::didReceiveTitle(WebFrame* frame, const WebString& title, WebTextDirection direction)
    936 {
    937     WebCString title8 = title.utf8();
    938 
    939     if (m_shell->shouldDumpFrameLoadCallbacks()) {
    940         printFrameDescription(frame);
    941         printf(" - didReceiveTitle: %s\n", title8.data());
    942     }
    943 
    944     if (layoutTestController()->shouldDumpTitleChanges())
    945         printf("TITLE CHANGED: %s\n", title8.data());
    946 
    947     setPageTitle(title);
    948     layoutTestController()->setTitleTextDirection(direction);
    949 }
    950 
    951 void WebViewHost::didFinishDocumentLoad(WebFrame* frame)
    952 {
    953     if (m_shell->shouldDumpFrameLoadCallbacks()) {
    954         printFrameDescription(frame);
    955         fputs(" - didFinishDocumentLoadForFrame\n", stdout);
    956     } else {
    957         unsigned pendingUnloadEvents = frame->unloadListenerCount();
    958         if (pendingUnloadEvents) {
    959             printFrameDescription(frame);
    960             printf(" - has %u onunload handler(s)\n", pendingUnloadEvents);
    961         }
    962     }
    963 }
    964 
    965 void WebViewHost::didHandleOnloadEvents(WebFrame* frame)
    966 {
    967     if (m_shell->shouldDumpFrameLoadCallbacks()) {
    968         printFrameDescription(frame);
    969         fputs(" - didHandleOnloadEventsForFrame\n", stdout);
    970     }
    971 }
    972 
    973 void WebViewHost::didFailLoad(WebFrame* frame, const WebURLError& error)
    974 {
    975     if (m_shell->shouldDumpFrameLoadCallbacks()) {
    976         printFrameDescription(frame);
    977         fputs(" - didFailLoadWithError\n", stdout);
    978     }
    979     locationChangeDone(frame);
    980 }
    981 
    982 void WebViewHost::didFinishLoad(WebFrame* frame)
    983 {
    984     if (m_shell->shouldDumpFrameLoadCallbacks()) {
    985         printFrameDescription(frame);
    986         fputs(" - didFinishLoadForFrame\n", stdout);
    987     }
    988     updateAddressBar(frame->view());
    989     locationChangeDone(frame);
    990 }
    991 
    992 void WebViewHost::didNavigateWithinPage(WebFrame* frame, bool isNewNavigation)
    993 {
    994     frame->dataSource()->setExtraData(m_pendingExtraData.leakPtr());
    995 
    996     updateForCommittedLoad(frame, isNewNavigation);
    997 }
    998 
    999 void WebViewHost::didChangeLocationWithinPage(WebFrame* frame)
   1000 {
   1001     if (m_shell->shouldDumpFrameLoadCallbacks()) {
   1002         printFrameDescription(frame);
   1003         fputs(" - didChangeLocationWithinPageForFrame\n", stdout);
   1004     }
   1005 }
   1006 
   1007 void WebViewHost::assignIdentifierToRequest(WebFrame*, unsigned identifier, const WebURLRequest& request)
   1008 {
   1009      if (!m_shell->shouldDumpResourceLoadCallbacks())
   1010         return;
   1011     ASSERT(!m_resourceIdentifierMap.contains(identifier));
   1012     m_resourceIdentifierMap.set(identifier, descriptionSuitableForTestResult(request.url().spec()));
   1013 }
   1014 
   1015 void WebViewHost::removeIdentifierForRequest(unsigned identifier)
   1016 {
   1017     m_resourceIdentifierMap.remove(identifier);
   1018 }
   1019 
   1020 void WebViewHost::willSendRequest(WebFrame*, unsigned identifier, WebURLRequest& request, const WebURLResponse& redirectResponse)
   1021 {
   1022     // Need to use GURL for host() and SchemeIs()
   1023     GURL url = request.url();
   1024     string requestURL = url.possibly_invalid_spec();
   1025 
   1026     if (layoutTestController()->shouldDumpResourceLoadCallbacks()) {
   1027         GURL mainDocumentURL = request.firstPartyForCookies();
   1028         printResourceDescription(identifier);
   1029         printf(" - willSendRequest <NSURLRequest URL %s, main document URL %s,"
   1030                " http method %s> redirectResponse ",
   1031                descriptionSuitableForTestResult(requestURL).c_str(),
   1032                URLDescription(mainDocumentURL).c_str(),
   1033                request.httpMethod().utf8().data());
   1034         printResponseDescription(redirectResponse);
   1035         fputs("\n", stdout);
   1036     }
   1037 
   1038     if (!redirectResponse.isNull() && m_blocksRedirects) {
   1039         fputs("Returning null for this redirect\n", stdout);
   1040         // To block the request, we set its URL to an empty one.
   1041         request.setURL(WebURL());
   1042         return;
   1043     }
   1044 
   1045     if (m_requestReturnNull) {
   1046         // To block the request, we set its URL to an empty one.
   1047         request.setURL(WebURL());
   1048         return;
   1049     }
   1050 
   1051     string host = url.host();
   1052     // 255.255.255.255 is used in some tests that expect to get back an error.
   1053     if (!host.empty() && (url.SchemeIs("http") || url.SchemeIs("https"))
   1054         && host != "127.0.0.1"
   1055         && host != "255.255.255.255"
   1056         && host != "localhost"
   1057         && !m_shell->allowExternalPages()) {
   1058         printf("Blocked access to external URL %s\n", requestURL.c_str());
   1059 
   1060         // To block the request, we set its URL to an empty one.
   1061         request.setURL(WebURL());
   1062         return;
   1063     }
   1064 
   1065     HashSet<String>::const_iterator end = m_clearHeaders.end();
   1066     for (HashSet<String>::const_iterator header = m_clearHeaders.begin(); header != end; ++header)
   1067         request.clearHTTPHeaderField(WebString(header->characters(), header->length()));
   1068 
   1069     // Set the new substituted URL.
   1070     request.setURL(webkit_support::RewriteLayoutTestsURL(request.url().spec()));
   1071 }
   1072 
   1073 void WebViewHost::didReceiveResponse(WebFrame*, unsigned identifier, const WebURLResponse& response)
   1074 {
   1075     if (m_shell->shouldDumpResourceLoadCallbacks()) {
   1076         printResourceDescription(identifier);
   1077         fputs(" - didReceiveResponse ", stdout);
   1078         printResponseDescription(response);
   1079         fputs("\n", stdout);
   1080     }
   1081     if (m_shell->shouldDumpResourceResponseMIMETypes()) {
   1082         GURL url = response.url();
   1083         WebString mimeType = response.mimeType();
   1084         printf("%s has MIME type %s\n",
   1085             url.ExtractFileName().c_str(),
   1086             // Simulate NSURLResponse's mapping of empty/unknown MIME types to application/octet-stream
   1087             mimeType.isEmpty() ? "application/octet-stream" : mimeType.utf8().data());
   1088     }
   1089 }
   1090 
   1091 void WebViewHost::didFinishResourceLoad(WebFrame*, unsigned identifier)
   1092 {
   1093     if (m_shell->shouldDumpResourceLoadCallbacks()) {
   1094         printResourceDescription(identifier);
   1095         fputs(" - didFinishLoading\n", stdout);
   1096     }
   1097     removeIdentifierForRequest(identifier);
   1098 }
   1099 
   1100 void WebViewHost::didFailResourceLoad(WebFrame*, unsigned identifier, const WebURLError& error)
   1101 {
   1102     if (m_shell->shouldDumpResourceLoadCallbacks()) {
   1103         printResourceDescription(identifier);
   1104         fputs(" - didFailLoadingWithError: ", stdout);
   1105         fputs(webkit_support::MakeURLErrorDescription(error).c_str(), stdout);
   1106         fputs("\n", stdout);
   1107     }
   1108     removeIdentifierForRequest(identifier);
   1109 }
   1110 
   1111 void WebViewHost::didDisplayInsecureContent(WebFrame*)
   1112 {
   1113     if (m_shell->shouldDumpFrameLoadCallbacks())
   1114         fputs("didDisplayInsecureContent\n", stdout);
   1115 }
   1116 
   1117 void WebViewHost::didRunInsecureContent(WebFrame*, const WebSecurityOrigin& origin, const WebURL& insecureURL)
   1118 {
   1119     if (m_shell->shouldDumpFrameLoadCallbacks())
   1120         fputs("didRunInsecureContent\n", stdout);
   1121 }
   1122 
   1123 bool WebViewHost::allowScript(WebFrame*, bool enabledPerSettings)
   1124 {
   1125     return enabledPerSettings;
   1126 }
   1127 
   1128 void WebViewHost::openFileSystem(WebFrame* frame, WebFileSystem::Type type, long long size, bool create, WebFileSystemCallbacks* callbacks)
   1129 {
   1130     webkit_support::OpenFileSystem(frame, type, size, create, callbacks);
   1131 }
   1132 
   1133 // Public functions -----------------------------------------------------------
   1134 
   1135 WebViewHost::WebViewHost(TestShell* shell)
   1136     : m_shell(shell)
   1137     , m_webWidget(0)
   1138     , m_lastRequestedTextCheckingCompletion(0)
   1139 {
   1140     reset();
   1141 }
   1142 
   1143 WebViewHost::~WebViewHost()
   1144 {
   1145     // DevTools frontend page is supposed to be navigated only once and
   1146     // loading another URL in that Page is an error.
   1147     if (m_shell->devToolsWebView() != this) {
   1148         // Navigate to an empty page to fire all the destruction logic for the
   1149         // current page.
   1150         loadURLForFrame(GURL("about:blank"), WebString());
   1151     }
   1152 
   1153     webWidget()->close();
   1154 
   1155     if (m_inModalLoop)
   1156         webkit_support::QuitMessageLoop();
   1157 }
   1158 
   1159 void WebViewHost::setWebWidget(WebKit::WebWidget* widget)
   1160 {
   1161     m_webWidget = widget;
   1162     webView()->setSpellCheckClient(this);
   1163 }
   1164 
   1165 WebView* WebViewHost::webView() const
   1166 {
   1167     ASSERT(m_webWidget);
   1168     // DRT does not support popup widgets. So m_webWidget is always a WebView.
   1169     return static_cast<WebView*>(m_webWidget);
   1170 }
   1171 
   1172 WebWidget* WebViewHost::webWidget() const
   1173 {
   1174     ASSERT(m_webWidget);
   1175     return m_webWidget;
   1176 }
   1177 
   1178 void WebViewHost::reset()
   1179 {
   1180     m_policyDelegateEnabled = false;
   1181     m_policyDelegateIsPermissive = false;
   1182     m_policyDelegateShouldNotifyDone = false;
   1183     m_topLoadingFrame = 0;
   1184     m_pageId = -1;
   1185     m_lastPageIdUpdated = -1;
   1186     m_hasWindow = false;
   1187     m_inModalLoop = false;
   1188     m_smartInsertDeleteEnabled = true;
   1189 #if OS(WINDOWS)
   1190     m_selectTrailingWhitespaceEnabled = true;
   1191 #else
   1192     m_selectTrailingWhitespaceEnabled = false;
   1193 #endif
   1194     m_blocksRedirects = false;
   1195     m_requestReturnNull = false;
   1196     m_isPainting = false;
   1197     m_canvas.clear();
   1198 
   1199     m_navigationController.set(new TestNavigationController(this));
   1200 
   1201     m_pendingExtraData.clear();
   1202     m_resourceIdentifierMap.clear();
   1203     m_clearHeaders.clear();
   1204     m_editCommandName.clear();
   1205     m_editCommandValue.clear();
   1206 
   1207     if (m_geolocationClientMock.get())
   1208         m_geolocationClientMock->resetMock();
   1209 
   1210     if (m_speechInputControllerMock.get())
   1211         m_speechInputControllerMock->clearResults();
   1212 
   1213     m_currentCursor = WebCursorInfo();
   1214     m_windowRect = WebRect();
   1215     m_paintRect = WebRect();
   1216 
   1217     if (m_webWidget) {
   1218         webView()->mainFrame()->setName(WebString());
   1219         webView()->settings()->setMinimumTimerInterval(webkit_support::GetForegroundTabTimerInterval());
   1220     }
   1221 }
   1222 
   1223 void WebViewHost::setSelectTrailingWhitespaceEnabled(bool enabled)
   1224 {
   1225     m_selectTrailingWhitespaceEnabled = enabled;
   1226     // In upstream WebKit, smart insert/delete is mutually exclusive with select
   1227     // trailing whitespace, however, we allow both because Chromium on Windows
   1228     // allows both.
   1229 }
   1230 
   1231 void WebViewHost::setSmartInsertDeleteEnabled(bool enabled)
   1232 {
   1233     m_smartInsertDeleteEnabled = enabled;
   1234     // In upstream WebKit, smart insert/delete is mutually exclusive with select
   1235     // trailing whitespace, however, we allow both because Chromium on Windows
   1236     // allows both.
   1237 }
   1238 
   1239 void WebViewHost::setCustomPolicyDelegate(bool isCustom, bool isPermissive)
   1240 {
   1241     m_policyDelegateEnabled = isCustom;
   1242     m_policyDelegateIsPermissive = isPermissive;
   1243 }
   1244 
   1245 void WebViewHost::waitForPolicyDelegate()
   1246 {
   1247     m_policyDelegateEnabled = true;
   1248     m_policyDelegateShouldNotifyDone = true;
   1249 }
   1250 
   1251 void WebViewHost::setEditCommand(const string& name, const string& value)
   1252 {
   1253     m_editCommandName = name;
   1254     m_editCommandValue = value;
   1255 }
   1256 
   1257 void WebViewHost::clearEditCommand()
   1258 {
   1259     m_editCommandName.clear();
   1260     m_editCommandValue.clear();
   1261 }
   1262 
   1263 void WebViewHost::loadURLForFrame(const WebURL& url, const WebString& frameName)
   1264 {
   1265     if (!url.isValid())
   1266         return;
   1267     TestShell::resizeWindowForTest(this, url);
   1268     navigationController()->loadEntry(TestNavigationEntry::create(-1, url, WebString(), frameName).get());
   1269 }
   1270 
   1271 bool WebViewHost::navigate(const TestNavigationEntry& entry, bool reload)
   1272 {
   1273     // Get the right target frame for the entry.
   1274     WebFrame* frame = webView()->mainFrame();
   1275     if (!entry.targetFrame().isEmpty())
   1276         frame = webView()->findFrameByName(entry.targetFrame());
   1277 
   1278     // TODO(mpcomplete): should we clear the target frame, or should
   1279     // back/forward navigations maintain the target frame?
   1280 
   1281     // A navigation resulting from loading a javascript URL should not be
   1282     // treated as a browser initiated event.  Instead, we want it to look as if
   1283     // the page initiated any load resulting from JS execution.
   1284     if (!GURL(entry.URL()).SchemeIs("javascript"))
   1285         setPendingExtraData(new TestShellExtraData(entry.pageID()));
   1286 
   1287     // If we are reloading, then WebKit will use the state of the current page.
   1288     // Otherwise, we give it the state to navigate to.
   1289     if (reload) {
   1290         frame->reload(false);
   1291     } else if (!entry.contentState().isNull()) {
   1292         ASSERT(entry.pageID() != -1);
   1293         frame->loadHistoryItem(entry.contentState());
   1294     } else {
   1295         ASSERT(entry.pageID() == -1);
   1296         frame->loadRequest(WebURLRequest(entry.URL()));
   1297     }
   1298 
   1299     // In case LoadRequest failed before DidCreateDataSource was called.
   1300     setPendingExtraData(0);
   1301 
   1302     // Restore focus to the main frame prior to loading new request.
   1303     // This makes sure that we don't have a focused iframe. Otherwise, that
   1304     // iframe would keep focus when the SetFocus called immediately after
   1305     // LoadRequest, thus making some tests fail (see http://b/issue?id=845337
   1306     // for more details).
   1307     webView()->setFocusedFrame(frame);
   1308     m_shell->setFocus(webView(), true);
   1309 
   1310     return true;
   1311 }
   1312 
   1313 // Private functions ----------------------------------------------------------
   1314 
   1315 LayoutTestController* WebViewHost::layoutTestController() const
   1316 {
   1317     return m_shell->layoutTestController();
   1318 }
   1319 
   1320 void WebViewHost::updateAddressBar(WebView* webView)
   1321 {
   1322     WebFrame* mainFrame = webView->mainFrame();
   1323     WebDataSource* dataSource = mainFrame->dataSource();
   1324     if (!dataSource)
   1325         dataSource = mainFrame->provisionalDataSource();
   1326     if (!dataSource)
   1327         return;
   1328 
   1329     setAddressBarURL(dataSource->request().url());
   1330 }
   1331 
   1332 void WebViewHost::locationChangeDone(WebFrame* frame)
   1333 {
   1334     if (frame != m_topLoadingFrame)
   1335         return;
   1336     m_topLoadingFrame = 0;
   1337     layoutTestController()->locationChangeDone();
   1338 }
   1339 
   1340 void WebViewHost::updateForCommittedLoad(WebFrame* frame, bool isNewNavigation)
   1341 {
   1342     // Code duplicated from RenderView::DidCommitLoadForFrame.
   1343     TestShellExtraData* extraData = static_cast<TestShellExtraData*>(frame->dataSource()->extraData());
   1344 
   1345     if (isNewNavigation) {
   1346         // New navigation.
   1347         updateSessionHistory(frame);
   1348         m_pageId = nextPageID++;
   1349     } else if (extraData && extraData->pendingPageID != -1 && !extraData->requestCommitted) {
   1350         // This is a successful session history navigation!
   1351         updateSessionHistory(frame);
   1352         m_pageId = extraData->pendingPageID;
   1353     }
   1354 
   1355     // Don't update session history multiple times.
   1356     if (extraData)
   1357         extraData->requestCommitted = true;
   1358 
   1359     updateURL(frame);
   1360 }
   1361 
   1362 void WebViewHost::updateURL(WebFrame* frame)
   1363 {
   1364     WebDataSource* ds = frame->dataSource();
   1365     ASSERT(ds);
   1366     const WebURLRequest& request = ds->request();
   1367     RefPtr<TestNavigationEntry> entry(TestNavigationEntry::create());
   1368 
   1369     // The referrer will be empty on https->http transitions. It
   1370     // would be nice if we could get the real referrer from somewhere.
   1371     entry->setPageID(m_pageId);
   1372     if (ds->hasUnreachableURL())
   1373         entry->setURL(ds->unreachableURL());
   1374     else
   1375         entry->setURL(request.url());
   1376 
   1377     const WebHistoryItem& historyItem = frame->currentHistoryItem();
   1378     if (!historyItem.isNull())
   1379         entry->setContentState(historyItem);
   1380 
   1381     navigationController()->didNavigateToEntry(entry.get());
   1382     updateAddressBar(frame->view());
   1383     m_lastPageIdUpdated = max(m_lastPageIdUpdated, m_pageId);
   1384 }
   1385 
   1386 void WebViewHost::updateSessionHistory(WebFrame* frame)
   1387 {
   1388     // If we have a valid page ID at this point, then it corresponds to the page
   1389     // we are navigating away from.  Otherwise, this is the first navigation, so
   1390     // there is no past session history to record.
   1391     if (m_pageId == -1)
   1392         return;
   1393 
   1394     TestNavigationEntry* entry = navigationController()->entryWithPageID(m_pageId);
   1395     if (!entry)
   1396         return;
   1397 
   1398     const WebHistoryItem& historyItem = webView()->mainFrame()->previousHistoryItem();
   1399     if (historyItem.isNull())
   1400         return;
   1401 
   1402     entry->setContentState(historyItem);
   1403 }
   1404 
   1405 void WebViewHost::printFrameDescription(WebFrame* webframe)
   1406 {
   1407     string name8 = webframe->name().utf8();
   1408     if (webframe == webView()->mainFrame()) {
   1409         if (!name8.length()) {
   1410             fputs("main frame", stdout);
   1411             return;
   1412         }
   1413         printf("main frame \"%s\"", name8.c_str());
   1414         return;
   1415     }
   1416     if (!name8.length()) {
   1417         fputs("frame (anonymous)", stdout);
   1418         return;
   1419     }
   1420     printf("frame \"%s\"", name8.c_str());
   1421 }
   1422 
   1423 void WebViewHost::printFrameUserGestureStatus(WebFrame* webframe, const char* msg)
   1424 {
   1425     bool isUserGesture = webframe->isProcessingUserGesture();
   1426     printf("Frame with user gesture \"%s\"%s", isUserGesture ? "true" : "false", msg);
   1427 }
   1428 
   1429 void WebViewHost::printResourceDescription(unsigned identifier)
   1430 {
   1431     ResourceMap::iterator it = m_resourceIdentifierMap.find(identifier);
   1432     printf("%s", it != m_resourceIdentifierMap.end() ? it->second.c_str() : "<unknown>");
   1433 }
   1434 
   1435 void WebViewHost::setPendingExtraData(TestShellExtraData* extraData)
   1436 {
   1437     m_pendingExtraData.set(extraData);
   1438 }
   1439 
   1440 void WebViewHost::setPageTitle(const WebString&)
   1441 {
   1442     // Nothing to do in layout test.
   1443 }
   1444 
   1445 void WebViewHost::setAddressBarURL(const WebURL&)
   1446 {
   1447     // Nothing to do in layout test.
   1448 }
   1449 
   1450 // Painting functions ---------------------------------------------------------
   1451 
   1452 void WebViewHost::updatePaintRect(const WebRect& rect)
   1453 {
   1454     // m_paintRect = m_paintRect U rect
   1455     if (rect.isEmpty())
   1456         return;
   1457     if (m_paintRect.isEmpty()) {
   1458         m_paintRect = rect;
   1459         return;
   1460     }
   1461     int left = min(m_paintRect.x, rect.x);
   1462     int top = min(m_paintRect.y, rect.y);
   1463     int right = max(m_paintRect.x + m_paintRect.width, rect.x + rect.width);
   1464     int bottom = max(m_paintRect.y + m_paintRect.height, rect.y + rect.height);
   1465     m_paintRect = WebRect(left, top, right - left, bottom - top);
   1466 }
   1467 
   1468 void WebViewHost::paintRect(const WebRect& rect)
   1469 {
   1470     ASSERT(!m_isPainting);
   1471     ASSERT(canvas());
   1472     m_isPainting = true;
   1473 #if USE(CG)
   1474     webWidget()->paint(skia::BeginPlatformPaint(canvas()), rect);
   1475     skia::EndPlatformPaint(canvas());
   1476 #else
   1477     webWidget()->paint(canvas(), rect);
   1478 #endif
   1479     m_isPainting = false;
   1480 }
   1481 
   1482 void WebViewHost::paintInvalidatedRegion()
   1483 {
   1484 #if ENABLE(REQUEST_ANIMATION_FRAME)
   1485     webWidget()->animate();
   1486 #endif
   1487     webWidget()->layout();
   1488     WebSize widgetSize = webWidget()->size();
   1489     WebRect clientRect(0, 0, widgetSize.width, widgetSize.height);
   1490 
   1491     // Paint the canvas if necessary.  Allow painting to generate extra rects
   1492     // for the first two calls. This is necessary because some WebCore rendering
   1493     // objects update their layout only when painted.
   1494     // Store the total area painted in total_paint. Then tell the gdk window
   1495     // to update that area after we're done painting it.
   1496     for (int i = 0; i < 3; ++i) {
   1497         // m_paintRect = intersect(m_paintRect , clientRect)
   1498         int left = max(m_paintRect.x, clientRect.x);
   1499         int top = max(m_paintRect.y, clientRect.y);
   1500         int right = min(m_paintRect.x + m_paintRect.width, clientRect.x + clientRect.width);
   1501         int bottom = min(m_paintRect.y + m_paintRect.height, clientRect.y + clientRect.height);
   1502         if (left >= right || top >= bottom)
   1503             m_paintRect = WebRect();
   1504         else
   1505             m_paintRect = WebRect(left, top, right - left, bottom - top);
   1506 
   1507         if (m_paintRect.isEmpty())
   1508             continue;
   1509         WebRect rect(m_paintRect);
   1510         m_paintRect = WebRect();
   1511         paintRect(rect);
   1512     }
   1513     ASSERT(m_paintRect.isEmpty());
   1514 }
   1515 
   1516 SkCanvas* WebViewHost::canvas()
   1517 {
   1518     if (m_canvas)
   1519         return m_canvas.get();
   1520     WebSize widgetSize = webWidget()->size();
   1521     resetScrollRect();
   1522     m_canvas.set(skia::CreateBitmapCanvas(
   1523         widgetSize.width, widgetSize.height, true));
   1524     return m_canvas.get();
   1525 }
   1526 
   1527 void WebViewHost::resetScrollRect()
   1528 {
   1529 }
   1530 
   1531 void WebViewHost::discardBackingStore()
   1532 {
   1533     m_canvas.clear();
   1534 }
   1535 
   1536 // Paints the entire canvas a semi-transparent black (grayish). This is used
   1537 // by the layout tests in fast/repaint. The alpha value matches upstream.
   1538 void WebViewHost::displayRepaintMask()
   1539 {
   1540     canvas()->drawARGB(167, 0, 0, 0);
   1541 }
   1542