WebKitTools/DumpRenderTree/chromium/WebViewHost.cpp
changeset 2 303757a437d3
parent 0 4f2f89ce4247
equal deleted inserted replaced
0:4f2f89ce4247 2:303757a437d3
     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 "net/base/net_errors.h" // FIXME: can we remove this?
       
    39 #include "public/WebCString.h"
       
    40 #include "public/WebConsoleMessage.h"
       
    41 #include "public/WebContextMenuData.h"
       
    42 #include "public/WebDataSource.h"
       
    43 #include "public/WebDragData.h"
       
    44 #include "public/WebFrame.h"
       
    45 #include "public/WebGeolocationServiceMock.h"
       
    46 #include "public/WebHistoryItem.h"
       
    47 #include "public/WebNode.h"
       
    48 #include "public/WebRange.h"
       
    49 #include "public/WebRect.h"
       
    50 #include "public/WebScreenInfo.h"
       
    51 #include "public/WebSize.h"
       
    52 #include "public/WebStorageNamespace.h"
       
    53 #include "public/WebURLRequest.h"
       
    54 #include "public/WebURLResponse.h"
       
    55 #include "public/WebView.h"
       
    56 #include "public/WebWindowFeatures.h"
       
    57 #include "skia/ext/platform_canvas.h"
       
    58 #include "webkit/support/webkit_support.h"
       
    59 #include <wtf/Assertions.h>
       
    60 #include <wtf/PassOwnPtr.h>
       
    61 
       
    62 using namespace WebCore;
       
    63 using namespace WebKit;
       
    64 using namespace skia;
       
    65 using namespace std;
       
    66 
       
    67 static const int screenWidth = 1920;
       
    68 static const int screenHeight = 1080;
       
    69 static const int screenUnavailableBorder = 8;
       
    70 
       
    71 // WebNavigationType debugging strings taken from PolicyDelegate.mm.
       
    72 static const char* linkClickedString = "link clicked";
       
    73 static const char* formSubmittedString = "form submitted";
       
    74 static const char* backForwardString = "back/forward";
       
    75 static const char* reloadString = "reload";
       
    76 static const char* formResubmittedString = "form resubmitted";
       
    77 static const char* otherString = "other";
       
    78 static const char* illegalString = "illegal value";
       
    79 
       
    80 static int nextPageID = 1;
       
    81 
       
    82 // Used to write a platform neutral file:/// URL by only taking the filename
       
    83 // (e.g., converts "file:///tmp/foo.txt" to just "foo.txt").
       
    84 static string urlSuitableForTestResult(const string& url)
       
    85 {
       
    86     if (url.empty() || string::npos == url.find("file://"))
       
    87         return url;
       
    88 
       
    89     size_t pos = url.rfind('/');
       
    90     if (pos == string::npos) {
       
    91 #if OS(WINDOWS)
       
    92         pos = url.rfind('\\');
       
    93         if (pos == string::npos)
       
    94             pos = 0;
       
    95 #else
       
    96         pos = 0;
       
    97 #endif
       
    98     }
       
    99     string filename = url.substr(pos + 1);
       
   100     if (filename.empty())
       
   101         return "file:"; // A WebKit test has this in its expected output.
       
   102     return filename;
       
   103 }
       
   104 
       
   105 // Used to write a platform neutral file:/// URL by taking the
       
   106 // filename and its directory. (e.g., converts
       
   107 // "file:///tmp/foo/bar.txt" to just "bar.txt").
       
   108 static string descriptionSuitableForTestResult(const string& url)
       
   109 {
       
   110     if (url.empty() || string::npos == url.find("file://"))
       
   111         return url;
       
   112 
       
   113     size_t pos = url.rfind('/');
       
   114     if (pos == string::npos || !pos)
       
   115         return "ERROR:" + url;
       
   116     pos = url.rfind('/', pos - 1);
       
   117     if (pos == string::npos)
       
   118         return "ERROR:" + url;
       
   119 
       
   120     return url.substr(pos + 1);
       
   121 }
       
   122 
       
   123 // Adds a file called "DRTFakeFile" to |data_object| (CF_HDROP).  Use to fake
       
   124 // dragging a file.
       
   125 static void addDRTFakeFileToDataObject(WebDragData* dragData)
       
   126 {
       
   127     dragData->appendToFileNames(WebString::fromUTF8("DRTFakeFile"));
       
   128 }
       
   129 
       
   130 // Get a debugging string from a WebNavigationType.
       
   131 static const char* webNavigationTypeToString(WebNavigationType type)
       
   132 {
       
   133     switch (type) {
       
   134     case WebKit::WebNavigationTypeLinkClicked:
       
   135         return linkClickedString;
       
   136     case WebKit::WebNavigationTypeFormSubmitted:
       
   137         return formSubmittedString;
       
   138     case WebKit::WebNavigationTypeBackForward:
       
   139         return backForwardString;
       
   140     case WebKit::WebNavigationTypeReload:
       
   141         return reloadString;
       
   142     case WebKit::WebNavigationTypeFormResubmitted:
       
   143         return formResubmittedString;
       
   144     case WebKit::WebNavigationTypeOther:
       
   145         return otherString;
       
   146     }
       
   147     return illegalString;
       
   148 }
       
   149 
       
   150 static string URLDescription(const GURL& url)
       
   151 {
       
   152     if (url.SchemeIs("file"))
       
   153         return url.ExtractFileName();
       
   154     return url.possibly_invalid_spec();
       
   155 }
       
   156 
       
   157 static void printResponseDescription(const WebURLResponse& response)
       
   158 {
       
   159     if (response.isNull()) {
       
   160         fputs("(null)", stdout);
       
   161         return;
       
   162     }
       
   163     string url = response.url().spec();
       
   164     printf("<NSURLResponse %s, http status code %d>",
       
   165            descriptionSuitableForTestResult(url).c_str(),
       
   166            response.httpStatusCode());
       
   167 }
       
   168 
       
   169 static void printErrorDescription(const WebURLError& error)
       
   170 {
       
   171     string domain = error.domain.utf8();
       
   172     int code = error.reason;
       
   173 
       
   174     if (domain == net::kErrorDomain) {
       
   175         domain = "NSURLErrorDomain";
       
   176         switch (error.reason) {
       
   177         case net::ERR_ABORTED:
       
   178             code = -999;
       
   179             break;
       
   180         case net::ERR_UNSAFE_PORT:
       
   181             // Our unsafe port checking happens at the network stack level, but we
       
   182             // make this translation here to match the behavior of stock WebKit.
       
   183             domain = "WebKitErrorDomain";
       
   184             code = 103;
       
   185             break;
       
   186         case net::ERR_ADDRESS_INVALID:
       
   187         case net::ERR_ADDRESS_UNREACHABLE:
       
   188             code = -1004;
       
   189             break;
       
   190         }
       
   191     } else
       
   192         LOG_ERROR("Unknown error domain");
       
   193 
       
   194     printf("<NSError domain %s, code %d, failing URL \"%s\">",
       
   195            domain.c_str(), code, error.unreachableURL.spec().data());
       
   196 }
       
   197 
       
   198 static void printNodeDescription(const WebNode& node, int exception)
       
   199 {
       
   200     if (exception) {
       
   201         fputs("ERROR", stdout);
       
   202         return;
       
   203     }
       
   204     if (node.isNull()) {
       
   205         fputs("(null)", stdout);
       
   206         return;
       
   207     }
       
   208     fputs(node.nodeName().utf8().data(), stdout);
       
   209     const WebNode& parent = node.parentNode();
       
   210     if (!parent.isNull()) {
       
   211         fputs(" > ", stdout);
       
   212         printNodeDescription(parent, 0);
       
   213     }
       
   214 }
       
   215 
       
   216 static void printRangeDescription(const WebRange& range)
       
   217 {
       
   218     if (range.isNull()) {
       
   219         fputs("(null)", stdout);
       
   220         return;
       
   221     }
       
   222     printf("range from %d of ", range.startOffset());
       
   223     int exception = 0;
       
   224     WebNode startNode = range.startContainer(exception);
       
   225     printNodeDescription(startNode, exception);
       
   226     printf(" to %d of ", range.endOffset());
       
   227     WebNode endNode = range.endContainer(exception);
       
   228     printNodeDescription(endNode, exception);
       
   229 }
       
   230 
       
   231 static string editingActionDescription(WebEditingAction action)
       
   232 {
       
   233     switch (action) {
       
   234     case WebKit::WebEditingActionTyped:
       
   235         return "WebViewInsertActionTyped";
       
   236     case WebKit::WebEditingActionPasted:
       
   237         return "WebViewInsertActionPasted";
       
   238     case WebKit::WebEditingActionDropped:
       
   239         return "WebViewInsertActionDropped";
       
   240     }
       
   241     return "(UNKNOWN ACTION)";
       
   242 }
       
   243 
       
   244 static string textAffinityDescription(WebTextAffinity affinity)
       
   245 {
       
   246     switch (affinity) {
       
   247     case WebKit::WebTextAffinityUpstream:
       
   248         return "NSSelectionAffinityUpstream";
       
   249     case WebKit::WebTextAffinityDownstream:
       
   250         return "NSSelectionAffinityDownstream";
       
   251     }
       
   252     return "(UNKNOWN AFFINITY)";
       
   253 }
       
   254 
       
   255 // WebViewClient -------------------------------------------------------------
       
   256 
       
   257 WebView* WebViewHost::createView(WebFrame*, const WebWindowFeatures&, const WebString&)
       
   258 {
       
   259     if (!layoutTestController()->canOpenWindows())
       
   260         return 0;
       
   261     return m_shell->createWebView()->webView();
       
   262 }
       
   263 
       
   264 WebWidget* WebViewHost::createPopupMenu(WebPopupType)
       
   265 {
       
   266     return 0;
       
   267 }
       
   268 
       
   269 WebWidget* WebViewHost::createPopupMenu(const WebPopupMenuInfo&)
       
   270 {
       
   271     return 0;
       
   272 }
       
   273 
       
   274 WebStorageNamespace* WebViewHost::createSessionStorageNamespace(unsigned quota)
       
   275 {
       
   276     return WebKit::WebStorageNamespace::createSessionStorageNamespace(quota);
       
   277 }
       
   278 
       
   279 void WebViewHost::didAddMessageToConsole(const WebConsoleMessage& message, const WebString& sourceName, unsigned sourceLine)
       
   280 {
       
   281     // This matches win DumpRenderTree's UIDelegate.cpp.
       
   282     string newMessage;
       
   283     if (!message.text.isEmpty()) {
       
   284         newMessage = message.text.utf8();
       
   285         size_t fileProtocol = newMessage.find("file://");
       
   286         if (fileProtocol != string::npos) {
       
   287             newMessage = newMessage.substr(0, fileProtocol)
       
   288                 + urlSuitableForTestResult(newMessage.substr(fileProtocol));
       
   289         }
       
   290     }
       
   291     printf("CONSOLE MESSAGE: line %d: %s\n", sourceLine, newMessage.data());
       
   292 }
       
   293 
       
   294 void WebViewHost::didStartLoading()
       
   295 {
       
   296     m_shell->setIsLoading(true);
       
   297 }
       
   298 
       
   299 void WebViewHost::didStopLoading()
       
   300 {
       
   301     m_shell->setIsLoading(false);
       
   302 }
       
   303 
       
   304 // The output from these methods in layout test mode should match that
       
   305 // expected by the layout tests.  See EditingDelegate.m in DumpRenderTree.
       
   306 
       
   307 bool WebViewHost::shouldBeginEditing(const WebRange& range)
       
   308 {
       
   309     if (layoutTestController()->shouldDumpEditingCallbacks()) {
       
   310         fputs("EDITING DELEGATE: shouldBeginEditingInDOMRange:", stdout);
       
   311         printRangeDescription(range);
       
   312         fputs("\n", stdout);
       
   313     }
       
   314     return layoutTestController()->acceptsEditing();
       
   315 }
       
   316 
       
   317 bool WebViewHost::shouldEndEditing(const WebRange& range)
       
   318 {
       
   319     if (layoutTestController()->shouldDumpEditingCallbacks()) {
       
   320         fputs("EDITING DELEGATE: shouldEndEditingInDOMRange:", stdout);
       
   321         printRangeDescription(range);
       
   322         fputs("\n", stdout);
       
   323     }
       
   324     return layoutTestController()->acceptsEditing();
       
   325 }
       
   326 
       
   327 bool WebViewHost::shouldInsertNode(const WebNode& node, const WebRange& range, WebEditingAction action)
       
   328 {
       
   329     if (layoutTestController()->shouldDumpEditingCallbacks()) {
       
   330         fputs("EDITING DELEGATE: shouldInsertNode:", stdout);
       
   331         printNodeDescription(node, 0);
       
   332         fputs(" replacingDOMRange:", stdout);
       
   333         printRangeDescription(range);
       
   334         printf(" givenAction:%s\n", editingActionDescription(action).c_str());
       
   335     }
       
   336     return layoutTestController()->acceptsEditing();
       
   337 }
       
   338 
       
   339 bool WebViewHost::shouldInsertText(const WebString& text, const WebRange& range, WebEditingAction action)
       
   340 {
       
   341     if (layoutTestController()->shouldDumpEditingCallbacks()) {
       
   342         printf("EDITING DELEGATE: shouldInsertText:%s replacingDOMRange:", text.utf8().data());
       
   343         printRangeDescription(range);
       
   344         printf(" givenAction:%s\n", editingActionDescription(action).c_str());
       
   345     }
       
   346     return layoutTestController()->acceptsEditing();
       
   347 }
       
   348 
       
   349 bool WebViewHost::shouldChangeSelectedRange(
       
   350     const WebRange& fromRange, const WebRange& toRange, WebTextAffinity affinity, bool stillSelecting)
       
   351 {
       
   352     if (layoutTestController()->shouldDumpEditingCallbacks()) {
       
   353         fputs("EDITING DELEGATE: shouldChangeSelectedDOMRange:", stdout);
       
   354         printRangeDescription(fromRange);
       
   355         fputs(" toDOMRange:", stdout);
       
   356         printRangeDescription(toRange);
       
   357         printf(" affinity:%s stillSelecting:%s\n",
       
   358                textAffinityDescription(affinity).c_str(),
       
   359                (stillSelecting ? "TRUE" : "FALSE"));
       
   360     }
       
   361     return layoutTestController()->acceptsEditing();
       
   362 }
       
   363 
       
   364 bool WebViewHost::shouldDeleteRange(const WebRange& range)
       
   365 {
       
   366     if (layoutTestController()->shouldDumpEditingCallbacks()) {
       
   367         fputs("EDITING DELEGATE: shouldDeleteDOMRange:", stdout);
       
   368         printRangeDescription(range);
       
   369         fputs("\n", stdout);
       
   370     }
       
   371     return layoutTestController()->acceptsEditing();
       
   372 }
       
   373 
       
   374 bool WebViewHost::shouldApplyStyle(const WebString& style, const WebRange& range)
       
   375 {
       
   376     if (layoutTestController()->shouldDumpEditingCallbacks()) {
       
   377         printf("EDITING DELEGATE: shouldApplyStyle:%s toElementsInDOMRange:", style.utf8().data());
       
   378         printRangeDescription(range);
       
   379         fputs("\n", stdout);
       
   380     }
       
   381     return layoutTestController()->acceptsEditing();
       
   382 }
       
   383 
       
   384 bool WebViewHost::isSmartInsertDeleteEnabled()
       
   385 {
       
   386     return m_smartInsertDeleteEnabled;
       
   387 }
       
   388 
       
   389 bool WebViewHost::isSelectTrailingWhitespaceEnabled()
       
   390 {
       
   391     return m_selectTrailingWhitespaceEnabled;
       
   392 }
       
   393 
       
   394 void WebViewHost::didBeginEditing()
       
   395 {
       
   396     if (!layoutTestController()->shouldDumpEditingCallbacks())
       
   397         return;
       
   398     fputs("EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification\n", stdout);
       
   399 }
       
   400 
       
   401 void WebViewHost::didChangeSelection(bool isEmptySelection)
       
   402 {
       
   403     if (layoutTestController()->shouldDumpEditingCallbacks())
       
   404         fputs("EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification\n", stdout);
       
   405     // No need to update clipboard with the selected text in DRT.
       
   406 }
       
   407 
       
   408 void WebViewHost::didChangeContents()
       
   409 {
       
   410     if (!layoutTestController()->shouldDumpEditingCallbacks())
       
   411         return;
       
   412     fputs("EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification\n", stdout);
       
   413 }
       
   414 
       
   415 void WebViewHost::didEndEditing()
       
   416 {
       
   417     if (!layoutTestController()->shouldDumpEditingCallbacks())
       
   418         return;
       
   419     fputs("EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification\n", stdout);
       
   420 }
       
   421 
       
   422 bool WebViewHost::handleCurrentKeyboardEvent()
       
   423 {
       
   424     if (m_editCommandName.empty())
       
   425         return false;
       
   426     WebFrame* frame = webView()->focusedFrame();
       
   427     if (!frame)
       
   428         return false;
       
   429 
       
   430     return frame->executeCommand(WebString::fromUTF8(m_editCommandName), WebString::fromUTF8(m_editCommandValue));
       
   431 }
       
   432 
       
   433 void WebViewHost::spellCheck(const WebString& text, int& misspelledOffset, int& misspelledLength)
       
   434 {
       
   435     // Check the spelling of the given text.
       
   436 #if OS(MAC_OS_X)
       
   437     // FIXME: rebaseline layout-test results of Windows and Linux so we
       
   438     // can enable this mock spellchecker on them.
       
   439     m_spellcheck.spellCheckWord(text, &misspelledOffset, &misspelledLength);
       
   440 #endif
       
   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&)
       
   476 {
       
   477 }
       
   478 
       
   479 
       
   480 void WebViewHost::setStatusText(const WebString& text)
       
   481 {
       
   482     if (!layoutTestController()->shouldDumpStatusCallbacks())
       
   483         return;
       
   484     // When running tests, write to stdout.
       
   485     printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", text.utf8().data());
       
   486 }
       
   487 
       
   488 void WebViewHost::startDragging(const WebDragData& data, WebDragOperationsMask mask, const WebImage&, const WebPoint&)
       
   489 {
       
   490     WebDragData mutableDragData = data;
       
   491     if (layoutTestController()->shouldAddFileToPasteboard()) {
       
   492         // Add a file called DRTFakeFile to the drag&drop clipboard.
       
   493         addDRTFakeFileToDataObject(&mutableDragData);
       
   494     }
       
   495 
       
   496     // When running a test, we need to fake a drag drop operation otherwise
       
   497     // Windows waits for real mouse events to know when the drag is over.
       
   498     m_shell->eventSender()->doDragDrop(mutableDragData, mask);
       
   499 }
       
   500 
       
   501 void WebViewHost::navigateBackForwardSoon(int offset)
       
   502 {
       
   503     navigationController()->goToOffset(offset);
       
   504 }
       
   505 
       
   506 int WebViewHost::historyBackListCount()
       
   507 {
       
   508     return navigationController()->lastCommittedEntryIndex();
       
   509 }
       
   510 
       
   511 int WebViewHost::historyForwardListCount()
       
   512 {
       
   513     int currentIndex =navigationController()->lastCommittedEntryIndex();
       
   514     return navigationController()->entryCount() - currentIndex - 1;
       
   515 }
       
   516 
       
   517 void WebViewHost::focusAccessibilityObject(const WebAccessibilityObject& object)
       
   518 {
       
   519     m_shell->accessibilityController()->setFocusedElement(object);
       
   520 }
       
   521 
       
   522 WebNotificationPresenter* WebViewHost::notificationPresenter()
       
   523 {
       
   524     return m_shell->notificationPresenter();
       
   525 }
       
   526 
       
   527 WebKit::WebGeolocationService* WebViewHost::geolocationService()
       
   528 {
       
   529     if (!m_geolocationServiceMock.get())
       
   530         m_geolocationServiceMock.set(WebGeolocationServiceMock::createWebGeolocationServiceMock());
       
   531     return m_geolocationServiceMock.get();
       
   532 }
       
   533 
       
   534 // WebWidgetClient -----------------------------------------------------------
       
   535 
       
   536 void WebViewHost::didInvalidateRect(const WebRect& rect)
       
   537 {
       
   538     if (m_isPainting)
       
   539         LOG_ERROR("unexpected invalidation while painting");
       
   540     updatePaintRect(rect);
       
   541 }
       
   542 
       
   543 void WebViewHost::didScrollRect(int, int, const WebRect& clipRect)
       
   544 {
       
   545     // This is used for optimizing painting when the renderer is scrolled. We're
       
   546     // currently not doing any optimizations so just invalidate the region.
       
   547     didInvalidateRect(clipRect);
       
   548 }
       
   549 
       
   550 void WebViewHost::didFocus()
       
   551 {
       
   552     m_shell->setFocus(webWidget(), true);
       
   553 }
       
   554 
       
   555 void WebViewHost::didBlur()
       
   556 {
       
   557     m_shell->setFocus(webWidget(), false);
       
   558 }
       
   559 
       
   560 WebScreenInfo WebViewHost::screenInfo()
       
   561 {
       
   562     // We don't need to set actual values.
       
   563     WebScreenInfo info;
       
   564     info.depth = 24;
       
   565     info.depthPerComponent = 8;
       
   566     info.isMonochrome = false;
       
   567     info.rect = WebRect(0, 0, screenWidth, screenHeight);
       
   568     // Use values different from info.rect for testing.
       
   569     info.availableRect = WebRect(screenUnavailableBorder, screenUnavailableBorder,
       
   570                                  screenWidth - screenUnavailableBorder * 2,
       
   571                                  screenHeight - screenUnavailableBorder * 2);
       
   572     return info;
       
   573 }
       
   574 
       
   575 void WebViewHost::show(WebNavigationPolicy)
       
   576 {
       
   577     m_hasWindow = true;
       
   578     WebSize size = webWidget()->size();
       
   579     updatePaintRect(WebRect(0, 0, size.width, size.height));
       
   580 }
       
   581 
       
   582 void WebViewHost::closeWidgetSoon()
       
   583 {
       
   584     m_hasWindow = false;
       
   585     m_shell->closeWindow(this);
       
   586 }
       
   587 
       
   588 void WebViewHost::didChangeCursor(const WebCursorInfo& cursorInfo)
       
   589 {
       
   590     if (!hasWindow())
       
   591         return;
       
   592     m_currentCursor = cursorInfo;
       
   593 }
       
   594 
       
   595 WebRect WebViewHost::windowRect()
       
   596 {
       
   597     return m_windowRect;
       
   598 }
       
   599 
       
   600 void WebViewHost::setWindowRect(const WebRect& rect)
       
   601 {
       
   602     m_windowRect = rect;
       
   603     const int border2 = TestShell::virtualWindowBorder * 2;
       
   604     if (m_windowRect.width <= border2)
       
   605         m_windowRect.width = 1 + border2;
       
   606     if (m_windowRect.height <= border2)
       
   607         m_windowRect.height = 1 + border2;
       
   608     int width = m_windowRect.width - border2;
       
   609     int height = m_windowRect.height - border2;
       
   610     discardBackingStore();
       
   611     webWidget()->resize(WebSize(width, height));
       
   612     updatePaintRect(WebRect(0, 0, width, height));
       
   613 }
       
   614 
       
   615 WebRect WebViewHost::rootWindowRect()
       
   616 {
       
   617     return windowRect();
       
   618 }
       
   619 
       
   620 WebRect WebViewHost::windowResizerRect()
       
   621 {
       
   622     // Not necessary.
       
   623     return WebRect();
       
   624 }
       
   625 
       
   626 void WebViewHost::runModal()
       
   627 {
       
   628     // FIXME: Should we implement this in DRT?
       
   629 }
       
   630 
       
   631 // WebFrameClient ------------------------------------------------------------
       
   632 
       
   633 WebPlugin* WebViewHost::createPlugin(WebFrame* frame, const WebPluginParams& params)
       
   634 {
       
   635     return webkit_support::CreateWebPlugin(frame, params);
       
   636 }
       
   637 
       
   638 WebWorker* WebViewHost::createWorker(WebFrame*, WebWorkerClient*)
       
   639 {
       
   640     return new TestWebWorker();
       
   641 }
       
   642 
       
   643 WebMediaPlayer* WebViewHost::createMediaPlayer(WebFrame* frame, WebMediaPlayerClient* client)
       
   644 {
       
   645     return webkit_support::CreateMediaPlayer(frame, client);
       
   646 }
       
   647 
       
   648 WebApplicationCacheHost* WebViewHost::createApplicationCacheHost(WebFrame* frame, WebApplicationCacheHostClient* client)
       
   649 {
       
   650     return webkit_support::CreateApplicationCacheHost(frame, client);
       
   651 }
       
   652 
       
   653 bool WebViewHost::allowPlugins(WebFrame* frame, bool enabledPerSettings)
       
   654 {
       
   655     return enabledPerSettings;
       
   656 }
       
   657 
       
   658 bool WebViewHost::allowImages(WebFrame* frame, bool enabledPerSettings)
       
   659 {
       
   660     return enabledPerSettings;
       
   661 }
       
   662 
       
   663 void WebViewHost::loadURLExternally(WebFrame*, const WebURLRequest& request, WebNavigationPolicy policy)
       
   664 {
       
   665     ASSERT(policy !=  WebKit::WebNavigationPolicyCurrentTab);
       
   666     WebViewHost* another = m_shell->createNewWindow(request.url());
       
   667     if (another)
       
   668         another->show(policy);
       
   669 }
       
   670 
       
   671 WebNavigationPolicy WebViewHost::decidePolicyForNavigation(
       
   672     WebFrame*, const WebURLRequest& request,
       
   673     WebNavigationType type, const WebNode& originatingNode,
       
   674     WebNavigationPolicy defaultPolicy, bool isRedirect)
       
   675 {
       
   676     WebNavigationPolicy result;
       
   677     if (!m_policyDelegateEnabled)
       
   678         return defaultPolicy;
       
   679 
       
   680     printf("Policy delegate: attempt to load %s with navigation type '%s'",
       
   681            URLDescription(request.url()).c_str(), webNavigationTypeToString(type));
       
   682     if (!originatingNode.isNull()) {
       
   683         fputs(" originating from ", stdout);
       
   684         printNodeDescription(originatingNode, 0);
       
   685     }
       
   686     fputs("\n", stdout);
       
   687     if (m_policyDelegateIsPermissive)
       
   688         result = WebKit::WebNavigationPolicyCurrentTab;
       
   689     else
       
   690         result = WebKit::WebNavigationPolicyIgnore;
       
   691 
       
   692     if (m_policyDelegateShouldNotifyDone)
       
   693         layoutTestController()->policyDelegateDone();
       
   694     return result;
       
   695 }
       
   696 
       
   697 bool WebViewHost::canHandleRequest(WebFrame*, const WebURLRequest& request)
       
   698 {
       
   699     GURL url = request.url();
       
   700     // Just reject the scheme used in
       
   701     // LayoutTests/http/tests/misc/redirect-to-external-url.html
       
   702     return !url.SchemeIs("spaceballs");
       
   703 }
       
   704 
       
   705 WebURLError WebViewHost::cannotHandleRequestError(WebFrame*, const WebURLRequest& request)
       
   706 {
       
   707     WebURLError error;
       
   708     // A WebKit layout test expects the following values.
       
   709     // unableToImplementPolicyWithError() below prints them.
       
   710     error.domain = WebString::fromUTF8("WebKitErrorDomain");
       
   711     error.reason = 101;
       
   712     error.unreachableURL = request.url();
       
   713     return error;
       
   714 }
       
   715 
       
   716 WebURLError WebViewHost::cancelledError(WebFrame*, const WebURLRequest& request)
       
   717 {
       
   718     WebURLError error;
       
   719     error.domain = WebString::fromUTF8(net::kErrorDomain);
       
   720     error.reason = net::ERR_ABORTED;
       
   721     error.unreachableURL = request.url();
       
   722     return error;
       
   723 }
       
   724 
       
   725 void WebViewHost::unableToImplementPolicyWithError(WebFrame* frame, const WebURLError& error)
       
   726 {
       
   727     printf("Policy delegate: unable to implement policy with error domain '%s', "
       
   728            "error code %d, in frame '%s'\n",
       
   729            error.domain.utf8().data(), error.reason, frame->name().utf8().data());
       
   730 }
       
   731 
       
   732 void WebViewHost::willPerformClientRedirect(WebFrame* frame, const WebURL& from, const WebURL& to,
       
   733                                             double interval, double fire_time)
       
   734 {
       
   735     if (!m_shell->shouldDumpFrameLoadCallbacks())
       
   736         return;
       
   737     printFrameDescription(frame);
       
   738     printf(" - willPerformClientRedirectToURL: %s \n", to.spec().data());
       
   739 }
       
   740 
       
   741 void WebViewHost::didCancelClientRedirect(WebFrame* frame)
       
   742 {
       
   743     if (!m_shell->shouldDumpFrameLoadCallbacks())
       
   744         return;
       
   745     printFrameDescription(frame);
       
   746     fputs(" - didCancelClientRedirectForFrame\n", stdout);
       
   747 }
       
   748 
       
   749 void WebViewHost::didCreateDataSource(WebFrame*, WebDataSource* ds)
       
   750 {
       
   751     ds->setExtraData(m_pendingExtraData.leakPtr());
       
   752 }
       
   753 
       
   754 void WebViewHost::didStartProvisionalLoad(WebFrame* frame)
       
   755 {
       
   756     if (m_shell->shouldDumpFrameLoadCallbacks()) {
       
   757         printFrameDescription(frame);
       
   758         fputs(" - didStartProvisionalLoadForFrame\n", stdout);
       
   759     }
       
   760 
       
   761     if (!m_topLoadingFrame)
       
   762         m_topLoadingFrame = frame;
       
   763 
       
   764     if (layoutTestController()->stopProvisionalFrameLoads()) {
       
   765         printFrameDescription(frame);
       
   766         fputs(" - stopping load in didStartProvisionalLoadForFrame callback\n", stdout);
       
   767         frame->stopLoading();
       
   768     }
       
   769     updateAddressBar(frame->view());
       
   770 }
       
   771 
       
   772 void WebViewHost::didReceiveServerRedirectForProvisionalLoad(WebFrame* frame)
       
   773 {
       
   774     if (m_shell->shouldDumpFrameLoadCallbacks()) {
       
   775         printFrameDescription(frame);
       
   776         fputs(" - didReceiveServerRedirectForProvisionalLoadForFrame\n", stdout);
       
   777     }
       
   778     updateAddressBar(frame->view());
       
   779 }
       
   780 
       
   781 void WebViewHost::didFailProvisionalLoad(WebFrame* frame, const WebURLError& error)
       
   782 {
       
   783     if (m_shell->shouldDumpFrameLoadCallbacks()) {
       
   784         printFrameDescription(frame);
       
   785         fputs(" - didFailProvisionalLoadWithError\n", stdout);
       
   786     }
       
   787 
       
   788     locationChangeDone(frame);
       
   789 
       
   790     // Don't display an error page if we're running layout tests, because
       
   791     // DumpRenderTree doesn't.
       
   792 }
       
   793 
       
   794 void WebViewHost::didCommitProvisionalLoad(WebFrame* frame, bool isNewNavigation)
       
   795 {
       
   796     if (m_shell->shouldDumpFrameLoadCallbacks()) {
       
   797         printFrameDescription(frame);
       
   798         fputs(" - didCommitLoadForFrame\n", stdout);
       
   799     }
       
   800     updateForCommittedLoad(frame, isNewNavigation);
       
   801 }
       
   802 
       
   803 void WebViewHost::didClearWindowObject(WebFrame* frame)
       
   804 {
       
   805     m_shell->bindJSObjectsToWindow(frame);
       
   806 }
       
   807 
       
   808 void WebViewHost::didReceiveTitle(WebFrame* frame, const WebString& title)
       
   809 {
       
   810     WebCString title8 = title.utf8();
       
   811 
       
   812     if (m_shell->shouldDumpFrameLoadCallbacks()) {
       
   813         printFrameDescription(frame);
       
   814         printf(" - didReceiveTitle: %s\n", title8.data());
       
   815     }
       
   816 
       
   817     if (layoutTestController()->shouldDumpTitleChanges())
       
   818         printf("TITLE CHANGED: %s\n", title8.data());
       
   819 
       
   820     setPageTitle(title);
       
   821 }
       
   822 
       
   823 void WebViewHost::didFinishDocumentLoad(WebFrame* frame)
       
   824 {
       
   825     if (m_shell->shouldDumpFrameLoadCallbacks()) {
       
   826         printFrameDescription(frame);
       
   827         fputs(" - didFinishDocumentLoadForFrame\n", stdout);
       
   828     } else {
       
   829         unsigned pendingUnloadEvents = frame->unloadListenerCount();
       
   830         if (pendingUnloadEvents) {
       
   831             printFrameDescription(frame);
       
   832             printf(" - has %u onunload handler(s)\n", pendingUnloadEvents);
       
   833         }
       
   834     }
       
   835 }
       
   836 
       
   837 void WebViewHost::didHandleOnloadEvents(WebFrame* frame)
       
   838 {
       
   839     if (m_shell->shouldDumpFrameLoadCallbacks()) {
       
   840         printFrameDescription(frame);
       
   841         fputs(" - didHandleOnloadEventsForFrame\n", stdout);
       
   842     }
       
   843 }
       
   844 
       
   845 void WebViewHost::didFailLoad(WebFrame* frame, const WebURLError& error)
       
   846 {
       
   847     if (m_shell->shouldDumpFrameLoadCallbacks()) {
       
   848         printFrameDescription(frame);
       
   849         fputs(" - didFailLoadWithError\n", stdout);
       
   850     }
       
   851     locationChangeDone(frame);
       
   852 }
       
   853 
       
   854 void WebViewHost::didFinishLoad(WebFrame* frame)
       
   855 {
       
   856     if (m_shell->shouldDumpFrameLoadCallbacks()) {
       
   857         printFrameDescription(frame);
       
   858         fputs(" - didFinishLoadForFrame\n", stdout);
       
   859     }
       
   860     updateAddressBar(frame->view());
       
   861     locationChangeDone(frame);
       
   862 }
       
   863 
       
   864 void WebViewHost::didNavigateWithinPage(WebFrame* frame, bool isNewNavigation)
       
   865 {
       
   866     frame->dataSource()->setExtraData(m_pendingExtraData.leakPtr());
       
   867 
       
   868     updateForCommittedLoad(frame, isNewNavigation);
       
   869 }
       
   870 
       
   871 void WebViewHost::didChangeLocationWithinPage(WebFrame* frame)
       
   872 {
       
   873     if (m_shell->shouldDumpFrameLoadCallbacks()) {
       
   874         printFrameDescription(frame);
       
   875         fputs(" - didChangeLocationWithinPageForFrame\n", stdout);
       
   876     }
       
   877 }
       
   878 
       
   879 void WebViewHost::assignIdentifierToRequest(WebFrame*, unsigned identifier, const WebURLRequest& request)
       
   880 {
       
   881     if (!m_shell->shouldDumpResourceLoadCallbacks())
       
   882         return;
       
   883     m_resourceIdentifierMap.set(identifier, descriptionSuitableForTestResult(request.url().spec()));
       
   884 }
       
   885 
       
   886 void WebViewHost::willSendRequest(WebFrame*, unsigned identifier, WebURLRequest& request, const WebURLResponse& redirectResponse)
       
   887 {
       
   888     // Need to use GURL for host() and SchemeIs()
       
   889     GURL url = request.url();
       
   890     string requestURL = url.possibly_invalid_spec();
       
   891 
       
   892     if (layoutTestController()->shouldDumpResourceLoadCallbacks()) {
       
   893         GURL mainDocumentURL = request.firstPartyForCookies();
       
   894         printResourceDescription(identifier);
       
   895         printf(" - willSendRequest <NSURLRequest URL %s, main document URL %s,"
       
   896                " http method %s> redirectResponse ",
       
   897                descriptionSuitableForTestResult(requestURL).c_str(),
       
   898                URLDescription(mainDocumentURL).c_str(),
       
   899                request.httpMethod().utf8().data());
       
   900         printResponseDescription(redirectResponse);
       
   901         fputs("\n", stdout);
       
   902     }
       
   903 
       
   904     if (!redirectResponse.isNull() && m_blocksRedirects) {
       
   905         fputs("Returning null for this redirect\n", stdout);
       
   906         // To block the request, we set its URL to an empty one.
       
   907         request.setURL(WebURL());
       
   908         return;
       
   909     }
       
   910 
       
   911     if (m_requestReturnNull) {
       
   912         // To block the request, we set its URL to an empty one.
       
   913         request.setURL(WebURL());
       
   914         return;
       
   915     }
       
   916 
       
   917     string host = url.host();
       
   918     // 255.255.255.255 is used in some tests that expect to get back an error.
       
   919     if (!host.empty() && (url.SchemeIs("http") || url.SchemeIs("https"))
       
   920         && host != "127.0.0.1"
       
   921         && host != "255.255.255.255"
       
   922         && host != "localhost"
       
   923         && !m_shell->allowExternalPages()) {
       
   924         printf("Blocked access to external URL %s\n", requestURL.c_str());
       
   925 
       
   926         // To block the request, we set its URL to an empty one.
       
   927         request.setURL(WebURL());
       
   928         return;
       
   929     }
       
   930 
       
   931     HashSet<String>::const_iterator end = m_clearHeaders.end();
       
   932     for (HashSet<String>::const_iterator header = m_clearHeaders.begin(); header != end; ++header)
       
   933         request.clearHTTPHeaderField(WebString(header->characters(), header->length()));
       
   934 
       
   935     // Set the new substituted URL.
       
   936     request.setURL(webkit_support::RewriteLayoutTestsURL(request.url().spec()));
       
   937 }
       
   938 
       
   939 void WebViewHost::didReceiveResponse(WebFrame*, unsigned identifier, const WebURLResponse& response)
       
   940 {
       
   941     if (!m_shell->shouldDumpResourceLoadCallbacks())
       
   942         return;
       
   943     printResourceDescription(identifier);
       
   944     fputs(" - didReceiveResponse ", stdout);
       
   945     printResponseDescription(response);
       
   946     fputs("\n", stdout);
       
   947 }
       
   948 
       
   949 void WebViewHost::didFinishResourceLoad(WebFrame*, unsigned identifier)
       
   950 {
       
   951     if (m_shell->shouldDumpResourceLoadCallbacks()) {
       
   952         printResourceDescription(identifier);
       
   953         fputs(" - didFinishLoading\n", stdout);
       
   954     }
       
   955     m_resourceIdentifierMap.remove(identifier);
       
   956 }
       
   957 
       
   958 void WebViewHost::didFailResourceLoad(WebFrame*, unsigned identifier, const WebURLError& error)
       
   959 {
       
   960     if (m_shell->shouldDumpResourceLoadCallbacks()) {
       
   961         printResourceDescription(identifier);
       
   962         fputs(" - didFailLoadingWithError: ", stdout);
       
   963         printErrorDescription(error);
       
   964         fputs("\n", stdout);
       
   965     }
       
   966     m_resourceIdentifierMap.remove(identifier);
       
   967 }
       
   968 
       
   969 void WebViewHost::didDisplayInsecureContent(WebFrame*)
       
   970 {
       
   971     if (m_shell->shouldDumpFrameLoadCallbacks())
       
   972         fputs("didDisplayInsecureContent\n", stdout);
       
   973 }
       
   974 
       
   975 void WebViewHost::didRunInsecureContent(WebFrame*, const WebSecurityOrigin& origin)
       
   976 {
       
   977     if (m_shell->shouldDumpFrameLoadCallbacks())
       
   978         fputs("didRunInsecureContent\n", stdout);
       
   979 }
       
   980 
       
   981 bool WebViewHost::allowScript(WebFrame*, bool enabledPerSettings)
       
   982 {
       
   983     return enabledPerSettings;
       
   984 }
       
   985 
       
   986 // Public functions -----------------------------------------------------------
       
   987 
       
   988 WebViewHost::WebViewHost(TestShell* shell)
       
   989     : m_policyDelegateEnabled(false)
       
   990     , m_policyDelegateIsPermissive(false)
       
   991     , m_policyDelegateShouldNotifyDone(false)
       
   992     , m_shell(shell)
       
   993     , m_topLoadingFrame(0)
       
   994     , m_hasWindow(false)
       
   995     , m_pageId(-1)
       
   996     , m_lastPageIdUpdated(-1)
       
   997     , m_smartInsertDeleteEnabled(true)
       
   998 #if OS(WINDOWS)
       
   999     , m_selectTrailingWhitespaceEnabled(true)
       
  1000 #else
       
  1001     , m_selectTrailingWhitespaceEnabled(false)
       
  1002 #endif
       
  1003     , m_blocksRedirects(false)
       
  1004     , m_requestReturnNull(false)
       
  1005     , m_isPainting(false)
       
  1006     , m_webWidget(0)
       
  1007 {
       
  1008     m_navigationController.set(new TestNavigationController(this));
       
  1009 }
       
  1010 
       
  1011 WebViewHost::~WebViewHost()
       
  1012 {
       
  1013 }
       
  1014 
       
  1015 WebView* WebViewHost::webView() const
       
  1016 {
       
  1017     ASSERT(m_webWidget);
       
  1018     // DRT does not support popup widgets. So m_webWidget is always a WebView.
       
  1019     return static_cast<WebView*>(m_webWidget);
       
  1020 }
       
  1021 
       
  1022 WebWidget* WebViewHost::webWidget() const
       
  1023 {
       
  1024     ASSERT(m_webWidget);
       
  1025     return m_webWidget;
       
  1026 }
       
  1027 
       
  1028 void WebViewHost::reset()
       
  1029 {
       
  1030     // Do a little placement new dance...
       
  1031     TestShell* shell = m_shell;
       
  1032     WebWidget* widget = m_webWidget;
       
  1033     this->~WebViewHost();
       
  1034     new (this) WebViewHost(shell);
       
  1035     setWebWidget(widget);
       
  1036     webView()->mainFrame()->setName(WebString());
       
  1037 }
       
  1038 
       
  1039 void WebViewHost::setSelectTrailingWhitespaceEnabled(bool enabled)
       
  1040 {
       
  1041     m_selectTrailingWhitespaceEnabled = enabled;
       
  1042     // In upstream WebKit, smart insert/delete is mutually exclusive with select
       
  1043     // trailing whitespace, however, we allow both because Chromium on Windows
       
  1044     // allows both.
       
  1045 }
       
  1046 
       
  1047 void WebViewHost::setSmartInsertDeleteEnabled(bool enabled)
       
  1048 {
       
  1049     m_smartInsertDeleteEnabled = enabled;
       
  1050     // In upstream WebKit, smart insert/delete is mutually exclusive with select
       
  1051     // trailing whitespace, however, we allow both because Chromium on Windows
       
  1052     // allows both.
       
  1053 }
       
  1054 
       
  1055 void WebViewHost::setCustomPolicyDelegate(bool isCustom, bool isPermissive)
       
  1056 {
       
  1057     m_policyDelegateEnabled = isCustom;
       
  1058     m_policyDelegateIsPermissive = isPermissive;
       
  1059 }
       
  1060 
       
  1061 void WebViewHost::waitForPolicyDelegate()
       
  1062 {
       
  1063     m_policyDelegateEnabled = true;
       
  1064     m_policyDelegateShouldNotifyDone = true;
       
  1065 }
       
  1066 
       
  1067 void WebViewHost::setEditCommand(const string& name, const string& value)
       
  1068 {
       
  1069     m_editCommandName = name;
       
  1070     m_editCommandValue = value;
       
  1071 }
       
  1072 
       
  1073 void WebViewHost::clearEditCommand()
       
  1074 {
       
  1075     m_editCommandName.clear();
       
  1076     m_editCommandValue.clear();
       
  1077 }
       
  1078 
       
  1079 void WebViewHost::loadURLForFrame(const WebURL& url, const WebString& frameName)
       
  1080 {
       
  1081     if (!url.isValid())
       
  1082         return;
       
  1083     TestShell::resizeWindowForTest(this, url);
       
  1084     navigationController()->loadEntry(new TestNavigationEntry(-1, url, WebString(), frameName));
       
  1085 }
       
  1086 
       
  1087 bool WebViewHost::navigate(const TestNavigationEntry& entry, bool reload)
       
  1088 {
       
  1089     // Get the right target frame for the entry.
       
  1090     WebFrame* frame = webView()->mainFrame();
       
  1091     if (!entry.targetFrame().isEmpty())
       
  1092         frame = webView()->findFrameByName(entry.targetFrame());
       
  1093 
       
  1094     // TODO(mpcomplete): should we clear the target frame, or should
       
  1095     // back/forward navigations maintain the target frame?
       
  1096 
       
  1097     // A navigation resulting from loading a javascript URL should not be
       
  1098     // treated as a browser initiated event.  Instead, we want it to look as if
       
  1099     // the page initiated any load resulting from JS execution.
       
  1100     if (!GURL(entry.URL()).SchemeIs("javascript"))
       
  1101         setPendingExtraData(new TestShellExtraData(entry.pageID()));
       
  1102 
       
  1103     // If we are reloading, then WebKit will use the state of the current page.
       
  1104     // Otherwise, we give it the state to navigate to.
       
  1105     if (reload) {
       
  1106         frame->reload(false);
       
  1107     } else if (!entry.contentState().isNull()) {
       
  1108         ASSERT(entry.pageID() != -1);
       
  1109         frame->loadHistoryItem(entry.contentState());
       
  1110     } else {
       
  1111         ASSERT(entry.pageID() == -1);
       
  1112         frame->loadRequest(WebURLRequest(entry.URL()));
       
  1113     }
       
  1114 
       
  1115     // In case LoadRequest failed before DidCreateDataSource was called.
       
  1116     setPendingExtraData(0);
       
  1117 
       
  1118     // Restore focus to the main frame prior to loading new request.
       
  1119     // This makes sure that we don't have a focused iframe. Otherwise, that
       
  1120     // iframe would keep focus when the SetFocus called immediately after
       
  1121     // LoadRequest, thus making some tests fail (see http://b/issue?id=845337
       
  1122     // for more details).
       
  1123     webView()->setFocusedFrame(frame);
       
  1124     m_shell->setFocus(webView(), true);
       
  1125 
       
  1126     return true;
       
  1127 }
       
  1128 
       
  1129 // Private functions ----------------------------------------------------------
       
  1130 
       
  1131 LayoutTestController* WebViewHost::layoutTestController() const
       
  1132 {
       
  1133     return m_shell->layoutTestController();
       
  1134 }
       
  1135 
       
  1136 void WebViewHost::updateAddressBar(WebView* webView)
       
  1137 {
       
  1138     WebFrame* mainFrame = webView->mainFrame();
       
  1139     WebDataSource* dataSource = mainFrame->dataSource();
       
  1140     if (!dataSource)
       
  1141         dataSource = mainFrame->provisionalDataSource();
       
  1142     if (!dataSource)
       
  1143         return;
       
  1144 
       
  1145     setAddressBarURL(dataSource->request().url());
       
  1146 }
       
  1147 
       
  1148 void WebViewHost::locationChangeDone(WebFrame* frame)
       
  1149 {
       
  1150     if (frame != m_topLoadingFrame)
       
  1151         return;
       
  1152     m_topLoadingFrame = 0;
       
  1153     layoutTestController()->locationChangeDone();
       
  1154 }
       
  1155 
       
  1156 void WebViewHost::updateForCommittedLoad(WebFrame* frame, bool isNewNavigation)
       
  1157 {
       
  1158     // Code duplicated from RenderView::DidCommitLoadForFrame.
       
  1159     TestShellExtraData* extraData = static_cast<TestShellExtraData*>(frame->dataSource()->extraData());
       
  1160 
       
  1161     if (isNewNavigation) {
       
  1162         // New navigation.
       
  1163         updateSessionHistory(frame);
       
  1164         m_pageId = nextPageID++;
       
  1165     } else if (extraData && extraData->pendingPageID != -1 && !extraData->requestCommitted) {
       
  1166         // This is a successful session history navigation!
       
  1167         updateSessionHistory(frame);
       
  1168         m_pageId = extraData->pendingPageID;
       
  1169     }
       
  1170 
       
  1171     // Don't update session history multiple times.
       
  1172     if (extraData)
       
  1173         extraData->requestCommitted = true;
       
  1174 
       
  1175     updateURL(frame);
       
  1176 }
       
  1177 
       
  1178 void WebViewHost::updateURL(WebFrame* frame)
       
  1179 {
       
  1180     WebDataSource* ds = frame->dataSource();
       
  1181     ASSERT(ds);
       
  1182     const WebURLRequest& request = ds->request();
       
  1183     OwnPtr<TestNavigationEntry> entry(new TestNavigationEntry);
       
  1184 
       
  1185     // The referrer will be empty on https->http transitions. It
       
  1186     // would be nice if we could get the real referrer from somewhere.
       
  1187     entry->setPageID(m_pageId);
       
  1188     if (ds->hasUnreachableURL())
       
  1189         entry->setURL(ds->unreachableURL());
       
  1190     else
       
  1191         entry->setURL(request.url());
       
  1192 
       
  1193     const WebHistoryItem& historyItem = frame->currentHistoryItem();
       
  1194     if (!historyItem.isNull())
       
  1195         entry->setContentState(historyItem);
       
  1196 
       
  1197     navigationController()->didNavigateToEntry(entry.leakPtr());
       
  1198     updateAddressBar(frame->view());
       
  1199     m_lastPageIdUpdated = max(m_lastPageIdUpdated, m_pageId);
       
  1200 }
       
  1201 
       
  1202 void WebViewHost::updateSessionHistory(WebFrame* frame)
       
  1203 {
       
  1204     // If we have a valid page ID at this point, then it corresponds to the page
       
  1205     // we are navigating away from.  Otherwise, this is the first navigation, so
       
  1206     // there is no past session history to record.
       
  1207     if (m_pageId == -1)
       
  1208         return;
       
  1209 
       
  1210     TestNavigationEntry* entry = static_cast<TestNavigationEntry*>(navigationController()->entryWithPageID(m_pageId));
       
  1211     if (!entry)
       
  1212         return;
       
  1213 
       
  1214     const WebHistoryItem& historyItem = webView()->mainFrame()->previousHistoryItem();
       
  1215     if (historyItem.isNull())
       
  1216         return;
       
  1217 
       
  1218     entry->setContentState(historyItem);
       
  1219 }
       
  1220 
       
  1221 void WebViewHost::printFrameDescription(WebFrame* webframe)
       
  1222 {
       
  1223     string name8 = webframe->name().utf8();
       
  1224     if (webframe == webView()->mainFrame()) {
       
  1225         if (!name8.length()) {
       
  1226             fputs("main frame", stdout);
       
  1227             return;
       
  1228         }
       
  1229         printf("main frame \"%s\"", name8.c_str());
       
  1230         return;
       
  1231     }
       
  1232     if (!name8.length()) {
       
  1233         fputs("frame (anonymous)", stdout);
       
  1234         return;
       
  1235     }
       
  1236     printf("frame \"%s\"", name8.c_str());
       
  1237 }
       
  1238 
       
  1239 void WebViewHost::printResourceDescription(unsigned identifier)
       
  1240 {
       
  1241     ResourceMap::iterator it = m_resourceIdentifierMap.find(identifier);
       
  1242     printf("%s", it != m_resourceIdentifierMap.end() ? it->second.c_str() : "<unknown>");
       
  1243 }
       
  1244 
       
  1245 void WebViewHost::setPendingExtraData(TestShellExtraData* extraData)
       
  1246 {
       
  1247     m_pendingExtraData.set(extraData);
       
  1248 }
       
  1249 
       
  1250 void WebViewHost::setPageTitle(const WebString&)
       
  1251 {
       
  1252     // Nothing to do in layout test.
       
  1253 }
       
  1254 
       
  1255 void WebViewHost::setAddressBarURL(const WebURL&)
       
  1256 {
       
  1257     // Nothing to do in layout test.
       
  1258 }
       
  1259 
       
  1260 // Painting functions ---------------------------------------------------------
       
  1261 
       
  1262 void WebViewHost::updatePaintRect(const WebRect& rect)
       
  1263 {
       
  1264     // m_paintRect = m_paintRect U rect
       
  1265     if (rect.isEmpty())
       
  1266         return;
       
  1267     if (m_paintRect.isEmpty()) {
       
  1268         m_paintRect = rect;
       
  1269         return;
       
  1270     }
       
  1271     int left = min(m_paintRect.x, rect.x);
       
  1272     int top = min(m_paintRect.y, rect.y);
       
  1273     int right = max(m_paintRect.x + m_paintRect.width, rect.x + rect.width);
       
  1274     int bottom = max(m_paintRect.y + m_paintRect.height, rect.y + rect.height);
       
  1275     m_paintRect = WebRect(left, top, right - left, bottom - top);
       
  1276 }
       
  1277 
       
  1278 void WebViewHost::paintRect(const WebRect& rect)
       
  1279 {
       
  1280     ASSERT(!m_isPainting);
       
  1281     ASSERT(canvas());
       
  1282     m_isPainting = true;
       
  1283 #if PLATFORM(CG)
       
  1284     webWidget()->paint(canvas()->getTopPlatformDevice().GetBitmapContext(), rect);
       
  1285 #else
       
  1286     webWidget()->paint(canvas(), rect);
       
  1287 #endif
       
  1288     m_isPainting = false;
       
  1289 }
       
  1290 
       
  1291 void WebViewHost::paintInvalidatedRegion()
       
  1292 {
       
  1293     webWidget()->layout();
       
  1294     WebSize widgetSize = webWidget()->size();
       
  1295     WebRect clientRect(0, 0, widgetSize.width, widgetSize.height);
       
  1296 
       
  1297     // Paint the canvas if necessary.  Allow painting to generate extra rects
       
  1298     // for the first two calls. This is necessary because some WebCore rendering
       
  1299     // objects update their layout only when painted.
       
  1300     // Store the total area painted in total_paint. Then tell the gdk window
       
  1301     // to update that area after we're done painting it.
       
  1302     for (int i = 0; i < 3; ++i) {
       
  1303         // m_paintRect = intersect(m_paintRect , clientRect)
       
  1304         int left = max(m_paintRect.x, clientRect.x);
       
  1305         int top = max(m_paintRect.y, clientRect.y);
       
  1306         int right = min(m_paintRect.x + m_paintRect.width, clientRect.x + clientRect.width);
       
  1307         int bottom = min(m_paintRect.y + m_paintRect.height, clientRect.y + clientRect.height);
       
  1308         if (left >= right || top >= bottom)
       
  1309             m_paintRect = WebRect();
       
  1310         else
       
  1311             m_paintRect = WebRect(left, top, right - left, bottom - top);
       
  1312 
       
  1313         if (m_paintRect.isEmpty())
       
  1314             continue;
       
  1315         WebRect rect(m_paintRect);
       
  1316         m_paintRect = WebRect();
       
  1317         paintRect(rect);
       
  1318         if (i >= 1)
       
  1319             LOG_ERROR("painting caused additional invalidations");
       
  1320     }
       
  1321     ASSERT(m_paintRect.isEmpty());
       
  1322 }
       
  1323 
       
  1324 PlatformCanvas* WebViewHost::canvas()
       
  1325 {
       
  1326     if (m_canvas)
       
  1327         return m_canvas.get();
       
  1328     WebSize widgetSize = webWidget()->size();
       
  1329     resetScrollRect();
       
  1330     m_canvas.set(new PlatformCanvas(widgetSize.width, widgetSize.height, true));
       
  1331     return m_canvas.get();
       
  1332 }
       
  1333 
       
  1334 void WebViewHost::resetScrollRect()
       
  1335 {
       
  1336 }
       
  1337 
       
  1338 void WebViewHost::discardBackingStore()
       
  1339 {
       
  1340     m_canvas.clear();
       
  1341 }
       
  1342 
       
  1343 // Paints the entire canvas a semi-transparent black (grayish). This is used
       
  1344 // by the layout tests in fast/repaint. The alpha value matches upstream.
       
  1345 void WebViewHost::displayRepaintMask()
       
  1346 {
       
  1347     canvas()->drawARGB(167, 0, 0, 0);
       
  1348 }