1 /*
2 * Copyright (C) 2006, 2007, 2008 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 COMPUTER, 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 COMPUTER, 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 "config.h"
28 #include "WebChromeClient.h"
29
30 #include "COMPropertyBag.h"
31 #include "COMVariantSetter.h"
32 #include "DOMCoreClasses.h"
33 #include "WebElementPropertyBag.h"
34 #include "WebFrame.h"
35 #include "WebHistory.h"
36 #include "WebMutableURLRequest.h"
37 #include "WebDesktopNotificationsDelegate.h"
38 #include "WebSecurityOrigin.h"
39 #include "WebView.h"
40 #include <WebCore/BString.h>
41 #include <WebCore/Console.h>
42 #include <WebCore/ContextMenu.h>
43 #include <WebCore/Cursor.h>
44 #include <WebCore/FileChooser.h>
45 #include <WebCore/FloatRect.h>
46 #include <WebCore/FrameLoadRequest.h>
47 #include <WebCore/FrameView.h>
48 #include <WebCore/HTMLNames.h>
49 #include <WebCore/Icon.h>
50 #include <WebCore/LocalWindowsContext.h>
51 #include <WebCore/LocalizedStrings.h>
52 #include <WebCore/NavigationAction.h>
53 #include <WebCore/NotImplemented.h>
54 #include <WebCore/Page.h>
55 #include <WebCore/SecurityOrigin.h>
56 #include <WebCore/PopupMenuWin.h>
57 #include <WebCore/SearchPopupMenuWin.h>
58 #include <WebCore/WindowFeatures.h>
59 #include <wchar.h>
60
61 #if USE(ACCELERATED_COMPOSITING)
62 #include <WebCore/GraphicsLayer.h>
63 #endif
64
65 using namespace WebCore;
66
67 // When you call GetOpenFileName, if the size of the buffer is too small,
68 // MSDN says that the first two bytes of the buffer contain the required size for the file selection, in bytes or characters
69 // So we can assume the required size can't be more than the maximum value for a short.
70 static const size_t maxFilePathsListSize = USHRT_MAX;
71
WebChromeClient(WebView * webView)72 WebChromeClient::WebChromeClient(WebView* webView)
73 : m_webView(webView)
74 #if ENABLE(NOTIFICATIONS)
75 , m_notificationsDelegate(new WebDesktopNotificationsDelegate(webView))
76 #endif
77 {
78 }
79
chromeDestroyed()80 void WebChromeClient::chromeDestroyed()
81 {
82 delete this;
83 }
84
setWindowRect(const FloatRect & r)85 void WebChromeClient::setWindowRect(const FloatRect& r)
86 {
87 IWebUIDelegate* uiDelegate = 0;
88 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
89 RECT rect = IntRect(r);
90 uiDelegate->setFrame(m_webView, &rect);
91 uiDelegate->Release();
92 }
93 }
94
windowRect()95 FloatRect WebChromeClient::windowRect()
96 {
97 IWebUIDelegate* uiDelegate = 0;
98 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
99 RECT rect;
100 HRESULT retval = uiDelegate->webViewFrame(m_webView, &rect);
101
102 uiDelegate->Release();
103
104 if (SUCCEEDED(retval))
105 return rect;
106 }
107
108 return FloatRect();
109 }
110
pageRect()111 FloatRect WebChromeClient::pageRect()
112 {
113 RECT rect;
114 m_webView->frameRect(&rect);
115 return rect;
116 }
117
scaleFactor()118 float WebChromeClient::scaleFactor()
119 {
120 // Windows doesn't support UI scaling.
121 return 1.0;
122 }
123
focus()124 void WebChromeClient::focus()
125 {
126 IWebUIDelegate* uiDelegate = 0;
127 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
128 uiDelegate->webViewFocus(m_webView);
129 uiDelegate->Release();
130 }
131 // Normally this would happen on a timer, but JS might need to know this earlier, so we'll update here.
132 m_webView->updateActiveState();
133 }
134
unfocus()135 void WebChromeClient::unfocus()
136 {
137 IWebUIDelegate* uiDelegate = 0;
138 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
139 uiDelegate->webViewUnfocus(m_webView);
140 uiDelegate->Release();
141 }
142 // Normally this would happen on a timer, but JS might need to know this earlier, so we'll update here.
143 m_webView->updateActiveState();
144 }
145
canTakeFocus(FocusDirection direction)146 bool WebChromeClient::canTakeFocus(FocusDirection direction)
147 {
148 IWebUIDelegate* uiDelegate = 0;
149 BOOL bForward = (direction == FocusDirectionForward) ? TRUE : FALSE;
150 BOOL result = FALSE;
151 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
152 uiDelegate->canTakeFocus(m_webView, bForward, &result);
153 uiDelegate->Release();
154 }
155
156 return !!result;
157 }
158
takeFocus(FocusDirection direction)159 void WebChromeClient::takeFocus(FocusDirection direction)
160 {
161 IWebUIDelegate* uiDelegate = 0;
162 BOOL bForward = (direction == FocusDirectionForward) ? TRUE : FALSE;
163 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
164 uiDelegate->takeFocus(m_webView, bForward);
165 uiDelegate->Release();
166 }
167 }
168
focusedNodeChanged(Node *)169 void WebChromeClient::focusedNodeChanged(Node*)
170 {
171 }
172
focusedFrameChanged(Frame *)173 void WebChromeClient::focusedFrameChanged(Frame*)
174 {
175 }
176
createWindowFeaturesPropertyBag(const WindowFeatures & features)177 static COMPtr<IPropertyBag> createWindowFeaturesPropertyBag(const WindowFeatures& features)
178 {
179 HashMap<String, COMVariant> map;
180 if (features.xSet)
181 map.set(WebWindowFeaturesXKey, features.x);
182 if (features.ySet)
183 map.set(WebWindowFeaturesYKey, features.y);
184 if (features.widthSet)
185 map.set(WebWindowFeaturesWidthKey, features.width);
186 if (features.heightSet)
187 map.set(WebWindowFeaturesHeightKey, features.height);
188 map.set(WebWindowFeaturesMenuBarVisibleKey, features.menuBarVisible);
189 map.set(WebWindowFeaturesStatusBarVisibleKey, features.statusBarVisible);
190 map.set(WebWindowFeaturesToolBarVisibleKey, features.toolBarVisible);
191 map.set(WebWindowFeaturesScrollbarsVisibleKey, features.scrollbarsVisible);
192 map.set(WebWindowFeaturesResizableKey, features.resizable);
193 map.set(WebWindowFeaturesFullscreenKey, features.fullscreen);
194 map.set(WebWindowFeaturesDialogKey, features.dialog);
195
196 return COMPtr<IPropertyBag>(AdoptCOM, COMPropertyBag<COMVariant>::adopt(map));
197 }
198
createWindow(Frame *,const FrameLoadRequest &,const WindowFeatures & features,const NavigationAction &)199 Page* WebChromeClient::createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures& features, const NavigationAction&)
200 {
201 COMPtr<IWebUIDelegate> delegate = uiDelegate();
202 if (!delegate)
203 return 0;
204
205 // Just create a blank request because createWindow() is only required to create window but not to load URL.
206 COMPtr<IWebMutableURLRequest> request(AdoptCOM, WebMutableURLRequest::createInstance());
207
208 COMPtr<IWebUIDelegatePrivate2> delegatePrivate(Query, delegate);
209 if (delegatePrivate) {
210 COMPtr<IWebView> newWebView;
211 HRESULT hr = delegatePrivate->createWebViewWithRequest(m_webView, request.get(), createWindowFeaturesPropertyBag(features).get(), &newWebView);
212
213 if (SUCCEEDED(hr) && newWebView)
214 return core(newWebView.get());
215
216 // If the delegate doesn't implement the IWebUIDelegatePrivate2 version of the call, fall back
217 // to the old versions (even if they support the IWebUIDelegatePrivate2 interface).
218 if (hr != E_NOTIMPL)
219 return 0;
220 }
221
222 COMPtr<IWebView> newWebView;
223
224 if (features.dialog) {
225 if (FAILED(delegate->createModalDialog(m_webView, request.get(), &newWebView)))
226 return 0;
227 } else if (FAILED(delegate->createWebViewWithRequest(m_webView, request.get(), &newWebView)))
228 return 0;
229
230 return newWebView ? core(newWebView.get()) : 0;
231 }
232
show()233 void WebChromeClient::show()
234 {
235 IWebUIDelegate* uiDelegate = 0;
236 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
237 uiDelegate->webViewShow(m_webView);
238 uiDelegate->Release();
239 }
240 }
241
canRunModal()242 bool WebChromeClient::canRunModal()
243 {
244 BOOL result = FALSE;
245 if (COMPtr<IWebUIDelegate> delegate = uiDelegate())
246 delegate->canRunModal(m_webView, &result);
247 return result;
248 }
249
runModal()250 void WebChromeClient::runModal()
251 {
252 if (COMPtr<IWebUIDelegate> delegate = uiDelegate())
253 delegate->runModal(m_webView);
254 }
255
setToolbarsVisible(bool visible)256 void WebChromeClient::setToolbarsVisible(bool visible)
257 {
258 IWebUIDelegate* uiDelegate = 0;
259 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
260 uiDelegate->setToolbarsVisible(m_webView, visible);
261 uiDelegate->Release();
262 }
263 }
264
toolbarsVisible()265 bool WebChromeClient::toolbarsVisible()
266 {
267 BOOL result = false;
268 IWebUIDelegate* uiDelegate = 0;
269 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
270 uiDelegate->webViewAreToolbarsVisible(m_webView, &result);
271 uiDelegate->Release();
272 }
273 return result != false;
274 }
275
setStatusbarVisible(bool visible)276 void WebChromeClient::setStatusbarVisible(bool visible)
277 {
278 IWebUIDelegate* uiDelegate = 0;
279 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
280 uiDelegate->setStatusBarVisible(m_webView, visible);
281 uiDelegate->Release();
282 }
283 }
284
statusbarVisible()285 bool WebChromeClient::statusbarVisible()
286 {
287 BOOL result = false;
288 IWebUIDelegate* uiDelegate = 0;
289 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
290 uiDelegate->webViewIsStatusBarVisible(m_webView, &result);
291 uiDelegate->Release();
292 }
293 return result != false;
294 }
295
setScrollbarsVisible(bool b)296 void WebChromeClient::setScrollbarsVisible(bool b)
297 {
298 WebFrame* webFrame = m_webView->topLevelFrame();
299 if (webFrame)
300 webFrame->setAllowsScrolling(b);
301 }
302
scrollbarsVisible()303 bool WebChromeClient::scrollbarsVisible()
304 {
305 WebFrame* webFrame = m_webView->topLevelFrame();
306 BOOL b = false;
307 if (webFrame)
308 webFrame->allowsScrolling(&b);
309
310 return !!b;
311 }
312
setMenubarVisible(bool visible)313 void WebChromeClient::setMenubarVisible(bool visible)
314 {
315 COMPtr<IWebUIDelegate> delegate = uiDelegate();
316 if (!delegate)
317 return;
318 delegate->setMenuBarVisible(m_webView, visible);
319 }
320
menubarVisible()321 bool WebChromeClient::menubarVisible()
322 {
323 COMPtr<IWebUIDelegate> delegate = uiDelegate();
324 if (!delegate)
325 return true;
326 BOOL result = true;
327 delegate->isMenuBarVisible(m_webView, &result);
328 return result;
329 }
330
setResizable(bool resizable)331 void WebChromeClient::setResizable(bool resizable)
332 {
333 IWebUIDelegate* uiDelegate = 0;
334 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
335 uiDelegate->setResizable(m_webView, resizable);
336 uiDelegate->Release();
337 }
338 }
339
addMessageToConsole(MessageSource source,MessageType type,MessageLevel level,const String & message,unsigned line,const String & url)340 void WebChromeClient::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned line, const String& url)
341 {
342 COMPtr<IWebUIDelegate> uiDelegate;
343 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
344 COMPtr<IWebUIDelegatePrivate> uiPrivate;
345 if (SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&uiPrivate)))
346 uiPrivate->webViewAddMessageToConsole(m_webView, BString(message), line, BString(url), true);
347 }
348 }
349
canRunBeforeUnloadConfirmPanel()350 bool WebChromeClient::canRunBeforeUnloadConfirmPanel()
351 {
352 IWebUIDelegate* ui;
353 if (SUCCEEDED(m_webView->uiDelegate(&ui)) && ui) {
354 ui->Release();
355 return true;
356 }
357 return false;
358 }
359
runBeforeUnloadConfirmPanel(const String & message,Frame * frame)360 bool WebChromeClient::runBeforeUnloadConfirmPanel(const String& message, Frame* frame)
361 {
362 BOOL result = TRUE;
363 IWebUIDelegate* ui;
364 if (SUCCEEDED(m_webView->uiDelegate(&ui)) && ui) {
365 WebFrame* webFrame = kit(frame);
366 ui->runBeforeUnloadConfirmPanelWithMessage(m_webView, BString(message), webFrame, &result);
367 ui->Release();
368 }
369 return !!result;
370 }
371
closeWindowSoon()372 void WebChromeClient::closeWindowSoon()
373 {
374 // We need to remove the parent WebView from WebViewSets here, before it actually
375 // closes, to make sure that JavaScript code that executes before it closes
376 // can't find it. Otherwise, window.open will select a closed WebView instead of
377 // opening a new one <rdar://problem/3572585>.
378
379 // We also need to stop the load to prevent further parsing or JavaScript execution
380 // after the window has torn down <rdar://problem/4161660>.
381
382 // FIXME: This code assumes that the UI delegate will respond to a webViewClose
383 // message by actually closing the WebView. Safari guarantees this behavior, but other apps might not.
384 // This approach is an inherent limitation of not making a close execute immediately
385 // after a call to window.close.
386
387 m_webView->setGroupName(0);
388 m_webView->stopLoading(0);
389 m_webView->closeWindowSoon();
390 }
391
runJavaScriptAlert(Frame *,const String & message)392 void WebChromeClient::runJavaScriptAlert(Frame*, const String& message)
393 {
394 COMPtr<IWebUIDelegate> ui;
395 if (SUCCEEDED(m_webView->uiDelegate(&ui)))
396 ui->runJavaScriptAlertPanelWithMessage(m_webView, BString(message));
397 }
398
runJavaScriptConfirm(Frame *,const String & message)399 bool WebChromeClient::runJavaScriptConfirm(Frame*, const String& message)
400 {
401 BOOL result = FALSE;
402 COMPtr<IWebUIDelegate> ui;
403 if (SUCCEEDED(m_webView->uiDelegate(&ui)))
404 ui->runJavaScriptConfirmPanelWithMessage(m_webView, BString(message), &result);
405 return !!result;
406 }
407
runJavaScriptPrompt(Frame *,const String & message,const String & defaultValue,String & result)408 bool WebChromeClient::runJavaScriptPrompt(Frame*, const String& message, const String& defaultValue, String& result)
409 {
410 COMPtr<IWebUIDelegate> ui;
411 if (FAILED(m_webView->uiDelegate(&ui)))
412 return false;
413
414 TimerBase::fireTimersInNestedEventLoop();
415
416 BSTR resultBSTR = 0;
417 if (FAILED(ui->runJavaScriptTextInputPanelWithPrompt(m_webView, BString(message), BString(defaultValue), &resultBSTR)))
418 return false;
419
420 if (resultBSTR) {
421 result = String(resultBSTR, SysStringLen(resultBSTR));
422 SysFreeString(resultBSTR);
423 return true;
424 }
425
426 return false;
427 }
428
setStatusbarText(const String & statusText)429 void WebChromeClient::setStatusbarText(const String& statusText)
430 {
431 COMPtr<IWebUIDelegate> uiDelegate;
432 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
433 uiDelegate->setStatusText(m_webView, BString(statusText));
434 }
435 }
436
shouldInterruptJavaScript()437 bool WebChromeClient::shouldInterruptJavaScript()
438 {
439 COMPtr<IWebUIDelegate> uiDelegate;
440 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
441 COMPtr<IWebUIDelegatePrivate> uiPrivate;
442 if (SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&uiPrivate))) {
443 BOOL result;
444 if (SUCCEEDED(uiPrivate->webViewShouldInterruptJavaScript(m_webView, &result)))
445 return !!result;
446 }
447 }
448 return false;
449 }
450
keyboardUIMode()451 KeyboardUIMode WebChromeClient::keyboardUIMode()
452 {
453 BOOL enabled = FALSE;
454 IWebPreferences* preferences;
455 if (SUCCEEDED(m_webView->preferences(&preferences)))
456 preferences->tabsToLinks(&enabled);
457
458 return enabled ? KeyboardAccessTabsToLinks : KeyboardAccessDefault;
459 }
460
windowResizerRect() const461 IntRect WebChromeClient::windowResizerRect() const
462 {
463 return IntRect();
464 }
465
invalidateWindow(const IntRect & windowRect,bool immediate)466 void WebChromeClient::invalidateWindow(const IntRect& windowRect, bool immediate)
467 {
468 ASSERT(core(m_webView->topLevelFrame()));
469 m_webView->repaint(windowRect, false /*contentChanged*/, immediate, false /*repaintContentOnly*/);
470 }
471
invalidateContentsAndWindow(const IntRect & windowRect,bool immediate)472 void WebChromeClient::invalidateContentsAndWindow(const IntRect& windowRect, bool immediate)
473 {
474 ASSERT(core(m_webView->topLevelFrame()));
475 m_webView->repaint(windowRect, true /*contentChanged*/, immediate /*immediate*/, false /*repaintContentOnly*/);
476 }
477
invalidateContentsForSlowScroll(const IntRect & windowRect,bool immediate)478 void WebChromeClient::invalidateContentsForSlowScroll(const IntRect& windowRect, bool immediate)
479 {
480 ASSERT(core(m_webView->topLevelFrame()));
481 m_webView->repaint(windowRect, true /*contentChanged*/, immediate, true /*repaintContentOnly*/);
482 }
483
scroll(const IntSize & delta,const IntRect & scrollViewRect,const IntRect & clipRect)484 void WebChromeClient::scroll(const IntSize& delta, const IntRect& scrollViewRect, const IntRect& clipRect)
485 {
486 ASSERT(core(m_webView->topLevelFrame()));
487
488 m_webView->scrollBackingStore(core(m_webView->topLevelFrame())->view(), delta.width(), delta.height(), scrollViewRect, clipRect);
489 }
490
windowToScreen(const IntRect & rect) const491 IntRect WebChromeClient::windowToScreen(const IntRect& rect) const
492 {
493 HWND viewWindow;
494 if (FAILED(m_webView->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow))))
495 return rect;
496
497 // Find the top left corner of the Widget's containing window in screen coords,
498 // and adjust the result rect's position by this amount.
499 POINT topLeft = {0, 0};
500 IntRect result = rect;
501 ::ClientToScreen(viewWindow, &topLeft);
502 result.move(topLeft.x, topLeft.y);
503
504 return result;
505 }
506
screenToWindow(const IntPoint & point) const507 IntPoint WebChromeClient::screenToWindow(const IntPoint& point) const
508 {
509 POINT result = point;
510
511 HWND viewWindow;
512 if (FAILED(m_webView->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow))))
513 return point;
514
515 ::ScreenToClient(viewWindow, &result);
516
517 return result;
518 }
519
platformPageClient() const520 PlatformPageClient WebChromeClient::platformPageClient() const
521 {
522 HWND viewWindow;
523 if (FAILED(m_webView->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow))))
524 return 0;
525 return viewWindow;
526 }
527
contentsSizeChanged(Frame *,const IntSize &) const528 void WebChromeClient::contentsSizeChanged(Frame*, const IntSize&) const
529 {
530 notImplemented();
531 }
532
mouseDidMoveOverElement(const HitTestResult & result,unsigned modifierFlags)533 void WebChromeClient::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags)
534 {
535 COMPtr<IWebUIDelegate> uiDelegate;
536 if (FAILED(m_webView->uiDelegate(&uiDelegate)))
537 return;
538
539 COMPtr<WebElementPropertyBag> element;
540 element.adoptRef(WebElementPropertyBag::createInstance(result));
541
542 uiDelegate->mouseDidMoveOverElement(m_webView, element.get(), modifierFlags);
543 }
544
shouldMissingPluginMessageBeButton() const545 bool WebChromeClient::shouldMissingPluginMessageBeButton() const
546 {
547 COMPtr<IWebUIDelegate> uiDelegate;
548 if (FAILED(m_webView->uiDelegate(&uiDelegate)))
549 return false;
550
551 // If the UI delegate implements IWebUIDelegatePrivate3,
552 // which contains didPressMissingPluginButton, then the message should be a button.
553 COMPtr<IWebUIDelegatePrivate3> uiDelegatePrivate3(Query, uiDelegate);
554 return uiDelegatePrivate3;
555 }
556
missingPluginButtonClicked(Element * element) const557 void WebChromeClient::missingPluginButtonClicked(Element* element) const
558 {
559 COMPtr<IWebUIDelegate> uiDelegate;
560 if (FAILED(m_webView->uiDelegate(&uiDelegate)))
561 return;
562
563 COMPtr<IWebUIDelegatePrivate3> uiDelegatePrivate3(Query, uiDelegate);
564 if (!uiDelegatePrivate3)
565 return;
566
567 COMPtr<IDOMElement> e(AdoptCOM, DOMElement::createInstance(element));
568 uiDelegatePrivate3->didPressMissingPluginButton(e.get());
569 }
570
setToolTip(const String & toolTip,TextDirection)571 void WebChromeClient::setToolTip(const String& toolTip, TextDirection)
572 {
573 m_webView->setToolTip(toolTip);
574 }
575
print(Frame * frame)576 void WebChromeClient::print(Frame* frame)
577 {
578 COMPtr<IWebUIDelegate> uiDelegate;
579 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate)))
580 uiDelegate->printFrame(m_webView, kit(frame));
581 }
582
583 #if ENABLE(DATABASE)
exceededDatabaseQuota(Frame * frame,const String & databaseIdentifier)584 void WebChromeClient::exceededDatabaseQuota(Frame* frame, const String& databaseIdentifier)
585 {
586 COMPtr<WebSecurityOrigin> origin(AdoptCOM, WebSecurityOrigin::createInstance(frame->document()->securityOrigin()));
587 COMPtr<IWebUIDelegate> uiDelegate;
588 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
589 COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate(Query, uiDelegate);
590 if (uiDelegatePrivate)
591 uiDelegatePrivate->exceededDatabaseQuota(m_webView, kit(frame), origin.get(), BString(databaseIdentifier));
592 else {
593 // FIXME: remove this workaround once shipping Safari has the necessary delegate implemented.
594 WCHAR path[MAX_PATH];
595 HMODULE safariHandle = GetModuleHandleW(L"Safari.exe");
596 if (!safariHandle)
597 return;
598 GetModuleFileName(safariHandle, path, WTF_ARRAY_LENGTH(path));
599 DWORD handle;
600 DWORD versionSize = GetFileVersionInfoSize(path, &handle);
601 if (!versionSize)
602 return;
603 Vector<char> data(versionSize);
604 if (!GetFileVersionInfo(path, 0, versionSize, data.data()))
605 return;
606
607 LPCTSTR productVersion;
608 UINT productVersionLength;
609 if (!VerQueryValueW(data.data(), L"\\StringFileInfo\\040904b0\\ProductVersion", (void**)&productVersion, &productVersionLength))
610 return;
611 if (wcsncmp(L"3.1", productVersion, productVersionLength) > 0) {
612 const unsigned long long defaultQuota = 5 * 1024 * 1024; // 5 megabytes should hopefully be enough to test storage support.
613 origin->setQuota(defaultQuota);
614 }
615 }
616 }
617 }
618 #endif
619
620 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
621 #include "ApplicationCacheStorage.h"
reachedMaxAppCacheSize(int64_t spaceNeeded)622 void WebChromeClient::reachedMaxAppCacheSize(int64_t spaceNeeded)
623 {
624 // FIXME: Free some space.
625 notImplemented();
626 }
627
reachedApplicationCacheOriginQuota(SecurityOrigin *)628 void WebChromeClient::reachedApplicationCacheOriginQuota(SecurityOrigin*)
629 {
630 notImplemented();
631 }
632 #endif
633
populateVisitedLinks()634 void WebChromeClient::populateVisitedLinks()
635 {
636 COMPtr<IWebHistoryDelegate> historyDelegate;
637 m_webView->historyDelegate(&historyDelegate);
638 if (historyDelegate) {
639 historyDelegate->populateVisitedLinksForWebView(m_webView);
640 return;
641 }
642
643 WebHistory* history = WebHistory::sharedHistory();
644 if (!history)
645 return;
646 history->addVisitedLinksToPageGroup(m_webView->page()->group());
647 }
648
paintCustomScrollbar(GraphicsContext * context,const FloatRect & rect,ScrollbarControlSize size,ScrollbarControlState state,ScrollbarPart pressedPart,bool vertical,float value,float proportion,ScrollbarControlPartMask parts)649 bool WebChromeClient::paintCustomScrollbar(GraphicsContext* context, const FloatRect& rect, ScrollbarControlSize size,
650 ScrollbarControlState state, ScrollbarPart pressedPart, bool vertical,
651 float value, float proportion, ScrollbarControlPartMask parts)
652 {
653 if (context->paintingDisabled())
654 return false;
655
656 COMPtr<IWebUIDelegate> delegate = uiDelegate();
657 if (!delegate)
658 return false;
659
660 WebScrollbarControlPartMask webParts = WebNoScrollPart;
661 if (parts & BackButtonStartPart) // FIXME: Hyatt, what about BackButtonEndPart?
662 webParts |= WebBackButtonPart;
663 if (parts & BackTrackPart)
664 webParts |= WebBackTrackPart;
665 if (parts & ThumbPart)
666 webParts |= WebThumbPart;
667 if (parts & ForwardTrackPart)
668 webParts |= WebForwardTrackPart;
669 if (parts & ForwardButtonStartPart) // FIXME: Hyatt, what about ForwardButtonEndPart?
670 webParts |= WebForwardButtonPart;
671
672 WebScrollbarControlPart webPressedPart = WebNoScrollPart;
673 switch (pressedPart) {
674 case BackButtonStartPart: // FIXME: Hyatt, what about BackButtonEndPart?
675 webPressedPart = WebBackButtonPart;
676 break;
677 case BackTrackPart:
678 webPressedPart = WebBackTrackPart;
679 break;
680 case ThumbPart:
681 webPressedPart = WebThumbPart;
682 break;
683 case ForwardTrackPart:
684 webPressedPart = WebForwardTrackPart;
685 break;
686 case ForwardButtonStartPart: // FIXME: Hyatt, what about ForwardButtonEndPart?
687 webPressedPart = WebForwardButtonPart;
688 break;
689 default:
690 break;
691 }
692
693 WebScrollBarControlSize webSize;
694 switch (size) {
695 case SmallScrollbar:
696 webSize = WebSmallScrollbar;
697 break;
698 case RegularScrollbar:
699 default:
700 webSize = WebRegularScrollbar;
701 }
702 WebScrollbarControlState webState = 0;
703 if (state & ActiveScrollbarState)
704 webState |= WebActiveScrollbarState;
705 if (state & EnabledScrollbarState)
706 webState |= WebEnabledScrollbarState;
707 if (state & PressedScrollbarState)
708 webState |= WebPressedScrollbarState;
709
710 RECT webRect = enclosingIntRect(rect);
711 LocalWindowsContext windowsContext(context, webRect);
712 HRESULT hr = delegate->paintCustomScrollbar(m_webView, windowsContext.hdc(), webRect, webSize, webState, webPressedPart,
713 vertical, value, proportion, webParts);
714 return SUCCEEDED(hr);
715 }
716
paintCustomScrollCorner(GraphicsContext * context,const FloatRect & rect)717 bool WebChromeClient::paintCustomScrollCorner(GraphicsContext* context, const FloatRect& rect)
718 {
719 if (context->paintingDisabled())
720 return false;
721
722 COMPtr<IWebUIDelegate> delegate = uiDelegate();
723 if (!delegate)
724 return false;
725
726 RECT webRect = enclosingIntRect(rect);
727 LocalWindowsContext windowsContext(context, webRect);
728 HRESULT hr = delegate->paintCustomScrollCorner(m_webView, windowsContext.hdc(), webRect);
729 return SUCCEEDED(hr);
730 }
731
runOpenPanel(Frame *,PassRefPtr<FileChooser> prpFileChooser)732 void WebChromeClient::runOpenPanel(Frame*, PassRefPtr<FileChooser> prpFileChooser)
733 {
734 RefPtr<FileChooser> fileChooser = prpFileChooser;
735
736 HWND viewWindow;
737 if (FAILED(m_webView->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow))))
738 return;
739
740 bool multiFile = fileChooser->allowsMultipleFiles();
741 Vector<WCHAR> fileBuf(multiFile ? maxFilePathsListSize : MAX_PATH);
742
743 OPENFILENAME ofn;
744
745 memset(&ofn, 0, sizeof(ofn));
746
747 // Need to zero out the first char of fileBuf so GetOpenFileName doesn't think it's an initialization string
748 fileBuf[0] = '\0';
749
750 ofn.lStructSize = sizeof(ofn);
751 ofn.hwndOwner = viewWindow;
752 String allFiles = allFilesText();
753 allFiles.append(L"\0*.*\0\0", 6);
754 ofn.lpstrFilter = allFiles.charactersWithNullTermination();
755 ofn.lpstrFile = fileBuf.data();
756 ofn.nMaxFile = fileBuf.size();
757 String dialogTitle = uploadFileText();
758 ofn.lpstrTitle = dialogTitle.charactersWithNullTermination();
759 ofn.Flags = OFN_ENABLESIZING | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_EXPLORER;
760 if (multiFile)
761 ofn.Flags = ofn.Flags | OFN_ALLOWMULTISELECT;
762
763 if (GetOpenFileName(&ofn)) {
764 WCHAR* files = fileBuf.data();
765 Vector<String> fileList;
766 String file(files);
767 if (multiFile) {
768 while (!file.isEmpty()) {
769 // When using the OFN_EXPLORER flag, the file list is null delimited.
770 // When you create a String from a ptr to this list, it will use strlen to look for the null character.
771 // Then we find the next file path string by using the length of the string we just created.
772 WCHAR* nextFilePtr = files + file.length() + 1;
773 String nextFile(nextFilePtr);
774 // If multiple files are selected, there will be a directory name first, which we don't want to add to the vector.
775 // We know a single file was selected if there is only one filename in the list.
776 // In that case, we don't want to skip adding the first (and only) name.
777 if (files != fileBuf.data() || nextFile.isEmpty())
778 fileList.append(file);
779 files = nextFilePtr;
780 file = nextFile;
781 }
782 } else
783 fileList.append(file);
784 ASSERT(fileList.size());
785 fileChooser->chooseFiles(fileList);
786 }
787 // FIXME: Show some sort of error if too many files are selected and the buffer is too small. For now, this will fail silently.
788 }
789
chooseIconForFiles(const Vector<WTF::String> & filenames,WebCore::FileChooser * chooser)790 void WebChromeClient::chooseIconForFiles(const Vector<WTF::String>& filenames, WebCore::FileChooser* chooser)
791 {
792 chooser->iconLoaded(Icon::createIconForFiles(filenames));
793 }
794
setCursor(const Cursor & cursor)795 void WebChromeClient::setCursor(const Cursor& cursor)
796 {
797 HCURSOR platformCursor = cursor.platformCursor()->nativeCursor();
798 if (!platformCursor)
799 return;
800
801 bool shouldSetCursor = true;
802 if (COMPtr<IWebUIDelegate> delegate = uiDelegate()) {
803 COMPtr<IWebUIDelegatePrivate> delegatePrivate(Query, delegate);
804 if (delegatePrivate) {
805 if (SUCCEEDED(delegatePrivate->webViewSetCursor(m_webView, reinterpret_cast<OLE_HANDLE>(platformCursor))))
806 shouldSetCursor = false;
807 }
808 }
809
810 if (shouldSetCursor)
811 ::SetCursor(platformCursor);
812
813 setLastSetCursorToCurrentCursor();
814 }
815
setLastSetCursorToCurrentCursor()816 void WebChromeClient::setLastSetCursorToCurrentCursor()
817 {
818 m_webView->setLastCursor(::GetCursor());
819 }
820
821 #if USE(ACCELERATED_COMPOSITING)
attachRootGraphicsLayer(Frame * frame,GraphicsLayer * graphicsLayer)822 void WebChromeClient::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* graphicsLayer)
823 {
824 m_webView->setRootChildLayer(graphicsLayer);
825 }
826
scheduleCompositingLayerSync()827 void WebChromeClient::scheduleCompositingLayerSync()
828 {
829 m_webView->flushPendingGraphicsLayerChangesSoon();
830 }
831
832 #endif
833
uiDelegate()834 COMPtr<IWebUIDelegate> WebChromeClient::uiDelegate()
835 {
836 COMPtr<IWebUIDelegate> delegate;
837 m_webView->uiDelegate(&delegate);
838 return delegate;
839 }
840
841 #if ENABLE(VIDEO)
842
supportsFullscreenForNode(const Node * node)843 bool WebChromeClient::supportsFullscreenForNode(const Node* node)
844 {
845 return node->hasTagName(HTMLNames::videoTag);
846 }
847
enterFullscreenForNode(Node * node)848 void WebChromeClient::enterFullscreenForNode(Node* node)
849 {
850 m_webView->enterFullscreenForNode(node);
851 }
852
exitFullscreenForNode(Node *)853 void WebChromeClient::exitFullscreenForNode(Node*)
854 {
855 m_webView->exitFullscreen();
856 }
857
858 #endif
859
selectItemWritingDirectionIsNatural()860 bool WebChromeClient::selectItemWritingDirectionIsNatural()
861 {
862 return true;
863 }
864
selectItemAlignmentFollowsMenuWritingDirection()865 bool WebChromeClient::selectItemAlignmentFollowsMenuWritingDirection()
866 {
867 return false;
868 }
869
createPopupMenu(PopupMenuClient * client) const870 PassRefPtr<PopupMenu> WebChromeClient::createPopupMenu(PopupMenuClient* client) const
871 {
872 return adoptRef(new PopupMenuWin(client));
873 }
874
createSearchPopupMenu(PopupMenuClient * client) const875 PassRefPtr<SearchPopupMenu> WebChromeClient::createSearchPopupMenu(PopupMenuClient* client) const
876 {
877 return adoptRef(new SearchPopupMenuWin(client));
878 }
879
880