c4c962dbf9c63e84a8c43d75181e95cdd8c271ac
[WebKit-https.git] / Tools / DumpRenderTree / chromium / WebViewHost.cpp
1 /*
2  * Copyright (C) 2010, 2011, 2012 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 "DRTDevToolsAgent.h"
35 #include "MockWebSpeechInputController.h"
36 #include "MockWebSpeechRecognizer.h"
37 #include "Task.h"
38 #include "TestNavigationController.h"
39 #include "TestShell.h"
40 #include "WebCachedURLRequest.h"
41 #include "WebConsoleMessage.h"
42 #include "WebContextMenuData.h"
43 #include "WebDOMMessageEvent.h"
44 #include "WebDataSource.h"
45 #include "WebDeviceOrientationClientMock.h"
46 #include "WebDocument.h"
47 #include "WebElement.h"
48 #include "WebFrame.h"
49 #include "WebGeolocationClientMock.h"
50 #include "WebHistoryItem.h"
51 #include "WebKit.h"
52 #include "WebNode.h"
53 #include "WebPluginParams.h"
54 #include "WebPopupMenu.h"
55 #include "WebPopupType.h"
56 #include "WebPrintParams.h"
57 #include "WebRange.h"
58 #include "WebScreenInfo.h"
59 #include "WebSerializedScriptValue.h"
60 #include "WebStorageNamespace.h"
61 #include "WebView.h"
62 #include "WebWindowFeatures.h"
63 #include "webkit/support/test_media_stream_client.h"
64 #include "webkit/support/webkit_support.h"
65 #include <cctype>
66 #include <clocale>
67 #include <public/WebCString.h>
68 #include <public/WebCompositorOutputSurface.h>
69 #include <public/WebCompositorSupport.h>
70 #include <public/WebDragData.h>
71 #include <public/WebRect.h>
72 #include <public/WebSize.h>
73 #include <public/WebThread.h>
74 #include <public/WebURLRequest.h>
75 #include <public/WebURLResponse.h>
76
77 #include <wtf/Assertions.h>
78 #include <wtf/OwnArrayPtr.h>
79 #include <wtf/PassOwnPtr.h>
80 #include <wtf/Vector.h>
81
82 using namespace WebCore;
83 using namespace WebKit;
84 using namespace WebTestRunner;
85 using namespace std;
86
87 static const int screenWidth = 1920;
88 static const int screenHeight = 1080;
89 static const int screenUnavailableBorder = 8;
90
91 static int nextPageID = 1;
92
93 // WebViewClient -------------------------------------------------------------
94
95 WebView* WebViewHost::createView(WebFrame* creator, const WebURLRequest&, const WebWindowFeatures&, const WebString&, WebNavigationPolicy)
96 {
97     creator->consumeUserGesture();
98     return m_shell->createNewWindow(WebURL())->webView();
99 }
100
101 WebWidget* WebViewHost::createPopupMenu(WebPopupType type)
102 {
103     switch (type) {
104     case WebKit::WebPopupTypeNone:
105     case WebKit::WebPopupTypePage:
106     case WebKit::WebPopupTypeHelperPlugin:
107         break;
108     case WebKit::WebPopupTypeSelect:
109     case WebKit::WebPopupTypeSuggestion:
110         m_popupmenus.append(WebPopupMenu::create(0));
111         return m_popupmenus.last();
112     }
113     return 0;
114 }
115
116 WebWidget* WebViewHost::createPopupMenu(const WebPopupMenuInfo&)
117 {
118     // Do not use this method. It's been replaced by createExternalPopupMenu.
119     ASSERT_NOT_REACHED();
120     return 0;
121 }
122
123 WebStorageNamespace* WebViewHost::createSessionStorageNamespace(unsigned quota)
124 {
125     return webkit_support::CreateSessionStorageNamespace(quota);
126 }
127
128 WebCompositorOutputSurface* WebViewHost::createOutputSurface()
129 {
130     if (!webView())
131         return 0;
132
133     if (m_shell->softwareCompositingEnabled())
134         return WebKit::Platform::current()->compositorSupport()->createOutputSurfaceForSoftware();
135
136     WebGraphicsContext3D* context = webkit_support::CreateGraphicsContext3D(WebGraphicsContext3D::Attributes(), webView());
137     return WebKit::Platform::current()->compositorSupport()->createOutputSurfaceFor3D(context);
138 }
139
140 void WebViewHost::didAddMessageToConsole(const WebConsoleMessage& message, const WebString& sourceName, unsigned sourceLine)
141 {
142 }
143
144 void WebViewHost::didStartLoading()
145 {
146 }
147
148 void WebViewHost::didStopLoading()
149 {
150 }
151
152 bool WebViewHost::shouldBeginEditing(const WebRange& range)
153 {
154     return true;
155 }
156
157 bool WebViewHost::shouldEndEditing(const WebRange& range)
158 {
159     return true;
160 }
161
162 bool WebViewHost::shouldInsertNode(const WebNode& node, const WebRange& range, WebEditingAction action)
163 {
164     return true;
165 }
166
167 bool WebViewHost::shouldInsertText(const WebString& text, const WebRange& range, WebEditingAction action)
168 {
169     return true;
170 }
171
172 bool WebViewHost::shouldChangeSelectedRange(
173     const WebRange& fromRange, const WebRange& toRange, WebTextAffinity affinity, bool stillSelecting)
174 {
175     return true;
176 }
177
178 bool WebViewHost::shouldDeleteRange(const WebRange& range)
179 {
180     return true;
181 }
182
183 bool WebViewHost::shouldApplyStyle(const WebString& style, const WebRange& range)
184 {
185     return true;
186 }
187
188 bool WebViewHost::isSmartInsertDeleteEnabled()
189 {
190     return true;
191 }
192
193 bool WebViewHost::isSelectTrailingWhitespaceEnabled()
194 {
195 #if OS(WINDOWS)
196     return true;
197 #else
198     return false;
199 #endif
200 }
201
202 bool WebViewHost::handleCurrentKeyboardEvent()
203 {
204     if (m_editCommandName.empty())
205         return false;
206     WebFrame* frame = webView()->focusedFrame();
207     if (!frame)
208         return false;
209
210     return frame->executeCommand(WebString::fromUTF8(m_editCommandName), WebString::fromUTF8(m_editCommandValue));
211 }
212
213 // WebKit::WebPrerendererClient
214
215 void WebViewHost::willAddPrerender(WebKit::WebPrerender*)
216 {
217 }
218
219
220 void WebViewHost::runModalAlertDialog(WebFrame*, const WebString& message)
221 {
222 }
223
224 bool WebViewHost::runModalConfirmDialog(WebFrame*, const WebString& message)
225 {
226     return true;
227 }
228
229 bool WebViewHost::runModalPromptDialog(WebFrame* frame, const WebString& message,
230                                        const WebString& defaultValue, WebString*)
231 {
232     return true;
233 }
234
235 void WebViewHost::showContextMenu(WebFrame*, const WebContextMenuData& contextMenuData)
236 {
237 }
238
239 void WebViewHost::didUpdateLayout()
240 {
241 #if OS(MAC_OS_X)
242     static bool queryingPreferredSize = false;
243     if (queryingPreferredSize)
244         return;
245
246     queryingPreferredSize = true;
247     // Query preferred width to emulate the same functionality in Chromium:
248     // see RenderView::CheckPreferredSize (src/content/renderer/render_view.cc)
249     // and TabContentsViewMac::RenderViewCreated (src/chrome/browser/tab_contents/tab_contents_view_mac.mm)
250     webView()->mainFrame()->contentsPreferredWidth();
251     webView()->mainFrame()->documentElementScrollHeight();
252     queryingPreferredSize = false;
253 #endif
254 }
255
256 void WebViewHost::navigateBackForwardSoon(int offset)
257 {
258     navigationController()->goToOffset(offset);
259 }
260
261 int WebViewHost::historyBackListCount()
262 {
263     return navigationController()->lastCommittedEntryIndex();
264 }
265
266 int WebViewHost::historyForwardListCount()
267 {
268     int currentIndex =navigationController()->lastCommittedEntryIndex();
269     return navigationController()->entryCount() - currentIndex - 1;
270 }
271
272 WebKit::WebGeolocationClient* WebViewHost::geolocationClient()
273 {
274     return geolocationClientMock();
275 }
276
277 WebKit::WebGeolocationClientMock* WebViewHost::geolocationClientMock()
278 {
279     if (!m_geolocationClientMock)
280         m_geolocationClientMock = adoptPtr(WebGeolocationClientMock::create());
281     return m_geolocationClientMock.get();
282 }
283
284 #if ENABLE(INPUT_SPEECH)
285 WebSpeechInputController* WebViewHost::speechInputController(WebKit::WebSpeechInputListener* listener)
286 {
287     if (!m_speechInputControllerMock)
288         m_speechInputControllerMock = MockWebSpeechInputController::create(listener);
289     return m_speechInputControllerMock.get();
290 }
291 #endif
292
293 #if ENABLE(SCRIPTED_SPEECH)
294 WebSpeechRecognizer* WebViewHost::speechRecognizer()
295 {
296     if (!m_mockSpeechRecognizer)
297         m_mockSpeechRecognizer = MockWebSpeechRecognizer::create();
298     return m_mockSpeechRecognizer.get();
299 }
300 #endif
301
302 WebDeviceOrientationClientMock* WebViewHost::deviceOrientationClientMock()
303 {
304     if (!m_deviceOrientationClientMock.get())
305         m_deviceOrientationClientMock = adoptPtr(WebDeviceOrientationClientMock::create());
306     return m_deviceOrientationClientMock.get();
307 }
308
309 WebDeviceOrientationClient* WebViewHost::deviceOrientationClient()
310 {
311     return deviceOrientationClientMock();
312 }
313
314 // WebWidgetClient -----------------------------------------------------------
315
316 void WebViewHost::didAutoResize(const WebSize& newSize)
317 {
318     // Purposely don't include the virtualWindowBorder in this case so that
319     // window.inner[Width|Height] is the same as window.outer[Width|Height]
320     setWindowRect(WebRect(0, 0, newSize.width, newSize.height));
321 }
322
323 void WebViewHost::initializeLayerTreeView(WebLayerTreeViewClient* client, const WebLayer& rootLayer, const WebLayerTreeView::Settings& settings)
324 {
325     m_layerTreeView = adoptPtr(Platform::current()->compositorSupport()->createLayerTreeView(client, rootLayer, settings));
326     if (m_layerTreeView)
327         m_layerTreeView->setSurfaceReady();
328 }
329
330 WebLayerTreeView* WebViewHost::layerTreeView()
331 {
332     return m_layerTreeView.get();
333 }
334
335 void WebViewHost::scheduleAnimation()
336 {
337     if (webView()->settings()->scrollAnimatorEnabled())
338         webView()->animate(0.0);
339 }
340
341 void WebViewHost::didFocus()
342 {
343     m_shell->setFocus(webWidget(), true);
344 }
345
346 void WebViewHost::didBlur()
347 {
348     m_shell->setFocus(webWidget(), false);
349 }
350
351 WebScreenInfo WebViewHost::screenInfo()
352 {
353     // We don't need to set actual values.
354     WebScreenInfo info;
355     info.depth = 24;
356     info.depthPerComponent = 8;
357     info.isMonochrome = false;
358     info.rect = WebRect(0, 0, screenWidth, screenHeight);
359     // Use values different from info.rect for testing.
360     info.availableRect = WebRect(screenUnavailableBorder, screenUnavailableBorder,
361                                  screenWidth - screenUnavailableBorder * 2,
362                                  screenHeight - screenUnavailableBorder * 2);
363     return info;
364 }
365
366 #if ENABLE(POINTER_LOCK)
367 bool WebViewHost::requestPointerLock()
368 {
369     switch (m_pointerLockPlannedResult) {
370     case PointerLockWillSucceed:
371         postDelayedTask(new HostMethodTask(this, &WebViewHost::didAcquirePointerLock), 0);
372         return true;
373     case PointerLockWillRespondAsync:
374         ASSERT(!m_pointerLocked);
375         return true;
376     case PointerLockWillFailSync:
377         ASSERT(!m_pointerLocked);
378         return false;
379     default:
380         ASSERT_NOT_REACHED();
381         return false;
382     }
383 }
384
385 void WebViewHost::requestPointerUnlock()
386 {
387     postDelayedTask(new HostMethodTask(this, &WebViewHost::didLosePointerLock), 0);
388 }
389
390 bool WebViewHost::isPointerLocked()
391 {
392     return m_pointerLocked;
393 }
394
395 void WebViewHost::didAcquirePointerLock()
396 {
397     m_pointerLocked = true;
398     webWidget()->didAcquirePointerLock();
399
400     // Reset planned result to default.
401     m_pointerLockPlannedResult = PointerLockWillSucceed;
402 }
403
404 void WebViewHost::didNotAcquirePointerLock()
405 {
406     ASSERT(!m_pointerLocked);
407     m_pointerLocked = false;
408     webWidget()->didNotAcquirePointerLock();
409
410     // Reset planned result to default.
411     m_pointerLockPlannedResult = PointerLockWillSucceed;
412 }
413
414 void WebViewHost::didLosePointerLock()
415 {
416     bool wasLocked = m_pointerLocked;
417     m_pointerLocked = false;
418     if (wasLocked)
419         webWidget()->didLosePointerLock();
420 }
421 #endif
422
423 void WebViewHost::show(WebNavigationPolicy)
424 {
425     m_hasWindow = true;
426 }
427
428
429
430 void WebViewHost::closeWidget()
431 {
432     m_hasWindow = false;
433     m_shell->closeWindow(this);
434     // No more code here, we should be deleted at this point.
435 }
436
437 void WebViewHost::closeWidgetSoon()
438 {
439     postDelayedTask(new HostMethodTask(this, &WebViewHost::closeWidget), 0);
440 }
441
442 void WebViewHost::didChangeCursor(const WebCursorInfo& cursorInfo)
443 {
444     if (!hasWindow())
445         return;
446     m_currentCursor = cursorInfo;
447 }
448
449 WebRect WebViewHost::windowRect()
450 {
451     return m_windowRect;
452 }
453
454 void WebViewHost::setWindowRect(const WebRect& rect)
455 {
456     m_windowRect = rect;
457     const int border2 = TestShell::virtualWindowBorder * 2;
458     if (m_windowRect.width <= border2)
459         m_windowRect.width = 1 + border2;
460     if (m_windowRect.height <= border2)
461         m_windowRect.height = 1 + border2;
462     int width = m_windowRect.width - border2;
463     int height = m_windowRect.height - border2;
464     webWidget()->resize(WebSize(width, height));
465 }
466
467 WebRect WebViewHost::rootWindowRect()
468 {
469     return windowRect();
470 }
471
472 WebRect WebViewHost::windowResizerRect()
473 {
474     // Not necessary.
475     return WebRect();
476 }
477
478 void WebViewHost::runModal()
479 {
480     if (m_shell->isDisplayingModalDialog()) {
481         // DumpRenderTree doesn't support real modal dialogs, so a test shouldn't try to start two modal dialogs at the same time.
482         ASSERT_NOT_REACHED();
483         return;
484     }
485     // This WebViewHost might get deleted before RunMessageLoop() returns, so keep a copy of the m_shell member variable around.
486     ASSERT(m_shell->webViewHost() != this);
487     TestShell* shell = m_shell;
488     shell->setIsDisplayingModalDialog(true);
489     bool oldState = webkit_support::MessageLoopNestableTasksAllowed();
490     webkit_support::MessageLoopSetNestableTasksAllowed(true);
491     m_inModalLoop = true;
492     webkit_support::RunMessageLoop();
493     webkit_support::MessageLoopSetNestableTasksAllowed(oldState);
494     shell->setIsDisplayingModalDialog(false);
495 }
496
497 bool WebViewHost::enterFullScreen()
498 {
499     postDelayedTask(new HostMethodTask(this, &WebViewHost::enterFullScreenNow), 0);
500     return true;
501 }
502
503 void WebViewHost::exitFullScreen()
504 {
505     postDelayedTask(new HostMethodTask(this, &WebViewHost::exitFullScreenNow), 0);
506 }
507
508 // WebFrameClient ------------------------------------------------------------
509
510 WebPlugin* WebViewHost::createPlugin(WebFrame* frame, const WebPluginParams& params)
511 {
512     return webkit_support::CreateWebPlugin(frame, params);
513 }
514
515 WebMediaPlayer* WebViewHost::createMediaPlayer(WebFrame* frame, const WebURL& url, WebMediaPlayerClient* client)
516 {
517 #if ENABLE(MEDIA_STREAM)
518     return webkit_support::CreateMediaPlayer(frame, url, client, testMediaStreamClient());
519 #else
520     return webkit_support::CreateMediaPlayer(frame, url, client);
521 #endif
522 }
523
524 WebApplicationCacheHost* WebViewHost::createApplicationCacheHost(WebFrame* frame, WebApplicationCacheHostClient* client)
525 {
526     return webkit_support::CreateApplicationCacheHost(frame, client);
527 }
528
529 void WebViewHost::loadURLExternally(WebFrame* frame, const WebURLRequest& request, WebNavigationPolicy policy)
530 {
531     loadURLExternally(frame, request, policy, WebString());
532 }
533
534 void WebViewHost::loadURLExternally(WebFrame*, const WebURLRequest& request, WebNavigationPolicy policy, const WebString& downloadName)
535 {
536     ASSERT(policy !=  WebKit::WebNavigationPolicyCurrentTab);
537     WebViewHost* another = m_shell->createNewWindow(request.url());
538     if (another)
539         another->show(policy);
540 }
541
542 WebNavigationPolicy WebViewHost::decidePolicyForNavigation(
543     WebFrame*, const WebURLRequest&,
544     WebNavigationType, const WebNode&,
545     WebNavigationPolicy defaultPolicy, bool)
546 {
547     return defaultPolicy;
548 }
549
550 bool WebViewHost::canHandleRequest(WebFrame*, const WebURLRequest& request)
551 {
552     return true;
553 }
554
555 WebURLError WebViewHost::cancelledError(WebFrame*, const WebURLRequest& request)
556 {
557     return webkit_support::CreateCancelledError(request);
558 }
559
560 void WebViewHost::unableToImplementPolicyWithError(WebFrame* frame, const WebURLError& error)
561 {
562 }
563
564 void WebViewHost::didCreateDataSource(WebFrame*, WebDataSource* ds)
565 {
566     ds->setExtraData(m_pendingExtraData.leakPtr());
567 }
568
569 void WebViewHost::didCommitProvisionalLoad(WebFrame* frame, bool isNewNavigation)
570 {
571     updateForCommittedLoad(frame, isNewNavigation);
572 }
573
574 void WebViewHost::didClearWindowObject(WebFrame* frame)
575 {
576     m_shell->bindJSObjectsToWindow(frame);
577 }
578
579 void WebViewHost::didReceiveTitle(WebFrame* frame, const WebString& title, WebTextDirection direction)
580 {
581     setPageTitle(title);
582 }
583
584 void WebViewHost::didNavigateWithinPage(WebFrame* frame, bool isNewNavigation)
585 {
586     frame->dataSource()->setExtraData(m_pendingExtraData.leakPtr());
587
588     updateForCommittedLoad(frame, isNewNavigation);
589 }
590
591 void WebViewHost::willSendRequest(WebFrame* frame, unsigned, WebURLRequest& request, const WebURLResponse&)
592 {
593     if (request.url().isEmpty())
594         return;
595
596     request.setExtraData(webkit_support::CreateWebURLRequestExtraData(frame->document().referrerPolicy()));
597 }
598
599 void WebViewHost::openFileSystem(WebFrame* frame, WebFileSystem::Type type, long long size, bool create, WebFileSystemCallbacks* callbacks)
600 {
601     webkit_support::OpenFileSystem(frame, type, size, create, callbacks);
602 }
603
604 void WebViewHost::deleteFileSystem(WebKit::WebFrame* frame, WebKit::WebFileSystem::Type type, WebKit::WebFileSystemCallbacks* callbacks)
605 {
606     webkit_support::DeleteFileSystem(frame, type, callbacks);
607 }
608
609 bool WebViewHost::willCheckAndDispatchMessageEvent(WebFrame* sourceFrame, WebFrame* targetFrame, WebSecurityOrigin target, WebDOMMessageEvent event)
610 {
611     return false;
612 }
613
614 // WebTestDelegate ------------------------------------------------------------
615
616 void WebViewHost::setEditCommand(const string& name, const string& value)
617 {
618     m_editCommandName = name;
619     m_editCommandValue = value;
620 }
621
622 void WebViewHost::clearEditCommand()
623 {
624     m_editCommandName.clear();
625     m_editCommandValue.clear();
626 }
627
628 void WebViewHost::setGamepadData(const WebGamepads& pads)
629 {
630     webkit_support::SetGamepadData(pads);
631 }
632
633 void WebViewHost::printMessage(const std::string& message)
634 {
635     printf("%s", message.c_str());
636 }
637
638 void WebViewHost::postTask(WebTask* task)
639 {
640     ::postTask(task);
641 }
642
643 void WebViewHost::postDelayedTask(WebTask* task, long long ms)
644 {
645     ::postDelayedTask(task, ms);
646 }
647
648 WebString WebViewHost::registerIsolatedFileSystem(const WebVector<WebString>& absoluteFilenames)
649 {
650     return webkit_support::RegisterIsolatedFileSystem(absoluteFilenames);
651 }
652
653 long long WebViewHost::getCurrentTimeInMillisecond()
654 {
655     return webkit_support::GetCurrentTimeInMillisecond();
656 }
657
658 WebKit::WebString WebViewHost::getAbsoluteWebStringFromUTF8Path(const std::string& path)
659 {
660     return webkit_support::GetAbsoluteWebStringFromUTF8Path(path);
661 }
662
663 WebURL WebViewHost::localFileToDataURL(const WebKit::WebURL& url)
664 {
665     return webkit_support::LocalFileToDataURL(url);
666 }
667
668 WebURL WebViewHost::rewriteLayoutTestsURL(const std::string& url)
669 {
670     return webkit_support::RewriteLayoutTestsURL(url);
671 }
672
673 WebPreferences* WebViewHost::preferences()
674 {
675     return m_shell->preferences();
676 }
677
678 void WebViewHost::applyPreferences()
679 {
680     m_shell->applyPreferences();
681 }
682
683 std::string WebViewHost::makeURLErrorDescription(const WebKit::WebURLError& error)
684 {
685     return webkit_support::MakeURLErrorDescription(error);
686 }
687
688 void WebViewHost::showDevTools()
689 {
690     m_shell->showDevTools();
691 }
692
693 void WebViewHost::closeDevTools()
694 {
695     m_shell->closeDevTools();
696 }
697
698 void WebViewHost::evaluateInWebInspector(long callID, const std::string& script)
699 {
700     m_shell->drtDevToolsAgent()->evaluateInWebInspector(callID, script);
701 }
702
703 void WebViewHost::clearAllDatabases()
704 {
705     webkit_support::ClearAllDatabases();
706 }
707
708 void WebViewHost::setDatabaseQuota(int quota)
709 {
710     webkit_support::SetDatabaseQuota(quota);
711 }
712
713 void WebViewHost::setDeviceScaleFactor(float deviceScaleFactor)
714 {
715     webView()->setDeviceScaleFactor(deviceScaleFactor);
716 }
717
718 void WebViewHost::setFocus(bool focused)
719 {
720     m_shell->setFocus(m_shell->webView(), focused);
721 }
722
723 void WebViewHost::setAcceptAllCookies(bool acceptCookies)
724 {
725     webkit_support::SetAcceptAllCookies(acceptCookies);
726 }
727
728 string WebViewHost::pathToLocalResource(const string& url)
729 {
730 #if OS(WINDOWS)
731     if (!url.find("/tmp/")) {
732         // We want a temp file.
733         const unsigned tempPrefixLength = 5;
734         size_t bufferSize = MAX_PATH;
735         OwnArrayPtr<WCHAR> tempPath = adoptArrayPtr(new WCHAR[bufferSize]);
736         DWORD tempLength = ::GetTempPathW(bufferSize, tempPath.get());
737         if (tempLength + url.length() - tempPrefixLength + 1 > bufferSize) {
738             bufferSize = tempLength + url.length() - tempPrefixLength + 1;
739             tempPath = adoptArrayPtr(new WCHAR[bufferSize]);
740             tempLength = GetTempPathW(bufferSize, tempPath.get());
741             ASSERT(tempLength < bufferSize);
742         }
743         string resultPath(WebString(tempPath.get(), tempLength).utf8());
744         resultPath.append(url.substr(tempPrefixLength));
745         return resultPath;
746     }
747 #endif
748
749     // Some layout tests use file://// which we resolve as a UNC path. Normalize
750     // them to just file:///.
751     string lowerUrl = url;
752     string result = url;
753     transform(lowerUrl.begin(), lowerUrl.end(), lowerUrl.begin(), ::tolower);
754     while (!lowerUrl.find("file:////")) {
755         result = result.substr(0, 8) + result.substr(9);
756         lowerUrl = lowerUrl.substr(0, 8) + lowerUrl.substr(9);
757     }
758     return webkit_support::RewriteLayoutTestsURL(result).spec();
759 }
760
761 void WebViewHost::setLocale(const std::string& locale)
762 {
763     setlocale(LC_ALL, locale.c_str());
764 }
765
766 void WebViewHost::setDeviceOrientation(WebKit::WebDeviceOrientation& orientation)
767 {
768     deviceOrientationClientMock()->setOrientation(orientation);
769 }
770
771 int WebViewHost::numberOfPendingGeolocationPermissionRequests()
772 {
773     Vector<WebViewHost*> windowList = m_shell->windowList();
774     int numberOfRequests = 0;
775     for (size_t i = 0; i < windowList.size(); i++)
776         numberOfRequests += windowList[i]->geolocationClientMock()->numberOfPendingPermissionRequests();
777     return numberOfRequests;
778 }
779
780 void WebViewHost::setGeolocationPermission(bool allowed)
781 {
782     Vector<WebViewHost*> windowList = m_shell->windowList();
783     for (size_t i = 0; i < windowList.size(); i++)
784         windowList[i]->geolocationClientMock()->setPermission(allowed);
785 }
786
787 void WebViewHost::setMockGeolocationPosition(double latitude, double longitude, double accuracy)
788 {
789     Vector<WebViewHost*> windowList = m_shell->windowList();
790     for (size_t i = 0; i < windowList.size(); i++)
791         windowList[i]->geolocationClientMock()->setPosition(latitude, longitude, accuracy);
792 }
793
794 void WebViewHost::setMockGeolocationPositionUnavailableError(const std::string& message)
795 {
796     Vector<WebViewHost*> windowList = m_shell->windowList();
797     // FIXME: Benjamin
798     for (size_t i = 0; i < windowList.size(); i++)
799         windowList[i]->geolocationClientMock()->setPositionUnavailableError(WebString::fromUTF8(message));
800 }
801
802 #if ENABLE(INPUT_SPEECH)
803 void WebViewHost::addMockSpeechInputResult(const std::string& result, double confidence, const std::string& language)
804 {
805     m_speechInputControllerMock->addMockRecognitionResult(WebString::fromUTF8(result), confidence, WebString::fromUTF8(language));
806 }
807
808 void WebViewHost::setMockSpeechInputDumpRect(bool dumpRect)
809 {
810     m_speechInputControllerMock->setDumpRect(dumpRect);
811 }
812 #endif
813
814 #if ENABLE(SCRIPTED_SPEECH)
815 void WebViewHost::addMockSpeechRecognitionResult(const std::string& transcript, double confidence)
816 {
817     m_mockSpeechRecognizer->addMockResult(WebString::fromUTF8(transcript), confidence);
818 }
819
820 void WebViewHost::setMockSpeechRecognitionError(const std::string& error, const std::string& message)
821 {
822     m_mockSpeechRecognizer->setError(WebString::fromUTF8(error), WebString::fromUTF8(message));
823 }
824
825 bool WebViewHost::wasMockSpeechRecognitionAborted()
826 {
827     return m_mockSpeechRecognizer->wasAborted();
828 }
829 #endif
830
831 void WebViewHost::testFinished()
832 {
833     m_shell->testFinished(this);
834 }
835
836 void WebViewHost::testTimedOut()
837 {
838     m_shell->testTimedOut();
839 }
840
841 bool WebViewHost::isBeingDebugged()
842 {
843     return webkit_support::BeingDebugged();
844 }
845
846 int WebViewHost::layoutTestTimeout()
847 {
848     return m_shell->layoutTestTimeout();
849 }
850
851 void WebViewHost::closeRemainingWindows()
852 {
853     m_shell->closeRemainingWindows();
854 }
855
856 int WebViewHost::navigationEntryCount()
857 {
858     return m_shell->navigationEntryCount();
859 }
860
861 int WebViewHost::windowCount()
862 {
863     return m_shell->windowCount();
864 }
865
866 void WebViewHost::goToOffset(int offset)
867 {
868     m_shell->goToOffset(offset);
869 }
870
871 void WebViewHost::reload()
872 {
873     m_shell->reload();
874 }
875
876 void WebViewHost::loadURLForFrame(const WebURL& url, const string& frameName)
877 {
878     if (!url.isValid())
879         return;
880     TestShell::resizeWindowForTest(this, url);
881     navigationController()->loadEntry(TestNavigationEntry::create(-1, url, WebString(), WebString::fromUTF8(frameName)).get());
882 }
883
884 bool WebViewHost::allowExternalPages()
885 {
886     return m_shell->allowExternalPages();
887 }
888
889 void WebViewHost::captureHistoryForWindow(size_t windowIndex, WebVector<WebHistoryItem>* history, size_t* currentEntryIndex)
890 {
891     m_shell->captureHistoryForWindow(windowIndex, history, currentEntryIndex);
892 }
893
894 // Public functions -----------------------------------------------------------
895
896 WebViewHost::WebViewHost(TestShell* shell)
897     : m_shell(shell)
898     , m_proxy(0)
899     , m_webWidget(0)
900     , m_shutdownWasInvoked(false)
901 {
902     reset();
903 }
904
905 WebViewHost::~WebViewHost()
906 {
907     ASSERT(m_shutdownWasInvoked);
908     if (m_inModalLoop)
909         webkit_support::QuitMessageLoop();
910 }
911
912 void WebViewHost::shutdown()
913 {
914     ASSERT(!m_shutdownWasInvoked);
915
916     // DevTools frontend page is supposed to be navigated only once and
917     // loading another URL in that Page is an error.
918     if (m_shell->devToolsWebView() != this) {
919         // Navigate to an empty page to fire all the destruction logic for the
920         // current page.
921         loadURLForFrame(GURL("about:blank"), string());
922     }
923
924     for (Vector<WebKit::WebWidget*>::iterator it = m_popupmenus.begin();
925          it < m_popupmenus.end(); ++it)
926         (*it)->close();
927
928     webWidget()->willCloseLayerTreeView();
929     m_layerTreeView.clear();
930     webWidget()->close();
931     m_webWidget = 0;
932     m_shutdownWasInvoked = true;
933 }
934
935 void WebViewHost::setWebWidget(WebKit::WebWidget* widget)
936 {
937     m_webWidget = widget;
938     webView()->setSpellCheckClient(proxy()->spellCheckClient());
939     webView()->setPrerendererClient(this);
940 }
941
942 WebView* WebViewHost::webView() const
943 {
944     ASSERT(m_webWidget);
945     // DRT does not support popup widgets. So m_webWidget is always a WebView.
946     return static_cast<WebView*>(m_webWidget);
947 }
948
949 WebWidget* WebViewHost::webWidget() const
950 {
951     ASSERT(m_webWidget);
952     return m_webWidget;
953 }
954
955 WebTestProxyBase* WebViewHost::proxy() const
956 {
957     ASSERT(m_proxy);
958     return m_proxy;
959 }
960
961 void WebViewHost::setProxy(WebTestProxyBase* proxy)
962 {
963     ASSERT(!m_proxy);
964     ASSERT(proxy);
965     m_proxy = proxy;
966 }
967
968 void WebViewHost::reset()
969 {
970     m_pageId = -1;
971     m_lastPageIdUpdated = -1;
972     m_hasWindow = false;
973     m_inModalLoop = false;
974 #if ENABLE(POINTER_LOCK)
975     m_pointerLocked = false;
976     m_pointerLockPlannedResult = PointerLockWillSucceed;
977 #endif
978
979     m_navigationController = adoptPtr(new TestNavigationController(this));
980
981     m_pendingExtraData.clear();
982     m_editCommandName.clear();
983     m_editCommandValue.clear();
984
985     if (m_geolocationClientMock.get())
986         m_geolocationClientMock->resetMock();
987
988 #if ENABLE(INPUT_SPEECH)
989     if (m_speechInputControllerMock.get())
990         m_speechInputControllerMock->clearResults();
991 #endif
992
993     m_currentCursor = WebCursorInfo();
994     m_windowRect = WebRect();
995     // m_proxy is not set when reset() is invoked from the constructor.
996     if (m_proxy)
997         proxy()->reset();
998
999     if (m_webWidget) {
1000         webView()->mainFrame()->setName(WebString());
1001     }
1002 }
1003
1004 void WebViewHost::setClientWindowRect(const WebKit::WebRect& rect)
1005 {
1006     setWindowRect(rect);
1007 }
1008
1009 bool WebViewHost::navigate(const TestNavigationEntry& entry, bool reload)
1010 {
1011     // Get the right target frame for the entry.
1012     WebFrame* frame = webView()->mainFrame();
1013     if (!entry.targetFrame().isEmpty())
1014         frame = webView()->findFrameByName(entry.targetFrame());
1015
1016     // TODO(mpcomplete): should we clear the target frame, or should
1017     // back/forward navigations maintain the target frame?
1018
1019     // A navigation resulting from loading a javascript URL should not be
1020     // treated as a browser initiated event. Instead, we want it to look as if
1021     // the page initiated any load resulting from JS execution.
1022     if (!GURL(entry.URL()).SchemeIs("javascript"))
1023         setPendingExtraData(adoptPtr(new TestShellExtraData(entry.pageID())));
1024
1025     // If we are reloading, then WebKit will use the state of the current page.
1026     // Otherwise, we give it the state to navigate to.
1027     if (reload) {
1028         frame->reload(false);
1029     } else if (!entry.contentState().isNull()) {
1030         ASSERT(entry.pageID() != -1);
1031         frame->loadHistoryItem(entry.contentState());
1032     } else {
1033         ASSERT(entry.pageID() == -1);
1034         frame->loadRequest(WebURLRequest(entry.URL()));
1035     }
1036
1037     // In case LoadRequest failed before DidCreateDataSource was called.
1038     setPendingExtraData(nullptr);
1039
1040     // Restore focus to the main frame prior to loading new request.
1041     // This makes sure that we don't have a focused iframe. Otherwise, that
1042     // iframe would keep focus when the SetFocus called immediately after
1043     // LoadRequest, thus making some tests fail (see http://b/issue?id=845337
1044     // for more details).
1045     webView()->setFocusedFrame(frame);
1046     m_shell->setFocus(webView(), true);
1047
1048     return true;
1049 }
1050
1051 // Private functions ----------------------------------------------------------
1052
1053 void WebViewHost::updateForCommittedLoad(WebFrame* frame, bool isNewNavigation)
1054 {
1055     // Code duplicated from RenderView::DidCommitLoadForFrame.
1056     TestShellExtraData* extraData = static_cast<TestShellExtraData*>(frame->dataSource()->extraData());
1057     const WebURL& url = frame->dataSource()->request().url();
1058     bool nonBlankPageAfterReset = m_pageId == -1 && !url.isEmpty() && strcmp(url.spec().data(), "about:blank");
1059
1060     if (isNewNavigation || nonBlankPageAfterReset) {
1061         // New navigation.
1062         updateSessionHistory(frame);
1063         m_pageId = nextPageID++;
1064     } else if (extraData && extraData->pendingPageID != -1 && !extraData->requestCommitted) {
1065         // This is a successful session history navigation!
1066         updateSessionHistory(frame);
1067         m_pageId = extraData->pendingPageID;
1068     }
1069
1070     // Don't update session history multiple times.
1071     if (extraData)
1072         extraData->requestCommitted = true;
1073
1074     updateURL(frame);
1075 }
1076
1077 void WebViewHost::updateURL(WebFrame* frame)
1078 {
1079     WebDataSource* ds = frame->dataSource();
1080     ASSERT(ds);
1081     const WebURLRequest& request = ds->request();
1082     RefPtr<TestNavigationEntry> entry(TestNavigationEntry::create());
1083
1084     // The referrer will be empty on https->http transitions. It
1085     // would be nice if we could get the real referrer from somewhere.
1086     entry->setPageID(m_pageId);
1087     if (ds->hasUnreachableURL())
1088         entry->setURL(ds->unreachableURL());
1089     else
1090         entry->setURL(request.url());
1091
1092     const WebHistoryItem& historyItem = frame->currentHistoryItem();
1093     if (!historyItem.isNull())
1094         entry->setContentState(historyItem);
1095
1096     navigationController()->didNavigateToEntry(entry.get());
1097     m_lastPageIdUpdated = max(m_lastPageIdUpdated, m_pageId);
1098 }
1099
1100 void WebViewHost::updateSessionHistory(WebFrame* frame)
1101 {
1102     // If we have a valid page ID at this point, then it corresponds to the page
1103     // we are navigating away from. Otherwise, this is the first navigation, so
1104     // there is no past session history to record.
1105     if (m_pageId == -1)
1106         return;
1107
1108     TestNavigationEntry* entry = navigationController()->entryWithPageID(m_pageId);
1109     if (!entry)
1110         return;
1111
1112     const WebHistoryItem& historyItem = webView()->mainFrame()->previousHistoryItem();
1113     if (historyItem.isNull())
1114         return;
1115
1116     entry->setContentState(historyItem);
1117 }
1118
1119 void WebViewHost::printFrameDescription(WebFrame* webframe)
1120 {
1121     string name8 = webframe->uniqueName().utf8();
1122     if (webframe == webView()->mainFrame()) {
1123         if (!name8.length()) {
1124             fputs("main frame", stdout);
1125             return;
1126         }
1127         printf("main frame \"%s\"", name8.c_str());
1128         return;
1129     }
1130     if (!name8.length()) {
1131         fputs("frame (anonymous)", stdout);
1132         return;
1133     }
1134     printf("frame \"%s\"", name8.c_str());
1135 }
1136
1137 void WebViewHost::setPendingExtraData(PassOwnPtr<TestShellExtraData> extraData)
1138 {
1139     m_pendingExtraData = extraData;
1140 }
1141
1142 void WebViewHost::setPageTitle(const WebString&)
1143 {
1144     // Nothing to do in layout test.
1145 }
1146
1147 void WebViewHost::enterFullScreenNow()
1148 {
1149     webView()->willEnterFullScreen();
1150     webView()->didEnterFullScreen();
1151 }
1152
1153 void WebViewHost::exitFullScreenNow()
1154 {
1155     webView()->willExitFullScreen();
1156     webView()->didExitFullScreen();
1157 }
1158
1159 #if ENABLE(MEDIA_STREAM)
1160 webkit_support::TestMediaStreamClient* WebViewHost::testMediaStreamClient()
1161 {
1162     if (!m_testMediaStreamClient.get())
1163         m_testMediaStreamClient = adoptPtr(new webkit_support::TestMediaStreamClient());
1164     return m_testMediaStreamClient.get();
1165 }
1166 #endif