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