8331ca9404e5915e736ce10abdffb98ab2fb4b6c
[WebKit-https.git] / Source / WebKitLegacy / 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)
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 IntPoint WebChromeClient::accessibilityScreenToRootView(const WebCore::IntPoint& point) const
475 {
476     return screenToRootView(point);
477 }
478
479 IntRect WebChromeClient::rootViewToAccessibilityScreen(const WebCore::IntRect& rect) const
480 {
481     return rootViewToScreen(rect);
482 }
483
484 IntRect WebChromeClient::rootViewToScreen(const IntRect& rect) const
485 {
486     HWND viewWindow;
487     if (FAILED(m_webView->viewWindow(&viewWindow)))
488         return rect;
489
490     // Find the top left corner of the Widget's containing window in screen coords,
491     // and adjust the result rect's position by this amount.
492     POINT topLeft = {0, 0};
493     IntRect result = rect;
494     ::ClientToScreen(viewWindow, &topLeft);
495     result.move(topLeft.x, topLeft.y);
496
497     return result;
498 }
499
500 IntPoint WebChromeClient::screenToRootView(const IntPoint& point) const
501 {
502     POINT result = point;
503
504     HWND viewWindow;
505     if (FAILED(m_webView->viewWindow(&viewWindow)))
506         return point;
507
508     ::ScreenToClient(viewWindow, &result);
509
510     return result;
511 }
512
513 PlatformPageClient WebChromeClient::platformPageClient() const
514 {
515     HWND viewWindow;
516     if (FAILED(m_webView->viewWindow(&viewWindow)))
517         return 0;
518     return viewWindow;
519 }
520
521 void WebChromeClient::contentsSizeChanged(Frame&, const IntSize&) const
522 {
523     notImplemented();
524 }
525
526 void WebChromeClient::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags)
527 {
528     COMPtr<IWebUIDelegate> uiDelegate;
529     if (FAILED(m_webView->uiDelegate(&uiDelegate)))
530         return;
531
532     COMPtr<WebElementPropertyBag> element;
533     element.adoptRef(WebElementPropertyBag::createInstance(result));
534
535     uiDelegate->mouseDidMoveOverElement(m_webView, element.get(), modifierFlags);
536 }
537
538 bool WebChromeClient::shouldUnavailablePluginMessageBeButton(RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason) const
539 {
540     if (pluginUnavailabilityReason != RenderEmbeddedObject::PluginMissing)
541         return false;
542
543     COMPtr<IWebUIDelegate> uiDelegate;
544     if (FAILED(m_webView->uiDelegate(&uiDelegate)))
545         return false;
546     
547     // If the UI delegate implements IWebUIDelegatePrivate3, 
548     // which contains didPressMissingPluginButton, then the message should be a button.
549     COMPtr<IWebUIDelegatePrivate3> uiDelegatePrivate3(Query, uiDelegate);
550     return uiDelegatePrivate3;
551 }
552
553 void WebChromeClient::unavailablePluginButtonClicked(Element& element, RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason) const
554 {
555     ASSERT_UNUSED(pluginUnavailabilityReason, pluginUnavailabilityReason == RenderEmbeddedObject::PluginMissing);
556
557     COMPtr<IWebUIDelegate> uiDelegate;
558     if (FAILED(m_webView->uiDelegate(&uiDelegate)))
559         return;
560
561     COMPtr<IWebUIDelegatePrivate3> uiDelegatePrivate3(Query, uiDelegate);
562     if (!uiDelegatePrivate3)
563         return;
564
565     COMPtr<IDOMElement> e(AdoptCOM, DOMElement::createInstance(&element));
566     uiDelegatePrivate3->didPressMissingPluginButton(e.get());
567 }
568
569 void WebChromeClient::setToolTip(const String& toolTip, TextDirection)
570 {
571     m_webView->setToolTip(toolTip);
572 }
573
574 void WebChromeClient::print(Frame& frame)
575 {
576     COMPtr<IWebUIDelegate> uiDelegate;
577     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate)))
578         uiDelegate->printFrame(m_webView, kit(&frame));
579 }
580
581 void WebChromeClient::exceededDatabaseQuota(Frame& frame, const String& databaseIdentifier, DatabaseDetails)
582 {
583     COMPtr<WebSecurityOrigin> origin(AdoptCOM, WebSecurityOrigin::createInstance(&frame.document()->securityOrigin()));
584     COMPtr<IWebUIDelegate> uiDelegate;
585     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
586         COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate(Query, uiDelegate);
587         if (uiDelegatePrivate)
588             uiDelegatePrivate->exceededDatabaseQuota(m_webView, kit(&frame), origin.get(), BString(databaseIdentifier));
589         else {
590             // FIXME: remove this workaround once shipping Safari has the necessary delegate implemented.
591             WCHAR path[MAX_PATH];
592             HMODULE safariHandle = GetModuleHandleW(L"Safari.exe");
593             if (!safariHandle)
594                 return;
595             if (!::GetModuleFileName(safariHandle, path, WTF_ARRAY_LENGTH(path)))
596                 return;
597             DWORD handle = 0;
598             DWORD versionSize = GetFileVersionInfoSize(path, &handle);
599             if (!versionSize)
600                 return;
601             Vector<char> data(versionSize);
602             if (!GetFileVersionInfo(path, 0, versionSize, data.data()))
603                 return;
604
605             LPCTSTR productVersion;
606             UINT productVersionLength;
607             if (!VerQueryValueW(data.data(), L"\\StringFileInfo\\040904b0\\ProductVersion", (void**)&productVersion, &productVersionLength))
608                 return;
609             if (wcsncmp(L"3.1", productVersion, productVersionLength) > 0) {
610                 const unsigned long long defaultQuota = 5 * 1024 * 1024; // 5 megabytes should hopefully be enough to test storage support.
611                 origin->setQuota(defaultQuota);
612             }
613         }
614     }
615 }
616
617 // FIXME: Move this include to the top of the file with the other includes.
618 #include <WebCore/ApplicationCacheStorage.h>
619
620 void WebChromeClient::reachedMaxAppCacheSize(int64_t spaceNeeded)
621 {
622     // FIXME: Free some space.
623     notImplemented();
624 }
625
626 void WebChromeClient::reachedApplicationCacheOriginQuota(SecurityOrigin&, int64_t)
627 {
628     notImplemented();
629 }
630
631 void WebChromeClient::runOpenPanel(Frame&, FileChooser& fileChooser)
632 {
633     HWND viewWindow;
634     if (FAILED(m_webView->viewWindow(&viewWindow)))
635         return;
636
637     bool multiFile = fileChooser.settings().allowsMultipleFiles;
638     Vector<WCHAR> fileBuf(multiFile ? maxFilePathsListSize : MAX_PATH);
639
640     OPENFILENAME ofn;
641
642     memset(&ofn, 0, sizeof(ofn));
643
644     // Need to zero out the first char of fileBuf so GetOpenFileName doesn't think it's an initialization string
645     fileBuf[0] = '\0';
646
647     ofn.lStructSize = sizeof(ofn);
648     ofn.hwndOwner = viewWindow;
649     String allFiles = allFilesText();
650     allFiles.append(L"\0*.*\0\0", 6);
651
652     Vector<UChar> filterCharacters = allFiles.charactersWithNullTermination(); // Retain buffer long enough to make the GetOpenFileName call
653     ofn.lpstrFilter = filterCharacters.data();
654
655     ofn.lpstrFile = fileBuf.data();
656     ofn.nMaxFile = fileBuf.size();
657     String dialogTitle = uploadFileText();
658     Vector<UChar> dialogTitleCharacters = dialogTitle.charactersWithNullTermination(); // Retain buffer long enough to make the GetOpenFileName call
659     ofn.lpstrTitle = dialogTitleCharacters.data();
660     ofn.Flags = OFN_ENABLESIZING | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_EXPLORER;
661     if (multiFile)
662         ofn.Flags = ofn.Flags | OFN_ALLOWMULTISELECT;
663
664     if (GetOpenFileName(&ofn)) {
665         WCHAR* files = fileBuf.data();
666         Vector<String> fileList;
667         String file(files);
668         if (multiFile) {
669             while (!file.isEmpty()) {
670                 // When using the OFN_EXPLORER flag, the file list is null delimited.
671                 // When you create a String from a ptr to this list, it will use strlen to look for the null character.
672                 // Then we find the next file path string by using the length of the string we just created.
673                 WCHAR* nextFilePtr = files + file.length() + 1;
674                 String nextFile(nextFilePtr);
675                 // If multiple files are selected, there will be a directory name first, which we don't want to add to the vector.
676                 // We know a single file was selected if there is only one filename in the list.  
677                 // In that case, we don't want to skip adding the first (and only) name.
678                 if (files != fileBuf.data() || nextFile.isEmpty())
679                     fileList.append(file);
680                 files = nextFilePtr;
681                 file = nextFile;
682             }
683         } else
684             fileList.append(file);
685         ASSERT(fileList.size());
686         fileChooser.chooseFiles(fileList);
687     }
688     // FIXME: Show some sort of error if too many files are selected and the buffer is too small.  For now, this will fail silently.
689 }
690
691 void WebChromeClient::loadIconForFiles(const Vector<WTF::String>& filenames, WebCore::FileIconLoader& loader)
692 {
693     loader.iconLoaded(Icon::createIconForFiles(filenames));
694 }
695
696 RefPtr<Icon> WebChromeClient::createIconForFiles(const Vector<String>& filenames)
697 {
698     return Icon::createIconForFiles(filenames);
699 }
700
701 void WebChromeClient::setCursor(const Cursor& cursor)
702 {
703     if (!cursor.platformCursor())
704         return;
705
706     HCURSOR platformCursor = cursor.platformCursor()->nativeCursor();
707     if (!platformCursor)
708         return;
709
710     bool shouldSetCursor = true;
711     if (COMPtr<IWebUIDelegate> delegate = uiDelegate()) {
712         COMPtr<IWebUIDelegatePrivate> delegatePrivate(Query, delegate);
713         if (delegatePrivate) {
714             if (SUCCEEDED(delegatePrivate->webViewSetCursor(m_webView, platformCursor)))
715                 shouldSetCursor = false;
716         }
717     }
718
719     if (shouldSetCursor)
720         ::SetCursor(platformCursor);
721
722     setLastSetCursorToCurrentCursor();
723 }
724
725 void WebChromeClient::setCursorHiddenUntilMouseMoves(bool)
726 {
727     notImplemented();
728 }
729
730 void WebChromeClient::setLastSetCursorToCurrentCursor()
731 {
732     m_webView->setLastCursor(::GetCursor());
733 }
734
735 void WebChromeClient::attachRootGraphicsLayer(Frame&, GraphicsLayer* graphicsLayer)
736 {
737     m_webView->setRootChildLayer(graphicsLayer);
738 }
739
740 void WebChromeClient::attachViewOverlayGraphicsLayer(GraphicsLayer*)
741 {
742     // FIXME: If we want view-relative page overlays in Legacy WebKit on Windows, this would be the place to hook them up.
743 }
744
745 void WebChromeClient::scheduleCompositingLayerFlush()
746 {
747     m_webView->flushPendingGraphicsLayerChangesSoon();
748 }
749
750 #if PLATFORM(WIN) && USE(AVFOUNDATION)
751 WebCore::GraphicsDeviceAdapter* WebChromeClient::graphicsDeviceAdapter() const
752 {
753     return m_webView->graphicsDeviceAdapter();
754 }
755 #endif
756
757 COMPtr<IWebUIDelegate> WebChromeClient::uiDelegate()
758 {
759     COMPtr<IWebUIDelegate> delegate;
760     m_webView->uiDelegate(&delegate);
761     return delegate;
762 }
763
764 #if ENABLE(VIDEO)
765
766 bool WebChromeClient::supportsVideoFullscreen(HTMLMediaElementEnums::VideoFullscreenMode)
767 {
768     return true;
769 }
770
771 void WebChromeClient::enterVideoFullscreenForVideoElement(HTMLVideoElement& videoElement, HTMLMediaElementEnums::VideoFullscreenMode, bool)
772 {
773     m_webView->enterVideoFullscreenForVideoElement(videoElement);
774 }
775
776 void WebChromeClient::exitVideoFullscreenForVideoElement(HTMLVideoElement& videoElement)
777 {
778     m_webView->exitVideoFullscreenForVideoElement(videoElement);
779 }
780
781 #endif
782
783 bool WebChromeClient::selectItemWritingDirectionIsNatural()
784 {
785     return false;
786 }
787
788 bool WebChromeClient::selectItemAlignmentFollowsMenuWritingDirection()
789 {
790     return true;
791 }
792
793 RefPtr<PopupMenu> WebChromeClient::createPopupMenu(PopupMenuClient& client) const
794 {
795     return adoptRef(new PopupMenuWin(&client));
796 }
797
798 RefPtr<SearchPopupMenu> WebChromeClient::createSearchPopupMenu(PopupMenuClient& client) const
799 {
800     return adoptRef(new SearchPopupMenuWin(&client));
801 }
802
803 #if ENABLE(FULLSCREEN_API)
804
805 bool WebChromeClient::supportsFullScreenForElement(const Element& element, bool requestingKeyboardAccess)
806 {
807     COMPtr<IWebUIDelegate> uiDelegate;
808     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
809         COMPtr<IWebUIDelegatePrivate4> uiDelegatePrivate4(Query, uiDelegate);
810         BOOL supports = FALSE;
811         COMPtr<IDOMElement> domElement(AdoptCOM, DOMElement::createInstance(const_cast<Element*>(&element)));
812
813         if (uiDelegatePrivate4 && SUCCEEDED(uiDelegatePrivate4->supportsFullScreenForElement(domElement.get(), requestingKeyboardAccess, &supports)))
814             return supports;
815     }
816
817     return m_webView->supportsFullScreenForElement(&element, requestingKeyboardAccess);
818 }
819
820 void WebChromeClient::enterFullScreenForElement(Element& element)
821 {
822     COMPtr<IWebUIDelegate> uiDelegate;
823     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
824         COMPtr<IWebUIDelegatePrivate4> uiDelegatePrivate4(Query, uiDelegate);
825         COMPtr<IDOMElement> domElement(AdoptCOM, DOMElement::createInstance(&element));
826         if (uiDelegatePrivate4 && SUCCEEDED(uiDelegatePrivate4->enterFullScreenForElement(domElement.get())))
827             return;
828     } 
829
830     m_webView->setFullScreenElement(&element);
831     m_webView->fullScreenController()->enterFullScreen();
832 }
833
834 void WebChromeClient::exitFullScreenForElement(Element* element)
835 {
836     COMPtr<IWebUIDelegate> uiDelegate;
837     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
838         COMPtr<IWebUIDelegatePrivate4> uiDelegatePrivate4(Query, uiDelegate);
839         COMPtr<IDOMElement> domElement(AdoptCOM, DOMElement::createInstance(element));
840         if (uiDelegatePrivate4 && SUCCEEDED(uiDelegatePrivate4->exitFullScreenForElement(domElement.get())))
841             return;
842     }
843
844     ASSERT(element == m_webView->fullScreenElement());
845     m_webView->fullScreenController()->exitFullScreen();
846 }
847
848 #endif
849
850 void WebChromeClient::AXStartFrameLoad()
851 {
852     COMPtr<IAccessibilityDelegate> delegate;
853     m_webView->accessibilityDelegate(&delegate);
854     if (delegate)
855         delegate->fireFrameLoadStartedEvents();
856 }
857
858 void WebChromeClient::AXFinishFrameLoad()
859 {
860     COMPtr<IAccessibilityDelegate> delegate;
861     m_webView->accessibilityDelegate(&delegate);
862     if (delegate)
863         delegate->fireFrameLoadFinishedEvents();
864 }
865
866 bool WebChromeClient::shouldUseTiledBackingForFrameView(const FrameView& frameView) const
867 {
868 #if !USE(CAIRO)
869     return frameView.frame().isMainFrame();
870 #else
871     return false;
872 #endif
873 }