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