2 * Copyright (C) 2010, 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
32 #include "WebViewHost.h"
34 #include "LayoutTestController.h"
35 #include "TestNavigationController.h"
36 #include "TestShell.h"
37 #include "TestWebPlugin.h"
38 #include "TestWebWorker.h"
39 #include "WebCString.h"
40 #include "WebCompositor.h"
41 #include "WebConsoleMessage.h"
42 #include "WebContextMenuData.h"
43 #include "WebDataSource.h"
44 #include "WebDeviceOrientationClientMock.h"
45 #include "WebDragData.h"
46 #include "WebElement.h"
48 #include "WebGeolocationClientMock.h"
49 #include "WebHistoryItem.h"
51 #include "WebKitPlatformSupport.h"
53 #include "WebPluginParams.h"
54 #include "WebPopupMenu.h"
55 #include "WebPopupType.h"
58 #include "WebScreenInfo.h"
60 #include "WebSpeechInputControllerMock.h"
61 #include "WebStorageNamespace.h"
62 #include "WebTextCheckingCompletion.h"
63 #include "WebTextCheckingResult.h"
64 #include "WebThread.h"
65 #include "WebURLRequest.h"
66 #include "WebURLResponse.h"
68 #include "WebWindowFeatures.h"
69 #include "skia/ext/platform_canvas.h"
70 #include "webkit/support/webkit_support.h"
72 #include <wtf/Assertions.h>
73 #include <wtf/PassOwnPtr.h>
74 #include <wtf/Threading.h>
75 #include <wtf/Vector.h>
77 using namespace WebCore;
78 using namespace WebKit;
81 static const int screenWidth = 1920;
82 static const int screenHeight = 1080;
83 static const int screenUnavailableBorder = 8;
85 // WebNavigationType debugging strings taken from PolicyDelegate.mm.
86 static const char* linkClickedString = "link clicked";
87 static const char* formSubmittedString = "form submitted";
88 static const char* backForwardString = "back/forward";
89 static const char* reloadString = "reload";
90 static const char* formResubmittedString = "form resubmitted";
91 static const char* otherString = "other";
92 static const char* illegalString = "illegal value";
94 static int nextPageID = 1;
96 // Used to write a platform neutral file:/// URL by only taking the filename
97 // (e.g., converts "file:///tmp/foo.txt" to just "foo.txt").
98 static string urlSuitableForTestResult(const string& url)
100 if (url.empty() || string::npos == url.find("file://"))
103 size_t pos = url.rfind('/');
104 if (pos == string::npos) {
106 pos = url.rfind('\\');
107 if (pos == string::npos)
113 string filename = url.substr(pos + 1);
114 if (filename.empty())
115 return "file:"; // A WebKit test has this in its expected output.
119 // Used to write a platform neutral file:/// URL by taking the
120 // filename and its directory. (e.g., converts
121 // "file:///tmp/foo/bar.txt" to just "bar.txt").
122 static string descriptionSuitableForTestResult(const string& url)
124 if (url.empty() || string::npos == url.find("file://"))
127 size_t pos = url.rfind('/');
128 if (pos == string::npos || !pos)
129 return "ERROR:" + url;
130 pos = url.rfind('/', pos - 1);
131 if (pos == string::npos)
132 return "ERROR:" + url;
134 return url.substr(pos + 1);
137 // Adds a file called "DRTFakeFile" to dragData (CF_HDROP). Use to fake
139 static void addDRTFakeFileToDataObject(WebDragData* dragData)
141 dragData->appendToFilenames(WebString::fromUTF8("DRTFakeFile"));
144 // Get a debugging string from a WebNavigationType.
145 static const char* webNavigationTypeToString(WebNavigationType type)
148 case WebKit::WebNavigationTypeLinkClicked:
149 return linkClickedString;
150 case WebKit::WebNavigationTypeFormSubmitted:
151 return formSubmittedString;
152 case WebKit::WebNavigationTypeBackForward:
153 return backForwardString;
154 case WebKit::WebNavigationTypeReload:
156 case WebKit::WebNavigationTypeFormResubmitted:
157 return formResubmittedString;
158 case WebKit::WebNavigationTypeOther:
161 return illegalString;
164 static string URLDescription(const GURL& url)
166 if (url.SchemeIs("file"))
167 return url.ExtractFileName();
168 return url.possibly_invalid_spec();
171 static void printResponseDescription(const WebURLResponse& response)
173 if (response.isNull()) {
174 fputs("(null)", stdout);
177 string url = response.url().spec();
178 printf("<NSURLResponse %s, http status code %d>",
179 descriptionSuitableForTestResult(url).c_str(),
180 response.httpStatusCode());
183 static void printNodeDescription(const WebNode& node, int exception)
186 fputs("ERROR", stdout);
190 fputs("(null)", stdout);
193 fputs(node.nodeName().utf8().data(), stdout);
194 const WebNode& parent = node.parentNode();
195 if (!parent.isNull()) {
196 fputs(" > ", stdout);
197 printNodeDescription(parent, 0);
201 static void printRangeDescription(const WebRange& range)
203 if (range.isNull()) {
204 fputs("(null)", stdout);
207 printf("range from %d of ", range.startOffset());
209 WebNode startNode = range.startContainer(exception);
210 printNodeDescription(startNode, exception);
211 printf(" to %d of ", range.endOffset());
212 WebNode endNode = range.endContainer(exception);
213 printNodeDescription(endNode, exception);
216 static string editingActionDescription(WebEditingAction action)
219 case WebKit::WebEditingActionTyped:
220 return "WebViewInsertActionTyped";
221 case WebKit::WebEditingActionPasted:
222 return "WebViewInsertActionPasted";
223 case WebKit::WebEditingActionDropped:
224 return "WebViewInsertActionDropped";
226 return "(UNKNOWN ACTION)";
229 static string textAffinityDescription(WebTextAffinity affinity)
232 case WebKit::WebTextAffinityUpstream:
233 return "NSSelectionAffinityUpstream";
234 case WebKit::WebTextAffinityDownstream:
235 return "NSSelectionAffinityDownstream";
237 return "(UNKNOWN AFFINITY)";
240 // WebViewClient -------------------------------------------------------------
242 WebView* WebViewHost::createView(WebFrame*, const WebURLRequest& request, const WebWindowFeatures&, const WebString&)
244 if (!layoutTestController()->canOpenWindows())
246 if (layoutTestController()->shouldDumpCreateView())
247 fprintf(stdout, "createView(%s)\n", URLDescription(request.url()).c_str());
248 return m_shell->createNewWindow(WebURL())->webView();
251 WebWidget* WebViewHost::createPopupMenu(WebPopupType type)
254 case WebKit::WebPopupTypeNone:
256 case WebKit::WebPopupTypeSelect:
257 case WebKit::WebPopupTypeSuggestion:
258 m_popupmenus.append(WebPopupMenu::create(0));
259 return m_popupmenus.last();
264 WebWidget* WebViewHost::createPopupMenu(const WebPopupMenuInfo&)
266 // Do not use this method. It's been replaced by createExternalPopupMenu.
267 ASSERT_NOT_REACHED();
271 WebStorageNamespace* WebViewHost::createSessionStorageNamespace(unsigned quota)
273 return WebKit::WebStorageNamespace::createSessionStorageNamespace(quota);
276 void WebViewHost::didAddMessageToConsole(const WebConsoleMessage& message, const WebString& sourceName, unsigned sourceLine)
278 // This matches win DumpRenderTree's UIDelegate.cpp.
279 if (!m_logConsoleOutput)
282 if (!message.text.isEmpty()) {
283 newMessage = message.text.utf8();
284 size_t fileProtocol = newMessage.find("file://");
285 if (fileProtocol != string::npos) {
286 newMessage = newMessage.substr(0, fileProtocol)
287 + urlSuitableForTestResult(newMessage.substr(fileProtocol));
290 printf("CONSOLE MESSAGE: line %d: %s\n", sourceLine, newMessage.data());
293 void WebViewHost::didStartLoading()
295 m_shell->setIsLoading(true);
298 void WebViewHost::didStopLoading()
300 if (layoutTestController()->shouldDumpProgressFinishedCallback())
301 fputs("postProgressFinishedNotification\n", stdout);
302 m_shell->setIsLoading(false);
305 // The output from these methods in layout test mode should match that
306 // expected by the layout tests. See EditingDelegate.m in DumpRenderTree.
308 bool WebViewHost::shouldBeginEditing(const WebRange& range)
310 if (layoutTestController()->shouldDumpEditingCallbacks()) {
311 fputs("EDITING DELEGATE: shouldBeginEditingInDOMRange:", stdout);
312 printRangeDescription(range);
315 return layoutTestController()->acceptsEditing();
318 bool WebViewHost::shouldEndEditing(const WebRange& range)
320 if (layoutTestController()->shouldDumpEditingCallbacks()) {
321 fputs("EDITING DELEGATE: shouldEndEditingInDOMRange:", stdout);
322 printRangeDescription(range);
325 return layoutTestController()->acceptsEditing();
328 bool WebViewHost::shouldInsertNode(const WebNode& node, const WebRange& range, WebEditingAction action)
330 if (layoutTestController()->shouldDumpEditingCallbacks()) {
331 fputs("EDITING DELEGATE: shouldInsertNode:", stdout);
332 printNodeDescription(node, 0);
333 fputs(" replacingDOMRange:", stdout);
334 printRangeDescription(range);
335 printf(" givenAction:%s\n", editingActionDescription(action).c_str());
337 return layoutTestController()->acceptsEditing();
340 bool WebViewHost::shouldInsertText(const WebString& text, const WebRange& range, WebEditingAction action)
342 if (layoutTestController()->shouldDumpEditingCallbacks()) {
343 printf("EDITING DELEGATE: shouldInsertText:%s replacingDOMRange:", text.utf8().data());
344 printRangeDescription(range);
345 printf(" givenAction:%s\n", editingActionDescription(action).c_str());
347 return layoutTestController()->acceptsEditing();
350 bool WebViewHost::shouldChangeSelectedRange(
351 const WebRange& fromRange, const WebRange& toRange, WebTextAffinity affinity, bool stillSelecting)
353 if (layoutTestController()->shouldDumpEditingCallbacks()) {
354 fputs("EDITING DELEGATE: shouldChangeSelectedDOMRange:", stdout);
355 printRangeDescription(fromRange);
356 fputs(" toDOMRange:", stdout);
357 printRangeDescription(toRange);
358 printf(" affinity:%s stillSelecting:%s\n",
359 textAffinityDescription(affinity).c_str(),
360 (stillSelecting ? "TRUE" : "FALSE"));
362 return layoutTestController()->acceptsEditing();
365 bool WebViewHost::shouldDeleteRange(const WebRange& range)
367 if (layoutTestController()->shouldDumpEditingCallbacks()) {
368 fputs("EDITING DELEGATE: shouldDeleteDOMRange:", stdout);
369 printRangeDescription(range);
372 return layoutTestController()->acceptsEditing();
375 bool WebViewHost::shouldApplyStyle(const WebString& style, const WebRange& range)
377 if (layoutTestController()->shouldDumpEditingCallbacks()) {
378 printf("EDITING DELEGATE: shouldApplyStyle:%s toElementsInDOMRange:", style.utf8().data());
379 printRangeDescription(range);
382 return layoutTestController()->acceptsEditing();
385 bool WebViewHost::isSmartInsertDeleteEnabled()
387 return m_smartInsertDeleteEnabled;
390 bool WebViewHost::isSelectTrailingWhitespaceEnabled()
392 return m_selectTrailingWhitespaceEnabled;
395 void WebViewHost::didBeginEditing()
397 if (!layoutTestController()->shouldDumpEditingCallbacks())
399 fputs("EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification\n", stdout);
402 void WebViewHost::didChangeSelection(bool isEmptySelection)
404 if (layoutTestController()->shouldDumpEditingCallbacks())
405 fputs("EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification\n", stdout);
406 // No need to update clipboard with the selected text in DRT.
409 void WebViewHost::didChangeContents()
411 if (!layoutTestController()->shouldDumpEditingCallbacks())
413 fputs("EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification\n", stdout);
416 void WebViewHost::didEndEditing()
418 if (!layoutTestController()->shouldDumpEditingCallbacks())
420 fputs("EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification\n", stdout);
423 bool WebViewHost::handleCurrentKeyboardEvent()
425 if (m_editCommandName.empty())
427 WebFrame* frame = webView()->focusedFrame();
431 return frame->executeCommand(WebString::fromUTF8(m_editCommandName), WebString::fromUTF8(m_editCommandValue));
434 void WebViewHost::spellCheck(const WebString& text, int& misspelledOffset, int& misspelledLength, WebVector<WebString>* optionalSuggestions)
436 // Check the spelling of the given text.
437 m_spellcheck.spellCheckWord(text, &misspelledOffset, &misspelledLength);
440 void WebViewHost::requestCheckingOfText(const WebString& text, WebTextCheckingCompletion* completion)
442 m_lastRequestedTextCheckingCompletion = completion;
443 m_lastRequestedTextCheckString = text;
444 postDelayedTask(new HostMethodTask(this, &WebViewHost::finishLastTextCheck), 0);
447 void WebViewHost::finishLastTextCheck()
449 Vector<WebTextCheckingResult> results;
450 // FIXME: Do the grammar check.
452 String text(m_lastRequestedTextCheckString.data(), m_lastRequestedTextCheckString.length());
453 while (text.length()) {
454 int misspelledPosition = 0;
455 int misspelledLength = 0;
456 m_spellcheck.spellCheckWord(WebString(text.characters(), text.length()), &misspelledPosition, &misspelledLength);
457 if (!misspelledLength)
459 results.append(WebTextCheckingResult(WebTextCheckingResult::ErrorSpelling, offset + misspelledPosition, misspelledLength));
460 text = text.substring(misspelledPosition + misspelledLength);
461 offset += misspelledPosition + misspelledLength;
464 m_lastRequestedTextCheckingCompletion->didFinishCheckingText(results);
465 m_lastRequestedTextCheckingCompletion = 0;
469 WebString WebViewHost::autoCorrectWord(const WebString&)
471 // Returns an empty string as Mac WebKit ('WebKitSupport/WebEditorClient.mm')
472 // does. (If this function returns a non-empty string, WebKit replaces the
473 // given misspelled string with the result one. This process executes some
474 // editor commands and causes layout-test failures.)
478 void WebViewHost::runModalAlertDialog(WebFrame*, const WebString& message)
480 printf("ALERT: %s\n", message.utf8().data());
483 bool WebViewHost::runModalConfirmDialog(WebFrame*, const WebString& message)
485 printf("CONFIRM: %s\n", message.utf8().data());
489 bool WebViewHost::runModalPromptDialog(WebFrame* frame, const WebString& message,
490 const WebString& defaultValue, WebString*)
492 printf("PROMPT: %s, default text: %s\n", message.utf8().data(), defaultValue.utf8().data());
496 bool WebViewHost::runModalBeforeUnloadDialog(WebFrame*, const WebString& message)
498 printf("CONFIRM NAVIGATION: %s\n", message.utf8().data());
499 return !layoutTestController()->shouldStayOnPageAfterHandlingBeforeUnload();
502 void WebViewHost::showContextMenu(WebFrame*, const WebContextMenuData& contextMenuData)
504 m_lastContextMenuData = adoptPtr(new WebContextMenuData(contextMenuData));
507 void WebViewHost::clearContextMenuData()
509 m_lastContextMenuData.clear();
512 WebContextMenuData* WebViewHost::lastContextMenuData() const
514 return m_lastContextMenuData.get();
517 void WebViewHost::setStatusText(const WebString& text)
519 if (!layoutTestController()->shouldDumpStatusCallbacks())
521 // When running tests, write to stdout.
522 printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", text.utf8().data());
525 void WebViewHost::startDragging(const WebDragData& data, WebDragOperationsMask mask, const WebImage&, const WebPoint&)
527 WebDragData mutableDragData = data;
528 if (layoutTestController()->shouldAddFileToPasteboard()) {
529 // Add a file called DRTFakeFile to the drag&drop clipboard.
530 addDRTFakeFileToDataObject(&mutableDragData);
533 // When running a test, we need to fake a drag drop operation otherwise
534 // Windows waits for real mouse events to know when the drag is over.
535 m_shell->eventSender()->doDragDrop(mutableDragData, mask);
538 void WebViewHost::navigateBackForwardSoon(int offset)
540 navigationController()->goToOffset(offset);
543 int WebViewHost::historyBackListCount()
545 return navigationController()->lastCommittedEntryIndex();
548 int WebViewHost::historyForwardListCount()
550 int currentIndex =navigationController()->lastCommittedEntryIndex();
551 return navigationController()->entryCount() - currentIndex - 1;
554 void WebViewHost::postAccessibilityNotification(const WebAccessibilityObject& obj, WebAccessibilityNotification notification)
556 if (notification == WebAccessibilityNotificationFocusedUIElementChanged)
557 m_shell->accessibilityController()->setFocusedElement(obj);
559 const char* notificationName;
560 switch (notification) {
561 case WebAccessibilityNotificationActiveDescendantChanged:
562 notificationName = "ActiveDescendantChanged";
564 case WebAccessibilityNotificationAutocorrectionOccured:
565 notificationName = "AutocorrectionOccured";
567 case WebAccessibilityNotificationCheckedStateChanged:
568 notificationName = "CheckedStateChanged";
570 case WebAccessibilityNotificationChildrenChanged:
571 notificationName = "ChildrenChanged";
573 case WebAccessibilityNotificationFocusedUIElementChanged:
574 notificationName = "FocusedUIElementChanged";
576 case WebAccessibilityNotificationLayoutComplete:
577 notificationName = "LayoutComplete";
579 case WebAccessibilityNotificationLoadComplete:
580 notificationName = "LoadComplete";
582 case WebAccessibilityNotificationSelectedChildrenChanged:
583 notificationName = "SelectedChildrenChanged";
585 case WebAccessibilityNotificationSelectedTextChanged:
586 notificationName = "SelectedTextChanged";
588 case WebAccessibilityNotificationValueChanged:
589 notificationName = "ValueChanged";
591 case WebAccessibilityNotificationScrolledToAnchor:
592 notificationName = "ScrolledToAnchor";
594 case WebAccessibilityNotificationLiveRegionChanged:
595 notificationName = "LiveRegionChanged";
597 case WebAccessibilityNotificationMenuListItemSelected:
598 notificationName = "MenuListItemSelected";
600 case WebAccessibilityNotificationMenuListValueChanged:
601 notificationName = "MenuListValueChanged";
603 case WebAccessibilityNotificationRowCountChanged:
604 notificationName = "RowCountChanged";
606 case WebAccessibilityNotificationRowCollapsed:
607 notificationName = "RowCollapsed";
609 case WebAccessibilityNotificationRowExpanded:
610 notificationName = "RowExpanded";
612 case WebAccessibilityNotificationInvalidStatusChanged:
613 notificationName = "InvalidStatusChanged";
616 notificationName = "UnknownNotification";
620 m_shell->accessibilityController()->notificationReceived(obj, notificationName);
622 if (m_shell->accessibilityController()->shouldLogAccessibilityEvents()) {
623 printf("AccessibilityNotification - %s", notificationName);
625 WebKit::WebNode node = obj.node();
626 if (!node.isNull() && node.isElementNode()) {
627 WebKit::WebElement element = node.to<WebKit::WebElement>();
628 if (element.hasAttribute("id"))
629 printf(" - id:%s", element.getAttribute("id").utf8().data());
636 WebNotificationPresenter* WebViewHost::notificationPresenter()
638 return m_shell->notificationPresenter();
641 WebKit::WebGeolocationClient* WebViewHost::geolocationClient()
643 return geolocationClientMock();
646 WebKit::WebGeolocationClientMock* WebViewHost::geolocationClientMock()
648 if (!m_geolocationClientMock)
649 m_geolocationClientMock = adoptPtr(WebGeolocationClientMock::create());
650 return m_geolocationClientMock.get();
653 WebSpeechInputController* WebViewHost::speechInputController(WebKit::WebSpeechInputListener* listener)
655 if (!m_speechInputControllerMock)
656 m_speechInputControllerMock = adoptPtr(WebSpeechInputControllerMock::create(listener));
657 return m_speechInputControllerMock.get();
660 WebDeviceOrientationClientMock* WebViewHost::deviceOrientationClientMock()
662 if (!m_deviceOrientationClientMock.get())
663 m_deviceOrientationClientMock = adoptPtr(WebDeviceOrientationClientMock::create());
664 return m_deviceOrientationClientMock.get();
667 MockSpellCheck* WebViewHost::mockSpellCheck()
669 return &m_spellcheck;
672 WebDeviceOrientationClient* WebViewHost::deviceOrientationClient()
674 return deviceOrientationClientMock();
677 // WebWidgetClient -----------------------------------------------------------
679 void WebViewHost::didInvalidateRect(const WebRect& rect)
681 updatePaintRect(rect);
684 void WebViewHost::didScrollRect(int, int, const WebRect& clipRect)
686 // This is used for optimizing painting when the renderer is scrolled. We're
687 // currently not doing any optimizations so just invalidate the region.
688 didInvalidateRect(clipRect);
691 void WebViewHost::scheduleComposite()
693 WebSize widgetSize = webWidget()->size();
694 WebRect clientRect(0, 0, widgetSize.width, widgetSize.height);
695 didInvalidateRect(clientRect);
698 #if ENABLE(REQUEST_ANIMATION_FRAME)
699 void WebViewHost::scheduleAnimation()
701 postDelayedTask(new HostMethodTask(this, &WebViewHost::scheduleComposite), 0);
705 void WebViewHost::didFocus()
707 m_shell->setFocus(webWidget(), true);
710 void WebViewHost::didBlur()
712 m_shell->setFocus(webWidget(), false);
715 WebScreenInfo WebViewHost::screenInfo()
717 // We don't need to set actual values.
720 info.depthPerComponent = 8;
721 info.isMonochrome = false;
722 info.rect = WebRect(0, 0, screenWidth, screenHeight);
723 // Use values different from info.rect for testing.
724 info.availableRect = WebRect(screenUnavailableBorder, screenUnavailableBorder,
725 screenWidth - screenUnavailableBorder * 2,
726 screenHeight - screenUnavailableBorder * 2);
730 void WebViewHost::show(WebNavigationPolicy)
733 WebSize size = webWidget()->size();
734 updatePaintRect(WebRect(0, 0, size.width, size.height));
739 void WebViewHost::closeWidget()
742 m_shell->closeWindow(this);
743 // No more code here, we should be deleted at this point.
746 void WebViewHost::closeWidgetSoon()
748 postDelayedTask(new HostMethodTask(this, &WebViewHost::closeWidget), 0);
751 void WebViewHost::didChangeCursor(const WebCursorInfo& cursorInfo)
755 m_currentCursor = cursorInfo;
758 WebRect WebViewHost::windowRect()
763 void WebViewHost::setWindowRect(const WebRect& rect)
766 const int border2 = TestShell::virtualWindowBorder * 2;
767 if (m_windowRect.width <= border2)
768 m_windowRect.width = 1 + border2;
769 if (m_windowRect.height <= border2)
770 m_windowRect.height = 1 + border2;
771 int width = m_windowRect.width - border2;
772 int height = m_windowRect.height - border2;
773 discardBackingStore();
774 webWidget()->resize(WebSize(width, height));
775 updatePaintRect(WebRect(0, 0, width, height));
778 WebRect WebViewHost::rootWindowRect()
783 WebRect WebViewHost::windowResizerRect()
789 void WebViewHost::runModal()
791 bool oldState = webkit_support::MessageLoopNestableTasksAllowed();
792 webkit_support::MessageLoopSetNestableTasksAllowed(true);
793 m_inModalLoop = true;
794 webkit_support::RunMessageLoop();
795 webkit_support::MessageLoopSetNestableTasksAllowed(oldState);
798 bool WebViewHost::enterFullScreen()
800 postDelayedTask(new HostMethodTask(this, &WebViewHost::enterFullScreenNow), 0);
804 void WebViewHost::exitFullScreen()
806 postDelayedTask(new HostMethodTask(this, &WebViewHost::exitFullScreenNow), 0);
809 // WebFrameClient ------------------------------------------------------------
811 WebPlugin* WebViewHost::createPlugin(WebFrame* frame, const WebPluginParams& params)
813 if (params.mimeType == TestWebPlugin::mimeType())
814 return new TestWebPlugin(frame, params);
816 return webkit_support::CreateWebPlugin(frame, params);
819 WebWorker* WebViewHost::createWorker(WebFrame*, WebWorkerClient*)
821 return new TestWebWorker();
824 WebMediaPlayer* WebViewHost::createMediaPlayer(WebFrame* frame, WebMediaPlayerClient* client)
826 return webkit_support::CreateMediaPlayer(frame, client);
829 WebApplicationCacheHost* WebViewHost::createApplicationCacheHost(WebFrame* frame, WebApplicationCacheHostClient* client)
831 return webkit_support::CreateApplicationCacheHost(frame, client);
834 void WebViewHost::didUpdateLayout(WebFrame*)
837 static bool queryingPreferredSize = false;
838 if (queryingPreferredSize)
841 queryingPreferredSize = true;
842 // Query preferred width to emulate the same functionality in Chromium:
843 // see RenderView::CheckPreferredSize (src/content/renderer/render_view.cc)
844 // and TabContentsViewMac::RenderViewCreated (src/chrome/browser/tab_contents/tab_contents_view_mac.mm)
845 webView()->mainFrame()->contentsPreferredWidth();
846 webView()->mainFrame()->documentElementScrollHeight();
847 queryingPreferredSize = false;
852 void WebViewHost::loadURLExternally(WebFrame* frame, const WebURLRequest& request, WebNavigationPolicy policy)
854 loadURLExternally(frame, request, policy, WebString());
857 void WebViewHost::loadURLExternally(WebFrame*, const WebURLRequest& request, WebNavigationPolicy policy, const WebString& downloadName)
859 ASSERT(policy != WebKit::WebNavigationPolicyCurrentTab);
860 WebViewHost* another = m_shell->createNewWindow(request.url());
862 another->show(policy);
865 WebNavigationPolicy WebViewHost::decidePolicyForNavigation(
866 WebFrame*, const WebURLRequest& request,
867 WebNavigationType type, const WebNode& originatingNode,
868 WebNavigationPolicy defaultPolicy, bool isRedirect)
870 WebNavigationPolicy result;
871 if (!m_policyDelegateEnabled)
872 return defaultPolicy;
874 printf("Policy delegate: attempt to load %s with navigation type '%s'",
875 URLDescription(request.url()).c_str(), webNavigationTypeToString(type));
876 if (!originatingNode.isNull()) {
877 fputs(" originating from ", stdout);
878 printNodeDescription(originatingNode, 0);
881 if (m_policyDelegateIsPermissive)
882 result = WebKit::WebNavigationPolicyCurrentTab;
884 result = WebKit::WebNavigationPolicyIgnore;
886 if (m_policyDelegateShouldNotifyDone)
887 layoutTestController()->policyDelegateDone();
891 bool WebViewHost::canHandleRequest(WebFrame*, const WebURLRequest& request)
893 GURL url = request.url();
894 // Just reject the scheme used in
895 // LayoutTests/http/tests/misc/redirect-to-external-url.html
896 return !url.SchemeIs("spaceballs");
899 WebURLError WebViewHost::cannotHandleRequestError(WebFrame*, const WebURLRequest& request)
902 // A WebKit layout test expects the following values.
903 // unableToImplementPolicyWithError() below prints them.
904 error.domain = WebString::fromUTF8("WebKitErrorDomain");
906 error.unreachableURL = request.url();
910 WebURLError WebViewHost::cancelledError(WebFrame*, const WebURLRequest& request)
912 return webkit_support::CreateCancelledError(request);
915 void WebViewHost::unableToImplementPolicyWithError(WebFrame* frame, const WebURLError& error)
917 printf("Policy delegate: unable to implement policy with error domain '%s', "
918 "error code %d, in frame '%s'\n",
919 error.domain.utf8().data(), error.reason, frame->name().utf8().data());
922 void WebViewHost::willPerformClientRedirect(WebFrame* frame, const WebURL& from, const WebURL& to,
923 double interval, double fire_time)
925 if (m_shell->shouldDumpFrameLoadCallbacks()) {
926 printFrameDescription(frame);
927 printf(" - willPerformClientRedirectToURL: %s \n", to.spec().data());
930 if (m_shell->shouldDumpUserGestureInFrameLoadCallbacks())
931 printFrameUserGestureStatus(frame, " - in willPerformClientRedirect\n");
934 void WebViewHost::didCancelClientRedirect(WebFrame* frame)
936 if (!m_shell->shouldDumpFrameLoadCallbacks())
938 printFrameDescription(frame);
939 fputs(" - didCancelClientRedirectForFrame\n", stdout);
942 void WebViewHost::didCreateDataSource(WebFrame*, WebDataSource* ds)
944 ds->setExtraData(m_pendingExtraData.leakPtr());
945 if (!layoutTestController()->deferMainResourceDataLoad())
946 ds->setDeferMainResourceDataLoad(false);
949 void WebViewHost::didStartProvisionalLoad(WebFrame* frame)
951 if (m_shell->shouldDumpFrameLoadCallbacks()) {
952 printFrameDescription(frame);
953 fputs(" - didStartProvisionalLoadForFrame\n", stdout);
956 if (m_shell->shouldDumpUserGestureInFrameLoadCallbacks())
957 printFrameUserGestureStatus(frame, " - in didStartProvisionalLoadForFrame\n");
959 if (!m_topLoadingFrame)
960 m_topLoadingFrame = frame;
962 if (layoutTestController()->stopProvisionalFrameLoads()) {
963 printFrameDescription(frame);
964 fputs(" - stopping load in didStartProvisionalLoadForFrame callback\n", stdout);
965 frame->stopLoading();
967 updateAddressBar(frame->view());
970 void WebViewHost::didReceiveServerRedirectForProvisionalLoad(WebFrame* frame)
972 if (m_shell->shouldDumpFrameLoadCallbacks()) {
973 printFrameDescription(frame);
974 fputs(" - didReceiveServerRedirectForProvisionalLoadForFrame\n", stdout);
976 updateAddressBar(frame->view());
979 void WebViewHost::didFailProvisionalLoad(WebFrame* frame, const WebURLError& error)
981 if (m_shell->shouldDumpFrameLoadCallbacks()) {
982 printFrameDescription(frame);
983 fputs(" - didFailProvisionalLoadWithError\n", stdout);
986 locationChangeDone(frame);
988 // Don't display an error page if we're running layout tests, because
989 // DumpRenderTree doesn't.
992 void WebViewHost::didCommitProvisionalLoad(WebFrame* frame, bool isNewNavigation)
994 if (m_shell->shouldDumpFrameLoadCallbacks()) {
995 printFrameDescription(frame);
996 fputs(" - didCommitLoadForFrame\n", stdout);
998 updateForCommittedLoad(frame, isNewNavigation);
1001 void WebViewHost::didClearWindowObject(WebFrame* frame)
1003 m_shell->bindJSObjectsToWindow(frame);
1006 void WebViewHost::didReceiveTitle(WebFrame* frame, const WebString& title, WebTextDirection direction)
1008 WebCString title8 = title.utf8();
1010 if (m_shell->shouldDumpFrameLoadCallbacks()) {
1011 printFrameDescription(frame);
1012 printf(" - didReceiveTitle: %s\n", title8.data());
1015 if (layoutTestController()->shouldDumpTitleChanges())
1016 printf("TITLE CHANGED: %s\n", title8.data());
1018 setPageTitle(title);
1019 layoutTestController()->setTitleTextDirection(direction);
1022 void WebViewHost::didFinishDocumentLoad(WebFrame* frame)
1024 if (m_shell->shouldDumpFrameLoadCallbacks()) {
1025 printFrameDescription(frame);
1026 fputs(" - didFinishDocumentLoadForFrame\n", stdout);
1028 unsigned pendingUnloadEvents = frame->unloadListenerCount();
1029 if (pendingUnloadEvents) {
1030 printFrameDescription(frame);
1031 printf(" - has %u onunload handler(s)\n", pendingUnloadEvents);
1036 void WebViewHost::didHandleOnloadEvents(WebFrame* frame)
1038 if (m_shell->shouldDumpFrameLoadCallbacks()) {
1039 printFrameDescription(frame);
1040 fputs(" - didHandleOnloadEventsForFrame\n", stdout);
1044 void WebViewHost::didFailLoad(WebFrame* frame, const WebURLError& error)
1046 if (m_shell->shouldDumpFrameLoadCallbacks()) {
1047 printFrameDescription(frame);
1048 fputs(" - didFailLoadWithError\n", stdout);
1050 locationChangeDone(frame);
1053 void WebViewHost::didFinishLoad(WebFrame* frame)
1055 if (m_shell->shouldDumpFrameLoadCallbacks()) {
1056 printFrameDescription(frame);
1057 fputs(" - didFinishLoadForFrame\n", stdout);
1059 updateAddressBar(frame->view());
1060 locationChangeDone(frame);
1063 void WebViewHost::didNavigateWithinPage(WebFrame* frame, bool isNewNavigation)
1065 frame->dataSource()->setExtraData(m_pendingExtraData.leakPtr());
1067 updateForCommittedLoad(frame, isNewNavigation);
1070 void WebViewHost::didChangeLocationWithinPage(WebFrame* frame)
1072 if (m_shell->shouldDumpFrameLoadCallbacks()) {
1073 printFrameDescription(frame);
1074 fputs(" - didChangeLocationWithinPageForFrame\n", stdout);
1078 void WebViewHost::assignIdentifierToRequest(WebFrame*, unsigned identifier, const WebURLRequest& request)
1080 if (!m_shell->shouldDumpResourceLoadCallbacks())
1082 ASSERT(!m_resourceIdentifierMap.contains(identifier));
1083 m_resourceIdentifierMap.set(identifier, descriptionSuitableForTestResult(request.url().spec()));
1086 void WebViewHost::removeIdentifierForRequest(unsigned identifier)
1088 m_resourceIdentifierMap.remove(identifier);
1091 void WebViewHost::willSendRequest(WebFrame*, unsigned identifier, WebURLRequest& request, const WebURLResponse& redirectResponse)
1093 // Need to use GURL for host() and SchemeIs()
1094 GURL url = request.url();
1095 string requestURL = url.possibly_invalid_spec();
1097 if (layoutTestController()->shouldDumpResourceLoadCallbacks()) {
1098 GURL mainDocumentURL = request.firstPartyForCookies();
1099 printResourceDescription(identifier);
1100 printf(" - willSendRequest <NSURLRequest URL %s, main document URL %s,"
1101 " http method %s> redirectResponse ",
1102 descriptionSuitableForTestResult(requestURL).c_str(),
1103 URLDescription(mainDocumentURL).c_str(),
1104 request.httpMethod().utf8().data());
1105 printResponseDescription(redirectResponse);
1106 fputs("\n", stdout);
1109 if (!redirectResponse.isNull() && m_blocksRedirects) {
1110 fputs("Returning null for this redirect\n", stdout);
1111 // To block the request, we set its URL to an empty one.
1112 request.setURL(WebURL());
1116 if (m_requestReturnNull) {
1117 // To block the request, we set its URL to an empty one.
1118 request.setURL(WebURL());
1122 string host = url.host();
1123 // 255.255.255.255 is used in some tests that expect to get back an error.
1124 if (!host.empty() && (url.SchemeIs("http") || url.SchemeIs("https"))
1125 && host != "127.0.0.1"
1126 && host != "255.255.255.255"
1127 && host != "localhost"
1128 && !m_shell->allowExternalPages()) {
1129 printf("Blocked access to external URL %s\n", requestURL.c_str());
1131 // To block the request, we set its URL to an empty one.
1132 request.setURL(WebURL());
1136 HashSet<String>::const_iterator end = m_clearHeaders.end();
1137 for (HashSet<String>::const_iterator header = m_clearHeaders.begin(); header != end; ++header)
1138 request.clearHTTPHeaderField(WebString(header->characters(), header->length()));
1140 // Set the new substituted URL.
1141 request.setURL(webkit_support::RewriteLayoutTestsURL(request.url().spec()));
1144 void WebViewHost::didReceiveResponse(WebFrame*, unsigned identifier, const WebURLResponse& response)
1146 if (m_shell->shouldDumpResourceLoadCallbacks()) {
1147 printResourceDescription(identifier);
1148 fputs(" - didReceiveResponse ", stdout);
1149 printResponseDescription(response);
1150 fputs("\n", stdout);
1152 if (m_shell->shouldDumpResourceResponseMIMETypes()) {
1153 GURL url = response.url();
1154 WebString mimeType = response.mimeType();
1155 printf("%s has MIME type %s\n",
1156 url.ExtractFileName().c_str(),
1157 // Simulate NSURLResponse's mapping of empty/unknown MIME types to application/octet-stream
1158 mimeType.isEmpty() ? "application/octet-stream" : mimeType.utf8().data());
1162 void WebViewHost::didFinishResourceLoad(WebFrame*, unsigned identifier)
1164 if (m_shell->shouldDumpResourceLoadCallbacks()) {
1165 printResourceDescription(identifier);
1166 fputs(" - didFinishLoading\n", stdout);
1168 removeIdentifierForRequest(identifier);
1171 void WebViewHost::didFailResourceLoad(WebFrame*, unsigned identifier, const WebURLError& error)
1173 if (m_shell->shouldDumpResourceLoadCallbacks()) {
1174 printResourceDescription(identifier);
1175 fputs(" - didFailLoadingWithError: ", stdout);
1176 fputs(webkit_support::MakeURLErrorDescription(error).c_str(), stdout);
1177 fputs("\n", stdout);
1179 removeIdentifierForRequest(identifier);
1182 void WebViewHost::didDisplayInsecureContent(WebFrame*)
1184 if (m_shell->shouldDumpFrameLoadCallbacks())
1185 fputs("didDisplayInsecureContent\n", stdout);
1188 void WebViewHost::didRunInsecureContent(WebFrame*, const WebSecurityOrigin& origin, const WebURL& insecureURL)
1190 if (m_shell->shouldDumpFrameLoadCallbacks())
1191 fputs("didRunInsecureContent\n", stdout);
1194 void WebViewHost::didDetectXSS(WebFrame*, const WebURL&, bool)
1196 if (m_shell->shouldDumpFrameLoadCallbacks())
1197 fputs("didDetectXSS\n", stdout);
1200 void WebViewHost::openFileSystem(WebFrame* frame, WebFileSystem::Type type, long long size, bool create, WebFileSystemCallbacks* callbacks)
1202 webkit_support::OpenFileSystem(frame, type, size, create, callbacks);
1205 // Public functions -----------------------------------------------------------
1207 WebViewHost::WebViewHost(TestShell* shell)
1210 , m_lastRequestedTextCheckingCompletion(0)
1212 WTF::initializeThreading();
1214 m_compositorThread = adoptPtr(WebKit::webKitPlatformSupport()->createThread("Compositor"));
1215 WebCompositor::setThread(m_compositorThread.get());
1220 WebViewHost::~WebViewHost()
1222 // DevTools frontend page is supposed to be navigated only once and
1223 // loading another URL in that Page is an error.
1224 if (m_shell->devToolsWebView() != this) {
1225 // Navigate to an empty page to fire all the destruction logic for the
1227 loadURLForFrame(GURL("about:blank"), WebString());
1230 for (Vector<WebKit::WebWidget*>::iterator it = m_popupmenus.begin();
1231 it < m_popupmenus.end(); ++it)
1234 webWidget()->close();
1236 webkit_support::QuitMessageLoop();
1239 void WebViewHost::setWebWidget(WebKit::WebWidget* widget)
1241 m_webWidget = widget;
1242 webView()->setSpellCheckClient(this);
1245 WebView* WebViewHost::webView() const
1247 ASSERT(m_webWidget);
1248 // DRT does not support popup widgets. So m_webWidget is always a WebView.
1249 return static_cast<WebView*>(m_webWidget);
1252 WebWidget* WebViewHost::webWidget() const
1254 ASSERT(m_webWidget);
1258 void WebViewHost::reset()
1260 m_policyDelegateEnabled = false;
1261 m_policyDelegateIsPermissive = false;
1262 m_policyDelegateShouldNotifyDone = false;
1263 m_topLoadingFrame = 0;
1265 m_lastPageIdUpdated = -1;
1266 m_hasWindow = false;
1267 m_inModalLoop = false;
1268 m_smartInsertDeleteEnabled = true;
1269 m_logConsoleOutput = true;
1271 m_selectTrailingWhitespaceEnabled = true;
1273 m_selectTrailingWhitespaceEnabled = false;
1275 m_blocksRedirects = false;
1276 m_requestReturnNull = false;
1277 m_isPainting = false;
1280 m_navigationController = adoptPtr(new TestNavigationController(this));
1282 m_pendingExtraData.clear();
1283 m_resourceIdentifierMap.clear();
1284 m_clearHeaders.clear();
1285 m_editCommandName.clear();
1286 m_editCommandValue.clear();
1288 if (m_geolocationClientMock.get())
1289 m_geolocationClientMock->resetMock();
1291 if (m_speechInputControllerMock.get())
1292 m_speechInputControllerMock->clearResults();
1294 m_currentCursor = WebCursorInfo();
1295 m_windowRect = WebRect();
1296 m_paintRect = WebRect();
1299 webView()->mainFrame()->setName(WebString());
1300 webView()->settings()->setMinimumTimerInterval(webkit_support::GetForegroundTabTimerInterval());
1304 void WebViewHost::setSelectTrailingWhitespaceEnabled(bool enabled)
1306 m_selectTrailingWhitespaceEnabled = enabled;
1307 // In upstream WebKit, smart insert/delete is mutually exclusive with select
1308 // trailing whitespace, however, we allow both because Chromium on Windows
1312 void WebViewHost::setSmartInsertDeleteEnabled(bool enabled)
1314 m_smartInsertDeleteEnabled = enabled;
1315 // In upstream WebKit, smart insert/delete is mutually exclusive with select
1316 // trailing whitespace, however, we allow both because Chromium on Windows
1320 void WebViewHost::setLogConsoleOutput(bool enabled)
1322 m_logConsoleOutput = enabled;
1325 void WebViewHost::setCustomPolicyDelegate(bool isCustom, bool isPermissive)
1327 m_policyDelegateEnabled = isCustom;
1328 m_policyDelegateIsPermissive = isPermissive;
1331 void WebViewHost::waitForPolicyDelegate()
1333 m_policyDelegateEnabled = true;
1334 m_policyDelegateShouldNotifyDone = true;
1337 void WebViewHost::setEditCommand(const string& name, const string& value)
1339 m_editCommandName = name;
1340 m_editCommandValue = value;
1343 void WebViewHost::clearEditCommand()
1345 m_editCommandName.clear();
1346 m_editCommandValue.clear();
1349 void WebViewHost::loadURLForFrame(const WebURL& url, const WebString& frameName)
1353 TestShell::resizeWindowForTest(this, url);
1354 navigationController()->loadEntry(TestNavigationEntry::create(-1, url, WebString(), frameName).get());
1357 bool WebViewHost::navigate(const TestNavigationEntry& entry, bool reload)
1359 // Get the right target frame for the entry.
1360 WebFrame* frame = webView()->mainFrame();
1361 if (!entry.targetFrame().isEmpty())
1362 frame = webView()->findFrameByName(entry.targetFrame());
1364 // TODO(mpcomplete): should we clear the target frame, or should
1365 // back/forward navigations maintain the target frame?
1367 // A navigation resulting from loading a javascript URL should not be
1368 // treated as a browser initiated event. Instead, we want it to look as if
1369 // the page initiated any load resulting from JS execution.
1370 if (!GURL(entry.URL()).SchemeIs("javascript"))
1371 setPendingExtraData(adoptPtr(new TestShellExtraData(entry.pageID())));
1373 // If we are reloading, then WebKit will use the state of the current page.
1374 // Otherwise, we give it the state to navigate to.
1376 frame->reload(false);
1377 } else if (!entry.contentState().isNull()) {
1378 ASSERT(entry.pageID() != -1);
1379 frame->loadHistoryItem(entry.contentState());
1381 ASSERT(entry.pageID() == -1);
1382 frame->loadRequest(WebURLRequest(entry.URL()));
1385 // In case LoadRequest failed before DidCreateDataSource was called.
1386 setPendingExtraData(nullptr);
1388 // Restore focus to the main frame prior to loading new request.
1389 // This makes sure that we don't have a focused iframe. Otherwise, that
1390 // iframe would keep focus when the SetFocus called immediately after
1391 // LoadRequest, thus making some tests fail (see http://b/issue?id=845337
1392 // for more details).
1393 webView()->setFocusedFrame(frame);
1394 m_shell->setFocus(webView(), true);
1399 // Private functions ----------------------------------------------------------
1401 LayoutTestController* WebViewHost::layoutTestController() const
1403 return m_shell->layoutTestController();
1406 void WebViewHost::updateAddressBar(WebView* webView)
1408 WebFrame* mainFrame = webView->mainFrame();
1409 WebDataSource* dataSource = mainFrame->dataSource();
1411 dataSource = mainFrame->provisionalDataSource();
1415 setAddressBarURL(dataSource->request().url());
1418 void WebViewHost::locationChangeDone(WebFrame* frame)
1420 if (frame != m_topLoadingFrame)
1422 m_topLoadingFrame = 0;
1423 layoutTestController()->locationChangeDone();
1426 void WebViewHost::updateForCommittedLoad(WebFrame* frame, bool isNewNavigation)
1428 // Code duplicated from RenderView::DidCommitLoadForFrame.
1429 TestShellExtraData* extraData = static_cast<TestShellExtraData*>(frame->dataSource()->extraData());
1431 if (isNewNavigation) {
1433 updateSessionHistory(frame);
1434 m_pageId = nextPageID++;
1435 } else if (extraData && extraData->pendingPageID != -1 && !extraData->requestCommitted) {
1436 // This is a successful session history navigation!
1437 updateSessionHistory(frame);
1438 m_pageId = extraData->pendingPageID;
1441 // Don't update session history multiple times.
1443 extraData->requestCommitted = true;
1448 void WebViewHost::updateURL(WebFrame* frame)
1450 WebDataSource* ds = frame->dataSource();
1452 const WebURLRequest& request = ds->request();
1453 RefPtr<TestNavigationEntry> entry(TestNavigationEntry::create());
1455 // The referrer will be empty on https->http transitions. It
1456 // would be nice if we could get the real referrer from somewhere.
1457 entry->setPageID(m_pageId);
1458 if (ds->hasUnreachableURL())
1459 entry->setURL(ds->unreachableURL());
1461 entry->setURL(request.url());
1463 const WebHistoryItem& historyItem = frame->currentHistoryItem();
1464 if (!historyItem.isNull())
1465 entry->setContentState(historyItem);
1467 navigationController()->didNavigateToEntry(entry.get());
1468 updateAddressBar(frame->view());
1469 m_lastPageIdUpdated = max(m_lastPageIdUpdated, m_pageId);
1472 void WebViewHost::updateSessionHistory(WebFrame* frame)
1474 // If we have a valid page ID at this point, then it corresponds to the page
1475 // we are navigating away from. Otherwise, this is the first navigation, so
1476 // there is no past session history to record.
1480 TestNavigationEntry* entry = navigationController()->entryWithPageID(m_pageId);
1484 const WebHistoryItem& historyItem = webView()->mainFrame()->previousHistoryItem();
1485 if (historyItem.isNull())
1488 entry->setContentState(historyItem);
1491 void WebViewHost::printFrameDescription(WebFrame* webframe)
1493 string name8 = webframe->name().utf8();
1494 if (webframe == webView()->mainFrame()) {
1495 if (!name8.length()) {
1496 fputs("main frame", stdout);
1499 printf("main frame \"%s\"", name8.c_str());
1502 if (!name8.length()) {
1503 fputs("frame (anonymous)", stdout);
1506 printf("frame \"%s\"", name8.c_str());
1509 void WebViewHost::printFrameUserGestureStatus(WebFrame* webframe, const char* msg)
1511 bool isUserGesture = webframe->isProcessingUserGesture();
1512 printf("Frame with user gesture \"%s\"%s", isUserGesture ? "true" : "false", msg);
1515 void WebViewHost::printResourceDescription(unsigned identifier)
1517 ResourceMap::iterator it = m_resourceIdentifierMap.find(identifier);
1518 printf("%s", it != m_resourceIdentifierMap.end() ? it->second.c_str() : "<unknown>");
1521 void WebViewHost::setPendingExtraData(PassOwnPtr<TestShellExtraData> extraData)
1523 m_pendingExtraData = extraData;
1526 void WebViewHost::setPageTitle(const WebString&)
1528 // Nothing to do in layout test.
1531 void WebViewHost::setAddressBarURL(const WebURL&)
1533 // Nothing to do in layout test.
1536 void WebViewHost::enterFullScreenNow()
1538 webView()->willEnterFullScreen();
1539 webView()->didEnterFullScreen();
1542 void WebViewHost::exitFullScreenNow()
1544 webView()->willExitFullScreen();
1545 webView()->didExitFullScreen();
1548 // Painting functions ---------------------------------------------------------
1550 void WebViewHost::updatePaintRect(const WebRect& rect)
1552 // m_paintRect = m_paintRect U rect
1555 if (m_paintRect.isEmpty()) {
1559 int left = min(m_paintRect.x, rect.x);
1560 int top = min(m_paintRect.y, rect.y);
1561 int right = max(m_paintRect.x + m_paintRect.width, rect.x + rect.width);
1562 int bottom = max(m_paintRect.y + m_paintRect.height, rect.y + rect.height);
1563 m_paintRect = WebRect(left, top, right - left, bottom - top);
1566 void WebViewHost::paintRect(const WebRect& rect)
1568 ASSERT(!m_isPainting);
1570 m_isPainting = true;
1572 webWidget()->paint(skia::BeginPlatformPaint(canvas()), rect);
1573 skia::EndPlatformPaint(canvas());
1575 webWidget()->paint(canvas(), rect);
1577 m_isPainting = false;
1580 void WebViewHost::paintInvalidatedRegion()
1582 #if ENABLE(REQUEST_ANIMATION_FRAME)
1583 webWidget()->animate(0.0);
1585 webWidget()->layout();
1586 WebSize widgetSize = webWidget()->size();
1587 WebRect clientRect(0, 0, widgetSize.width, widgetSize.height);
1589 // Paint the canvas if necessary. Allow painting to generate extra rects
1590 // for the first two calls. This is necessary because some WebCore rendering
1591 // objects update their layout only when painted.
1592 // Store the total area painted in total_paint. Then tell the gdk window
1593 // to update that area after we're done painting it.
1594 for (int i = 0; i < 3; ++i) {
1595 // m_paintRect = intersect(m_paintRect , clientRect)
1596 int left = max(m_paintRect.x, clientRect.x);
1597 int top = max(m_paintRect.y, clientRect.y);
1598 int right = min(m_paintRect.x + m_paintRect.width, clientRect.x + clientRect.width);
1599 int bottom = min(m_paintRect.y + m_paintRect.height, clientRect.y + clientRect.height);
1600 if (left >= right || top >= bottom)
1601 m_paintRect = WebRect();
1603 m_paintRect = WebRect(left, top, right - left, bottom - top);
1605 if (m_paintRect.isEmpty())
1607 WebRect rect(m_paintRect);
1608 m_paintRect = WebRect();
1611 ASSERT(m_paintRect.isEmpty());
1614 void WebViewHost::paintPagesWithBoundaries()
1616 ASSERT(!m_isPainting);
1618 m_isPainting = true;
1620 WebSize pageSizeInPixels = webWidget()->size();
1621 WebFrame* webFrame = webView()->mainFrame();
1623 int pageCount = webFrame->printBegin(pageSizeInPixels);
1624 int totalHeight = pageCount * (pageSizeInPixels.height + 1) - 1;
1626 SkCanvas* testCanvas = skia::TryCreateBitmapCanvas(pageSizeInPixels.width, totalHeight, true);
1628 discardBackingStore();
1629 m_canvas = adoptPtr(testCanvas);
1631 webFrame->printEnd();
1635 #if WEBKIT_USING_SKIA
1636 WebCanvas* webCanvas = canvas();
1637 #elif WEBKIT_USING_CG
1638 const SkBitmap& canvasBitmap = canvas()->getDevice()->accessBitmap(false);
1639 WebCanvas* webCanvas = CGBitmapContextCreate(canvasBitmap.getPixels(),
1640 pageSizeInPixels.width, totalHeight,
1641 8, pageSizeInPixels.width * 4,
1642 CGColorSpaceCreateDeviceRGB(),
1643 kCGImageAlphaPremultipliedFirst |
1644 kCGBitmapByteOrder32Host);
1645 CGContextTranslateCTM(webCanvas, 0.0, totalHeight);
1646 CGContextScaleCTM(webCanvas, 1.0, -1.0f);
1649 webFrame->printPagesWithBoundaries(webCanvas, pageSizeInPixels);
1650 webFrame->printEnd();
1652 m_isPainting = false;
1655 SkCanvas* WebViewHost::canvas()
1658 return m_canvas.get();
1659 WebSize widgetSize = webWidget()->size();
1661 m_canvas = adoptPtr(skia::CreateBitmapCanvas(widgetSize.width, widgetSize.height, true));
1662 return m_canvas.get();
1665 void WebViewHost::resetScrollRect()
1669 void WebViewHost::discardBackingStore()
1674 // Paints the entire canvas a semi-transparent black (grayish). This is used
1675 // by the layout tests in fast/repaint. The alpha value matches upstream.
1676 void WebViewHost::displayRepaintMask()
1678 canvas()->drawARGB(167, 0, 0, 0);