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