a39d58751b6e4be828f5dd52ef8d7b026537c2d1
[WebKit-https.git] / Source / WebKit / win / WebCoreSupport / WebChromeClient.cpp
1 /*
2  * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
3  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "WebChromeClient.h"
28
29 #include "COMPropertyBag.h"
30 #include "COMVariantSetter.h"
31 #include "DOMCoreClasses.h"
32 #include "WebElementPropertyBag.h"
33 #include "WebFrame.h"
34 #include "WebHistory.h"
35 #include "WebMutableURLRequest.h"
36 #include "WebDesktopNotificationsDelegate.h"
37 #include "WebSecurityOrigin.h"
38 #include "WebView.h"
39 #include <WebCore/BString.h>
40 #include <WebCore/ContextMenu.h>
41 #include <WebCore/Cursor.h>
42 #include <WebCore/FileChooser.h>
43 #include <WebCore/FileIconLoader.h>
44 #include <WebCore/FloatRect.h>
45 #include <WebCore/Frame.h>
46 #include <WebCore/FrameLoadRequest.h>
47 #include <WebCore/FrameView.h>
48 #include <WebCore/FullScreenController.h>
49 #include <WebCore/GraphicsLayer.h>
50 #include <WebCore/HTMLNames.h>
51 #include <WebCore/HTMLVideoElement.h>
52 #include <WebCore/Icon.h>
53 #include <WebCore/LocalWindowsContext.h>
54 #include <WebCore/LocalizedStrings.h>
55 #include <WebCore/NavigationAction.h>
56 #include <WebCore/NotImplemented.h>
57 #include <WebCore/Page.h>
58 #include <WebCore/SecurityOrigin.h>
59 #include <WebCore/PopupMenuWin.h>
60 #include <WebCore/SearchPopupMenuWin.h>
61 #include <WebCore/WindowFeatures.h>
62 #include <wchar.h>
63
64 using namespace WebCore;
65
66 // When you call GetOpenFileName, if the size of the buffer is too small,
67 // MSDN says that the first two bytes of the buffer contain the required size for the file selection, in bytes or characters
68 // So we can assume the required size can't be more than the maximum value for a short.
69 static const size_t maxFilePathsListSize = USHRT_MAX;
70
71 WebChromeClient::WebChromeClient(WebView* webView)
72     : m_webView(webView)
73 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
74     , m_notificationsDelegate(std::make_unique<WebDesktopNotificationsDelegate>(webView))
75 #endif
76 {
77 }
78
79 void WebChromeClient::chromeDestroyed()
80 {
81     delete this;
82 }
83
84 void WebChromeClient::setWindowRect(const FloatRect& r)
85 {
86     IWebUIDelegate* uiDelegate = 0;
87     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
88         RECT rect = IntRect(r);
89         uiDelegate->setFrame(m_webView, &rect);
90         uiDelegate->Release();
91     }
92 }
93
94 FloatRect WebChromeClient::windowRect()
95 {
96     IWebUIDelegate* uiDelegate = 0;
97     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
98         RECT rect;
99         HRESULT retval = uiDelegate->webViewFrame(m_webView, &rect);
100
101         uiDelegate->Release();
102
103         if (SUCCEEDED(retval))
104             return rect;
105     }
106
107     return FloatRect();
108 }
109
110 FloatRect WebChromeClient::pageRect()
111 {
112     RECT rect;
113     m_webView->frameRect(&rect);
114     return rect;
115 }
116
117 void WebChromeClient::focus()
118 {
119     IWebUIDelegate* uiDelegate = 0;
120     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
121         uiDelegate->webViewFocus(m_webView);
122         uiDelegate->Release();
123     }
124     // Normally this would happen on a timer, but JS might need to know this earlier, so we'll update here.
125     m_webView->updateActiveState();
126 }
127
128 void WebChromeClient::unfocus()
129 {
130     IWebUIDelegate* uiDelegate = 0;
131     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
132         uiDelegate->webViewUnfocus(m_webView);
133         uiDelegate->Release();
134     }
135     // Normally this would happen on a timer, but JS might need to know this earlier, so we'll update here.
136     m_webView->updateActiveState();
137 }
138
139 bool WebChromeClient::canTakeFocus(FocusDirection direction)
140 {
141     IWebUIDelegate* uiDelegate = 0;
142     BOOL bForward = (direction == FocusDirectionForward) ? TRUE : FALSE;
143     BOOL result = FALSE;
144     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
145         uiDelegate->canTakeFocus(m_webView, bForward, &result);
146         uiDelegate->Release();
147     }
148
149     return !!result;
150 }
151
152 void WebChromeClient::takeFocus(FocusDirection direction)
153 {
154     IWebUIDelegate* uiDelegate = 0;
155     BOOL bForward = (direction == FocusDirectionForward) ? TRUE : FALSE;
156     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
157         uiDelegate->takeFocus(m_webView, bForward);
158         uiDelegate->Release();
159     }
160 }
161
162 void WebChromeClient::focusedElementChanged(Element*)
163 {
164 }
165
166 void WebChromeClient::focusedFrameChanged(Frame*)
167 {
168 }
169
170 static COMPtr<IPropertyBag> createWindowFeaturesPropertyBag(const WindowFeatures& features)
171 {
172     HashMap<String, COMVariant> map;
173     if (features.x)
174         map.set(WebWindowFeaturesXKey, *features.x);
175     if (features.y)
176         map.set(WebWindowFeaturesYKey, *features.y);
177     if (features.width)
178         map.set(WebWindowFeaturesWidthKey, *features.width);
179     if (features.height)
180         map.set(WebWindowFeaturesHeightKey, *features.height);
181     map.set(WebWindowFeaturesMenuBarVisibleKey, features.menuBarVisible);
182     map.set(WebWindowFeaturesStatusBarVisibleKey, features.statusBarVisible);
183     map.set(WebWindowFeaturesToolBarVisibleKey, features.toolBarVisible);
184     map.set(WebWindowFeaturesScrollbarsVisibleKey, features.scrollbarsVisible);
185     map.set(WebWindowFeaturesResizableKey, features.resizable);
186     map.set(WebWindowFeaturesFullscreenKey, features.fullscreen);
187     map.set(WebWindowFeaturesDialogKey, features.dialog);
188
189     return COMPtr<IPropertyBag>(AdoptCOM, COMPropertyBag<COMVariant>::adopt(map));
190 }
191
192 Page* WebChromeClient::createWindow(Frame* frame, const FrameLoadRequest&, const WindowFeatures& features, const NavigationAction& navigationAction)
193 {
194     COMPtr<IWebUIDelegate> delegate = uiDelegate();
195     if (!delegate)
196         return 0;
197
198 #if ENABLE(FULLSCREEN_API)
199     if (frame->document() && frame->document()->webkitCurrentFullScreenElement())
200         frame->document()->webkitCancelFullScreen();
201 #endif
202
203     COMPtr<WebMutableURLRequest> request = adoptCOM(WebMutableURLRequest::createInstance(ResourceRequest(navigationAction.url())));
204
205     COMPtr<IWebUIDelegatePrivate2> delegatePrivate(Query, delegate);
206     if (delegatePrivate) {
207         COMPtr<IWebView> newWebView;
208         HRESULT hr = delegatePrivate->createWebViewWithRequest(m_webView, request.get(), createWindowFeaturesPropertyBag(features).get(), &newWebView);
209
210         if (SUCCEEDED(hr) && newWebView)
211             return core(newWebView.get());
212
213         // If the delegate doesn't implement the IWebUIDelegatePrivate2 version of the call, fall back
214         // to the old versions (even if they support the IWebUIDelegatePrivate2 interface).
215         if (hr != E_NOTIMPL)
216             return 0;
217     }
218
219     COMPtr<IWebView> newWebView;
220
221     if (features.dialog) {
222         if (FAILED(delegate->createModalDialog(m_webView, request.get(), &newWebView)))
223             return 0;
224     } else if (FAILED(delegate->createWebViewWithRequest(m_webView, request.get(), &newWebView)))
225         return 0;
226
227     return newWebView ? core(newWebView.get()) : 0;
228 }
229
230 void WebChromeClient::show()
231 {
232     IWebUIDelegate* uiDelegate = 0;
233     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
234         uiDelegate->webViewShow(m_webView);
235         uiDelegate->Release();
236     }
237 }
238
239 bool WebChromeClient::canRunModal()
240 {
241     BOOL result = FALSE;
242     if (COMPtr<IWebUIDelegate> delegate = uiDelegate())
243         delegate->canRunModal(m_webView, &result);
244     return result;
245 }
246
247 void WebChromeClient::runModal()
248 {
249     if (COMPtr<IWebUIDelegate> delegate = uiDelegate())
250         delegate->runModal(m_webView);
251 }
252
253 void WebChromeClient::setToolbarsVisible(bool visible)
254 {
255     IWebUIDelegate* uiDelegate = 0;
256     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
257         uiDelegate->setToolbarsVisible(m_webView, visible);
258         uiDelegate->Release();
259     }
260 }
261
262 bool WebChromeClient::toolbarsVisible()
263 {
264     BOOL result = false;
265     IWebUIDelegate* uiDelegate = 0;
266     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
267         uiDelegate->webViewAreToolbarsVisible(m_webView, &result);
268         uiDelegate->Release();
269     }
270     return result != false;
271 }
272
273 void WebChromeClient::setStatusbarVisible(bool visible)
274 {
275     IWebUIDelegate* uiDelegate = 0;
276     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
277         uiDelegate->setStatusBarVisible(m_webView, visible);
278         uiDelegate->Release();
279     }
280 }
281
282 bool WebChromeClient::statusbarVisible()
283 {
284     BOOL result = false;
285     IWebUIDelegate* uiDelegate = 0;
286     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
287         uiDelegate->webViewIsStatusBarVisible(m_webView, &result);
288         uiDelegate->Release();
289     }
290     return result != false;
291 }
292
293 void WebChromeClient::setScrollbarsVisible(bool b)
294 {
295     WebFrame* webFrame = m_webView->topLevelFrame();
296     if (webFrame)
297         webFrame->setAllowsScrolling(b);
298 }
299
300 bool WebChromeClient::scrollbarsVisible()
301 {
302     WebFrame* webFrame = m_webView->topLevelFrame();
303     BOOL b = false;
304     if (webFrame)
305         webFrame->allowsScrolling(&b);
306
307     return !!b;
308 }
309
310 void WebChromeClient::setMenubarVisible(bool visible)
311 {
312     COMPtr<IWebUIDelegate> delegate = uiDelegate();
313     if (!delegate)
314         return;
315     delegate->setMenuBarVisible(m_webView, visible);
316 }
317
318 bool WebChromeClient::menubarVisible()
319 {
320     COMPtr<IWebUIDelegate> delegate = uiDelegate();
321     if (!delegate)
322         return true;
323     BOOL result = true;
324     delegate->isMenuBarVisible(m_webView, &result);
325     return result;
326 }
327
328 void WebChromeClient::setResizable(bool resizable)
329 {
330     IWebUIDelegate* uiDelegate = 0;
331     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
332         uiDelegate->setResizable(m_webView, resizable);
333         uiDelegate->Release();
334     }
335 }
336
337 static BOOL messageIsError(MessageLevel level)
338 {
339     return level == MessageLevel::Error;
340 }
341
342 void WebChromeClient::addMessageToConsole(MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, unsigned columnNumber, const String& url)
343 {
344     UNUSED_PARAM(columnNumber);
345
346     COMPtr<IWebUIDelegate> uiDelegate;
347     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
348         COMPtr<IWebUIDelegatePrivate> uiPrivate;
349         if (SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&uiPrivate)))
350             uiPrivate->webViewAddMessageToConsole(m_webView, BString(message), lineNumber, BString(url), messageIsError(level));
351     }
352 }
353
354 bool WebChromeClient::canRunBeforeUnloadConfirmPanel()
355 {
356     IWebUIDelegate* ui;
357     if (SUCCEEDED(m_webView->uiDelegate(&ui)) && ui) {
358         ui->Release();
359         return true;
360     }
361     return false;
362 }
363
364 bool WebChromeClient::runBeforeUnloadConfirmPanel(const String& message, Frame* frame)
365 {
366     BOOL result = TRUE;
367     IWebUIDelegate* ui;
368     if (SUCCEEDED(m_webView->uiDelegate(&ui)) && ui) {
369         WebFrame* webFrame = kit(frame);
370         ui->runBeforeUnloadConfirmPanelWithMessage(m_webView, BString(message), webFrame, &result);
371         ui->Release();
372     }
373     return !!result;
374 }
375
376 void WebChromeClient::closeWindowSoon()
377 {
378     // We need to remove the parent WebView from WebViewSets here, before it actually
379     // closes, to make sure that JavaScript code that executes before it closes
380     // can't find it. Otherwise, window.open will select a closed WebView instead of 
381     // opening a new one <rdar://problem/3572585>.
382
383     // We also need to stop the load to prevent further parsing or JavaScript execution
384     // after the window has torn down <rdar://problem/4161660>.
385   
386     // FIXME: This code assumes that the UI delegate will respond to a webViewClose
387     // message by actually closing the WebView. Safari guarantees this behavior, but other apps might not.
388     // This approach is an inherent limitation of not making a close execute immediately
389     // after a call to window.close.
390
391     m_webView->setGroupName(0);
392     m_webView->stopLoading(0);
393     m_webView->closeWindowSoon();
394 }
395
396 void WebChromeClient::runJavaScriptAlert(Frame*, const String& message)
397 {
398     COMPtr<IWebUIDelegate> ui;
399     if (SUCCEEDED(m_webView->uiDelegate(&ui)))
400         ui->runJavaScriptAlertPanelWithMessage(m_webView, BString(message));
401 }
402
403 bool WebChromeClient::runJavaScriptConfirm(Frame*, const String& message)
404 {
405     BOOL result = FALSE;
406     COMPtr<IWebUIDelegate> ui;
407     if (SUCCEEDED(m_webView->uiDelegate(&ui)))
408         ui->runJavaScriptConfirmPanelWithMessage(m_webView, BString(message), &result);
409     return !!result;
410 }
411
412 bool WebChromeClient::runJavaScriptPrompt(Frame*, const String& message, const String& defaultValue, String& result)
413 {
414     COMPtr<IWebUIDelegate> ui;
415     if (FAILED(m_webView->uiDelegate(&ui)))
416         return false;
417
418     TimerBase::fireTimersInNestedEventLoop();
419
420     BString resultBSTR;
421     if (FAILED(ui->runJavaScriptTextInputPanelWithPrompt(m_webView, BString(message), BString(defaultValue), &resultBSTR)))
422         return false;
423
424     if (!resultBSTR)
425         return false;
426
427     result = String(resultBSTR, SysStringLen(resultBSTR));
428     return true;
429 }
430
431 void WebChromeClient::setStatusbarText(const String& statusText)
432 {
433     COMPtr<IWebUIDelegate> uiDelegate;
434     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
435         uiDelegate->setStatusText(m_webView, BString(statusText));
436     }
437 }
438
439 KeyboardUIMode WebChromeClient::keyboardUIMode()
440 {
441     BOOL enabled = FALSE;
442     IWebPreferences* preferences;
443     if (SUCCEEDED(m_webView->preferences(&preferences)))
444         preferences->tabsToLinks(&enabled);
445
446     return enabled ? KeyboardAccessTabsToLinks : KeyboardAccessDefault;
447 }
448
449 void WebChromeClient::invalidateRootView(const IntRect& windowRect)
450 {
451     ASSERT(core(m_webView->topLevelFrame()));
452     m_webView->repaint(windowRect, false /*contentChanged*/, false /*immediate*/, false /*repaintContentOnly*/);
453 }
454
455 void WebChromeClient::invalidateContentsAndRootView(const IntRect& windowRect)
456 {
457     ASSERT(core(m_webView->topLevelFrame()));
458     m_webView->repaint(windowRect, true /*contentChanged*/, false /*immediate*/, false /*repaintContentOnly*/);
459 }
460
461 void WebChromeClient::invalidateContentsForSlowScroll(const IntRect& windowRect)
462 {
463     ASSERT(core(m_webView->topLevelFrame()));
464     m_webView->repaint(windowRect, true /*contentChanged*/, false /*immediate*/, true /*repaintContentOnly*/);
465 }
466
467 void WebChromeClient::scroll(const IntSize& delta, const IntRect& scrollViewRect, const IntRect& clipRect)
468 {
469     ASSERT(core(m_webView->topLevelFrame()));
470
471     m_webView->scrollBackingStore(core(m_webView->topLevelFrame())->view(), delta.width(), delta.height(), scrollViewRect, clipRect);
472 }
473
474 IntRect WebChromeClient::rootViewToScreen(const IntRect& rect) const
475 {
476     HWND viewWindow;
477     if (FAILED(m_webView->viewWindow(&viewWindow)))
478         return rect;
479
480     // Find the top left corner of the Widget's containing window in screen coords,
481     // and adjust the result rect's position by this amount.
482     POINT topLeft = {0, 0};
483     IntRect result = rect;
484     ::ClientToScreen(viewWindow, &topLeft);
485     result.move(topLeft.x, topLeft.y);
486
487     return result;
488 }
489
490 IntPoint WebChromeClient::screenToRootView(const IntPoint& point) const
491 {
492     POINT result = point;
493
494     HWND viewWindow;
495     if (FAILED(m_webView->viewWindow(&viewWindow)))
496         return point;
497
498     ::ScreenToClient(viewWindow, &result);
499
500     return result;
501 }
502
503 PlatformPageClient WebChromeClient::platformPageClient() const
504 {
505     HWND viewWindow;
506     if (FAILED(m_webView->viewWindow(&viewWindow)))
507         return 0;
508     return viewWindow;
509 }
510
511 void WebChromeClient::contentsSizeChanged(Frame*, const IntSize&) const
512 {
513     notImplemented();
514 }
515
516 void WebChromeClient::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags)
517 {
518     COMPtr<IWebUIDelegate> uiDelegate;
519     if (FAILED(m_webView->uiDelegate(&uiDelegate)))
520         return;
521
522     COMPtr<WebElementPropertyBag> element;
523     element.adoptRef(WebElementPropertyBag::createInstance(result));
524
525     uiDelegate->mouseDidMoveOverElement(m_webView, element.get(), modifierFlags);
526 }
527
528 bool WebChromeClient::shouldUnavailablePluginMessageBeButton(RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason) const
529 {
530     if (pluginUnavailabilityReason != RenderEmbeddedObject::PluginMissing)
531         return false;
532
533     COMPtr<IWebUIDelegate> uiDelegate;
534     if (FAILED(m_webView->uiDelegate(&uiDelegate)))
535         return false;
536     
537     // If the UI delegate implements IWebUIDelegatePrivate3, 
538     // which contains didPressMissingPluginButton, then the message should be a button.
539     COMPtr<IWebUIDelegatePrivate3> uiDelegatePrivate3(Query, uiDelegate);
540     return uiDelegatePrivate3;
541 }
542
543 void WebChromeClient::unavailablePluginButtonClicked(Element* element, RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason) const
544 {
545     ASSERT_UNUSED(pluginUnavailabilityReason, pluginUnavailabilityReason == RenderEmbeddedObject::PluginMissing);
546
547     COMPtr<IWebUIDelegate> uiDelegate;
548     if (FAILED(m_webView->uiDelegate(&uiDelegate)))
549         return;
550
551     COMPtr<IWebUIDelegatePrivate3> uiDelegatePrivate3(Query, uiDelegate);
552     if (!uiDelegatePrivate3)
553         return;
554
555     COMPtr<IDOMElement> e(AdoptCOM, DOMElement::createInstance(element));
556     uiDelegatePrivate3->didPressMissingPluginButton(e.get());
557 }
558
559 void WebChromeClient::setToolTip(const String& toolTip, TextDirection)
560 {
561     m_webView->setToolTip(toolTip);
562 }
563
564 void WebChromeClient::print(Frame* frame)
565 {
566     COMPtr<IWebUIDelegate> uiDelegate;
567     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate)))
568         uiDelegate->printFrame(m_webView, kit(frame));
569 }
570
571 void WebChromeClient::exceededDatabaseQuota(Frame* frame, const String& databaseIdentifier, DatabaseDetails)
572 {
573     COMPtr<WebSecurityOrigin> origin(AdoptCOM, WebSecurityOrigin::createInstance(frame->document()->securityOrigin()));
574     COMPtr<IWebUIDelegate> uiDelegate;
575     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
576         COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate(Query, uiDelegate);
577         if (uiDelegatePrivate)
578             uiDelegatePrivate->exceededDatabaseQuota(m_webView, kit(frame), origin.get(), BString(databaseIdentifier));
579         else {
580             // FIXME: remove this workaround once shipping Safari has the necessary delegate implemented.
581             WCHAR path[MAX_PATH];
582             HMODULE safariHandle = GetModuleHandleW(L"Safari.exe");
583             if (!safariHandle)
584                 return;
585             if (!::GetModuleFileName(safariHandle, path, WTF_ARRAY_LENGTH(path)))
586                 return;
587             DWORD handle = 0;
588             DWORD versionSize = GetFileVersionInfoSize(path, &handle);
589             if (!versionSize)
590                 return;
591             Vector<char> data(versionSize);
592             if (!GetFileVersionInfo(path, 0, versionSize, data.data()))
593                 return;
594
595             LPCTSTR productVersion;
596             UINT productVersionLength;
597             if (!VerQueryValueW(data.data(), L"\\StringFileInfo\\040904b0\\ProductVersion", (void**)&productVersion, &productVersionLength))
598                 return;
599             if (wcsncmp(L"3.1", productVersion, productVersionLength) > 0) {
600                 const unsigned long long defaultQuota = 5 * 1024 * 1024; // 5 megabytes should hopefully be enough to test storage support.
601                 origin->setQuota(defaultQuota);
602             }
603         }
604     }
605 }
606
607 // FIXME: Move this include to the top of the file with the other includes.
608 #include "ApplicationCacheStorage.h"
609
610 void WebChromeClient::reachedMaxAppCacheSize(int64_t spaceNeeded)
611 {
612     // FIXME: Free some space.
613     notImplemented();
614 }
615
616 void WebChromeClient::reachedApplicationCacheOriginQuota(SecurityOrigin*, int64_t)
617 {
618     notImplemented();
619 }
620
621 void WebChromeClient::runOpenPanel(Frame&, FileChooser& fileChooser)
622 {
623     HWND viewWindow;
624     if (FAILED(m_webView->viewWindow(&viewWindow)))
625         return;
626
627     bool multiFile = fileChooser.settings().allowsMultipleFiles;
628     Vector<WCHAR> fileBuf(multiFile ? maxFilePathsListSize : MAX_PATH);
629
630     OPENFILENAME ofn;
631
632     memset(&ofn, 0, sizeof(ofn));
633
634     // Need to zero out the first char of fileBuf so GetOpenFileName doesn't think it's an initialization string
635     fileBuf[0] = '\0';
636
637     ofn.lStructSize = sizeof(ofn);
638     ofn.hwndOwner = viewWindow;
639     String allFiles = allFilesText();
640     allFiles.append(L"\0*.*\0\0", 6);
641
642     Vector<UChar> filterCharacters = allFiles.charactersWithNullTermination(); // Retain buffer long enough to make the GetOpenFileName call
643     ofn.lpstrFilter = filterCharacters.data();
644
645     ofn.lpstrFile = fileBuf.data();
646     ofn.nMaxFile = fileBuf.size();
647     String dialogTitle = uploadFileText();
648     Vector<UChar> dialogTitleCharacters = dialogTitle.charactersWithNullTermination(); // Retain buffer long enough to make the GetOpenFileName call
649     ofn.lpstrTitle = dialogTitleCharacters.data();
650     ofn.Flags = OFN_ENABLESIZING | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_EXPLORER;
651     if (multiFile)
652         ofn.Flags = ofn.Flags | OFN_ALLOWMULTISELECT;
653
654     if (GetOpenFileName(&ofn)) {
655         WCHAR* files = fileBuf.data();
656         Vector<String> fileList;
657         String file(files);
658         if (multiFile) {
659             while (!file.isEmpty()) {
660                 // When using the OFN_EXPLORER flag, the file list is null delimited.
661                 // When you create a String from a ptr to this list, it will use strlen to look for the null character.
662                 // Then we find the next file path string by using the length of the string we just created.
663                 WCHAR* nextFilePtr = files + file.length() + 1;
664                 String nextFile(nextFilePtr);
665                 // If multiple files are selected, there will be a directory name first, which we don't want to add to the vector.
666                 // We know a single file was selected if there is only one filename in the list.  
667                 // In that case, we don't want to skip adding the first (and only) name.
668                 if (files != fileBuf.data() || nextFile.isEmpty())
669                     fileList.append(file);
670                 files = nextFilePtr;
671                 file = nextFile;
672             }
673         } else
674             fileList.append(file);
675         ASSERT(fileList.size());
676         fileChooser.chooseFiles(fileList);
677     }
678     // FIXME: Show some sort of error if too many files are selected and the buffer is too small.  For now, this will fail silently.
679 }
680
681 void WebChromeClient::loadIconForFiles(const Vector<WTF::String>& filenames, WebCore::FileIconLoader& loader)
682 {
683     loader.iconLoaded(Icon::createIconForFiles(filenames));
684 }
685
686 void WebChromeClient::setCursor(const Cursor& cursor)
687 {
688     if (!cursor.platformCursor())
689         return;
690
691     HCURSOR platformCursor = cursor.platformCursor()->nativeCursor();
692     if (!platformCursor)
693         return;
694
695     bool shouldSetCursor = true;
696     if (COMPtr<IWebUIDelegate> delegate = uiDelegate()) {
697         COMPtr<IWebUIDelegatePrivate> delegatePrivate(Query, delegate);
698         if (delegatePrivate) {
699             if (SUCCEEDED(delegatePrivate->webViewSetCursor(m_webView, platformCursor)))
700                 shouldSetCursor = false;
701         }
702     }
703
704     if (shouldSetCursor)
705         ::SetCursor(platformCursor);
706
707     setLastSetCursorToCurrentCursor();
708 }
709
710 void WebChromeClient::setCursorHiddenUntilMouseMoves(bool)
711 {
712     notImplemented();
713 }
714
715 void WebChromeClient::setLastSetCursorToCurrentCursor()
716 {
717     m_webView->setLastCursor(::GetCursor());
718 }
719
720 void WebChromeClient::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* graphicsLayer)
721 {
722     m_webView->setRootChildLayer(graphicsLayer);
723 }
724
725 void WebChromeClient::attachViewOverlayGraphicsLayer(Frame*, GraphicsLayer*)
726 {
727     // FIXME: If we want view-relative page overlays in Legacy WebKit on Windows, this would be the place to hook them up.
728 }
729
730 void WebChromeClient::scheduleCompositingLayerFlush()
731 {
732     m_webView->flushPendingGraphicsLayerChangesSoon();
733 }
734
735 #if PLATFORM(WIN) && USE(AVFOUNDATION)
736 WebCore::GraphicsDeviceAdapter* WebChromeClient::graphicsDeviceAdapter() const
737 {
738     return m_webView->graphicsDeviceAdapter();
739 }
740 #endif
741
742 COMPtr<IWebUIDelegate> WebChromeClient::uiDelegate()
743 {
744     COMPtr<IWebUIDelegate> delegate;
745     m_webView->uiDelegate(&delegate);
746     return delegate;
747 }
748
749 #if ENABLE(VIDEO)
750
751 bool WebChromeClient::supportsVideoFullscreen(HTMLMediaElementEnums::VideoFullscreenMode)
752 {
753     return true;
754 }
755
756 void WebChromeClient::enterVideoFullscreenForVideoElement(HTMLVideoElement& videoElement)
757 {
758     m_webView->enterVideoFullscreenForVideoElement(videoElement);
759 }
760
761 void WebChromeClient::exitVideoFullscreenForVideoElement(HTMLVideoElement& videoElement)
762 {
763     m_webView->exitVideoFullscreenForVideoElement(videoElement);
764 }
765
766 #endif
767
768 bool WebChromeClient::selectItemWritingDirectionIsNatural()
769 {
770     return false;
771 }
772
773 bool WebChromeClient::selectItemAlignmentFollowsMenuWritingDirection()
774 {
775     return true;
776 }
777
778 bool WebChromeClient::hasOpenedPopup() const
779 {
780     notImplemented();
781     return false;
782 }
783
784 RefPtr<PopupMenu> WebChromeClient::createPopupMenu(PopupMenuClient* client) const
785 {
786     return adoptRef(new PopupMenuWin(client));
787 }
788
789 RefPtr<SearchPopupMenu> WebChromeClient::createSearchPopupMenu(PopupMenuClient* client) const
790 {
791     return adoptRef(new SearchPopupMenuWin(client));
792 }
793
794 #if ENABLE(FULLSCREEN_API)
795 bool WebChromeClient::supportsFullScreenForElement(const Element* element, bool requestingKeyboardAccess)
796 {
797     COMPtr<IWebUIDelegate> uiDelegate;
798     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
799         COMPtr<IWebUIDelegatePrivate4> uiDelegatePrivate4(Query, uiDelegate);
800         BOOL supports = FALSE;
801         COMPtr<IDOMElement> domElement(AdoptCOM, DOMElement::createInstance(const_cast<Element*>(element)));
802
803         if (uiDelegatePrivate4 && SUCCEEDED(uiDelegatePrivate4->supportsFullScreenForElement(domElement.get(), requestingKeyboardAccess, &supports)))
804             return supports;
805     }
806
807     return m_webView->supportsFullScreenForElement(element, requestingKeyboardAccess);
808 }
809
810 void WebChromeClient::enterFullScreenForElement(Element* element)
811 {
812     COMPtr<IWebUIDelegate> uiDelegate;
813     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
814         COMPtr<IWebUIDelegatePrivate4> uiDelegatePrivate4(Query, uiDelegate);
815         COMPtr<IDOMElement> domElement(AdoptCOM, DOMElement::createInstance(element));
816         if (uiDelegatePrivate4 && SUCCEEDED(uiDelegatePrivate4->enterFullScreenForElement(domElement.get())))
817             return;
818     } 
819
820     m_webView->setFullScreenElement(element);
821     m_webView->fullScreenController()->enterFullScreen();
822 }
823
824 void WebChromeClient::exitFullScreenForElement(Element* element)
825 {
826     COMPtr<IWebUIDelegate> uiDelegate;
827     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
828         COMPtr<IWebUIDelegatePrivate4> uiDelegatePrivate4(Query, uiDelegate);
829         COMPtr<IDOMElement> domElement(AdoptCOM, DOMElement::createInstance(element));
830         if (uiDelegatePrivate4 && SUCCEEDED(uiDelegatePrivate4->exitFullScreenForElement(domElement.get())))
831             return;
832     }
833
834     ASSERT(element == m_webView->fullScreenElement());
835     m_webView->fullScreenController()->exitFullScreen();
836 }
837 #endif
838
839 void WebChromeClient::AXStartFrameLoad()
840 {
841     COMPtr<IAccessibilityDelegate> delegate;
842     m_webView->accessibilityDelegate(&delegate);
843     if (delegate)
844         delegate->fireFrameLoadStartedEvents();
845 }
846
847 void WebChromeClient::AXFinishFrameLoad()
848 {
849     COMPtr<IAccessibilityDelegate> delegate;
850     m_webView->accessibilityDelegate(&delegate);
851     if (delegate)
852         delegate->fireFrameLoadFinishedEvents();
853 }
854
855 bool WebChromeClient::shouldUseTiledBackingForFrameView(const FrameView* frameView) const
856 {
857 #if !USE(CAIRO)
858     return frameView && frameView->frame().isMainFrame();
859 #else
860     return false;
861 #endif
862 }