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/FileIconLoader.h> 46#include <WebCore/FloatRect.h> 47#include <WebCore/Frame.h> 48#include <WebCore/FrameLoadRequest.h> 49#include <WebCore/FrameView.h> 50#include <WebCore/FullScreenController.h> 51#include <WebCore/HTMLNames.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#if USE(ACCELERATED_COMPOSITING) 65#include <WebCore/GraphicsLayer.h> 66#endif 67 68using namespace WebCore; 69 70// When you call GetOpenFileName, if the size of the buffer is too small, 71// MSDN says that the first two bytes of the buffer contain the required size for the file selection, in bytes or characters 72// So we can assume the required size can't be more than the maximum value for a short. 73static const size_t maxFilePathsListSize = USHRT_MAX; 74 75WebChromeClient::WebChromeClient(WebView* webView) 76 : m_webView(webView) 77#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS) 78 , m_notificationsDelegate(new WebDesktopNotificationsDelegate(webView)) 79#endif 80{ 81} 82 83void WebChromeClient::chromeDestroyed() 84{ 85 delete this; 86} 87 88void WebChromeClient::setWindowRect(const FloatRect& r) 89{ 90 IWebUIDelegate* uiDelegate = 0; 91 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 92 RECT rect = IntRect(r); 93 uiDelegate->setFrame(m_webView, &rect); 94 uiDelegate->Release(); 95 } 96} 97 98FloatRect WebChromeClient::windowRect() 99{ 100 IWebUIDelegate* uiDelegate = 0; 101 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 102 RECT rect; 103 HRESULT retval = uiDelegate->webViewFrame(m_webView, &rect); 104 105 uiDelegate->Release(); 106 107 if (SUCCEEDED(retval)) 108 return rect; 109 } 110 111 return FloatRect(); 112} 113 114FloatRect WebChromeClient::pageRect() 115{ 116 RECT rect; 117 m_webView->frameRect(&rect); 118 return rect; 119} 120 121void WebChromeClient::focus() 122{ 123 IWebUIDelegate* uiDelegate = 0; 124 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 125 uiDelegate->webViewFocus(m_webView); 126 uiDelegate->Release(); 127 } 128 // Normally this would happen on a timer, but JS might need to know this earlier, so we'll update here. 129 m_webView->updateActiveState(); 130} 131 132void WebChromeClient::unfocus() 133{ 134 IWebUIDelegate* uiDelegate = 0; 135 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 136 uiDelegate->webViewUnfocus(m_webView); 137 uiDelegate->Release(); 138 } 139 // Normally this would happen on a timer, but JS might need to know this earlier, so we'll update here. 140 m_webView->updateActiveState(); 141} 142 143bool WebChromeClient::canTakeFocus(FocusDirection direction) 144{ 145 IWebUIDelegate* uiDelegate = 0; 146 BOOL bForward = (direction == FocusDirectionForward) ? TRUE : FALSE; 147 BOOL result = FALSE; 148 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 149 uiDelegate->canTakeFocus(m_webView, bForward, &result); 150 uiDelegate->Release(); 151 } 152 153 return !!result; 154} 155 156void WebChromeClient::takeFocus(FocusDirection direction) 157{ 158 IWebUIDelegate* uiDelegate = 0; 159 BOOL bForward = (direction == FocusDirectionForward) ? TRUE : FALSE; 160 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 161 uiDelegate->takeFocus(m_webView, bForward); 162 uiDelegate->Release(); 163 } 164} 165 166void WebChromeClient::focusedNodeChanged(Node*) 167{ 168} 169 170void WebChromeClient::focusedFrameChanged(Frame*) 171{ 172} 173 174static COMPtr<IPropertyBag> createWindowFeaturesPropertyBag(const WindowFeatures& features) 175{ 176 HashMap<String, COMVariant> map; 177 if (features.xSet) 178 map.set(WebWindowFeaturesXKey, features.x); 179 if (features.ySet) 180 map.set(WebWindowFeaturesYKey, features.y); 181 if (features.widthSet) 182 map.set(WebWindowFeaturesWidthKey, features.width); 183 if (features.heightSet) 184 map.set(WebWindowFeaturesHeightKey, features.height); 185 map.set(WebWindowFeaturesMenuBarVisibleKey, features.menuBarVisible); 186 map.set(WebWindowFeaturesStatusBarVisibleKey, features.statusBarVisible); 187 map.set(WebWindowFeaturesToolBarVisibleKey, features.toolBarVisible); 188 map.set(WebWindowFeaturesScrollbarsVisibleKey, features.scrollbarsVisible); 189 map.set(WebWindowFeaturesResizableKey, features.resizable); 190 map.set(WebWindowFeaturesFullscreenKey, features.fullscreen); 191 map.set(WebWindowFeaturesDialogKey, features.dialog); 192 193 return COMPtr<IPropertyBag>(AdoptCOM, COMPropertyBag<COMVariant>::adopt(map)); 194} 195 196Page* WebChromeClient::createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures& features, const NavigationAction&) 197{ 198 COMPtr<IWebUIDelegate> delegate = uiDelegate(); 199 if (!delegate) 200 return 0; 201 202 // Just create a blank request because createWindow() is only required to create window but not to load URL. 203 COMPtr<IWebMutableURLRequest> request(AdoptCOM, WebMutableURLRequest::createInstance()); 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 230void 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 239bool WebChromeClient::canRunModal() 240{ 241 BOOL result = FALSE; 242 if (COMPtr<IWebUIDelegate> delegate = uiDelegate()) 243 delegate->canRunModal(m_webView, &result); 244 return result; 245} 246 247void WebChromeClient::runModal() 248{ 249 if (COMPtr<IWebUIDelegate> delegate = uiDelegate()) 250 delegate->runModal(m_webView); 251} 252 253void 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 262bool 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 273void 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 282bool 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 293void WebChromeClient::setScrollbarsVisible(bool b) 294{ 295 WebFrame* webFrame = m_webView->topLevelFrame(); 296 if (webFrame) 297 webFrame->setAllowsScrolling(b); 298} 299 300bool 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 310void WebChromeClient::setMenubarVisible(bool visible) 311{ 312 COMPtr<IWebUIDelegate> delegate = uiDelegate(); 313 if (!delegate) 314 return; 315 delegate->setMenuBarVisible(m_webView, visible); 316} 317 318bool 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 328void 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 337void WebChromeClient::addMessageToConsole(MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, unsigned columnNumber, const String& url) 338{ 339 UNUSED_PARAM(columnNumber); 340 341 COMPtr<IWebUIDelegate> uiDelegate; 342 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 343 COMPtr<IWebUIDelegatePrivate> uiPrivate; 344 if (SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&uiPrivate))) 345 uiPrivate->webViewAddMessageToConsole(m_webView, BString(message), lineNumber, BString(url), true); 346 } 347} 348 349bool WebChromeClient::canRunBeforeUnloadConfirmPanel() 350{ 351 IWebUIDelegate* ui; 352 if (SUCCEEDED(m_webView->uiDelegate(&ui)) && ui) { 353 ui->Release(); 354 return true; 355 } 356 return false; 357} 358 359bool WebChromeClient::runBeforeUnloadConfirmPanel(const String& message, Frame* frame) 360{ 361 BOOL result = TRUE; 362 IWebUIDelegate* ui; 363 if (SUCCEEDED(m_webView->uiDelegate(&ui)) && ui) { 364 WebFrame* webFrame = kit(frame); 365 ui->runBeforeUnloadConfirmPanelWithMessage(m_webView, BString(message), webFrame, &result); 366 ui->Release(); 367 } 368 return !!result; 369} 370 371void WebChromeClient::closeWindowSoon() 372{ 373 // We need to remove the parent WebView from WebViewSets here, before it actually 374 // closes, to make sure that JavaScript code that executes before it closes 375 // can't find it. Otherwise, window.open will select a closed WebView instead of 376 // opening a new one <rdar://problem/3572585>. 377 378 // We also need to stop the load to prevent further parsing or JavaScript execution 379 // after the window has torn down <rdar://problem/4161660>. 380 381 // FIXME: This code assumes that the UI delegate will respond to a webViewClose 382 // message by actually closing the WebView. Safari guarantees this behavior, but other apps might not. 383 // This approach is an inherent limitation of not making a close execute immediately 384 // after a call to window.close. 385 386 m_webView->setGroupName(0); 387 m_webView->stopLoading(0); 388 m_webView->closeWindowSoon(); 389} 390 391void WebChromeClient::runJavaScriptAlert(Frame*, const String& message) 392{ 393 COMPtr<IWebUIDelegate> ui; 394 if (SUCCEEDED(m_webView->uiDelegate(&ui))) 395 ui->runJavaScriptAlertPanelWithMessage(m_webView, BString(message)); 396} 397 398bool WebChromeClient::runJavaScriptConfirm(Frame*, const String& message) 399{ 400 BOOL result = FALSE; 401 COMPtr<IWebUIDelegate> ui; 402 if (SUCCEEDED(m_webView->uiDelegate(&ui))) 403 ui->runJavaScriptConfirmPanelWithMessage(m_webView, BString(message), &result); 404 return !!result; 405} 406 407bool WebChromeClient::runJavaScriptPrompt(Frame*, const String& message, const String& defaultValue, String& result) 408{ 409 COMPtr<IWebUIDelegate> ui; 410 if (FAILED(m_webView->uiDelegate(&ui))) 411 return false; 412 413 TimerBase::fireTimersInNestedEventLoop(); 414 415 BString resultBSTR; 416 if (FAILED(ui->runJavaScriptTextInputPanelWithPrompt(m_webView, BString(message), BString(defaultValue), &resultBSTR))) 417 return false; 418 419 if (!resultBSTR) 420 return false; 421 422 result = String(resultBSTR, SysStringLen(resultBSTR)); 423 return true; 424} 425 426void WebChromeClient::setStatusbarText(const String& statusText) 427{ 428 COMPtr<IWebUIDelegate> uiDelegate; 429 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 430 uiDelegate->setStatusText(m_webView, BString(statusText)); 431 } 432} 433 434bool WebChromeClient::shouldInterruptJavaScript() 435{ 436 COMPtr<IWebUIDelegate> uiDelegate; 437 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 438 COMPtr<IWebUIDelegatePrivate> uiPrivate; 439 if (SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&uiPrivate))) { 440 BOOL result; 441 if (SUCCEEDED(uiPrivate->webViewShouldInterruptJavaScript(m_webView, &result))) 442 return !!result; 443 } 444 } 445 return false; 446} 447 448KeyboardUIMode WebChromeClient::keyboardUIMode() 449{ 450 BOOL enabled = FALSE; 451 IWebPreferences* preferences; 452 if (SUCCEEDED(m_webView->preferences(&preferences))) 453 preferences->tabsToLinks(&enabled); 454 455 return enabled ? KeyboardAccessTabsToLinks : KeyboardAccessDefault; 456} 457 458IntRect WebChromeClient::windowResizerRect() const 459{ 460 return IntRect(); 461} 462 463void WebChromeClient::invalidateRootView(const IntRect& windowRect, bool immediate) 464{ 465 ASSERT(core(m_webView->topLevelFrame())); 466 m_webView->repaint(windowRect, false /*contentChanged*/, immediate, false /*repaintContentOnly*/); 467} 468 469void WebChromeClient::invalidateContentsAndRootView(const IntRect& windowRect, bool immediate) 470{ 471 ASSERT(core(m_webView->topLevelFrame())); 472 m_webView->repaint(windowRect, true /*contentChanged*/, immediate /*immediate*/, false /*repaintContentOnly*/); 473} 474 475void WebChromeClient::invalidateContentsForSlowScroll(const IntRect& windowRect, bool immediate) 476{ 477 ASSERT(core(m_webView->topLevelFrame())); 478 m_webView->repaint(windowRect, true /*contentChanged*/, immediate, true /*repaintContentOnly*/); 479} 480 481void WebChromeClient::scroll(const IntSize& delta, const IntRect& scrollViewRect, const IntRect& clipRect) 482{ 483 ASSERT(core(m_webView->topLevelFrame())); 484 485 m_webView->scrollBackingStore(core(m_webView->topLevelFrame())->view(), delta.width(), delta.height(), scrollViewRect, clipRect); 486} 487 488IntRect WebChromeClient::rootViewToScreen(const IntRect& rect) const 489{ 490 HWND viewWindow; 491 if (FAILED(m_webView->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow)))) 492 return rect; 493 494 // Find the top left corner of the Widget's containing window in screen coords, 495 // and adjust the result rect's position by this amount. 496 POINT topLeft = {0, 0}; 497 IntRect result = rect; 498 ::ClientToScreen(viewWindow, &topLeft); 499 result.move(topLeft.x, topLeft.y); 500 501 return result; 502} 503 504IntPoint WebChromeClient::screenToRootView(const IntPoint& point) const 505{ 506 POINT result = point; 507 508 HWND viewWindow; 509 if (FAILED(m_webView->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow)))) 510 return point; 511 512 ::ScreenToClient(viewWindow, &result); 513 514 return result; 515} 516 517PlatformPageClient WebChromeClient::platformPageClient() const 518{ 519 HWND viewWindow; 520 if (FAILED(m_webView->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow)))) 521 return 0; 522 return viewWindow; 523} 524 525void WebChromeClient::contentsSizeChanged(Frame*, const IntSize&) const 526{ 527 notImplemented(); 528} 529 530void WebChromeClient::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags) 531{ 532 COMPtr<IWebUIDelegate> uiDelegate; 533 if (FAILED(m_webView->uiDelegate(&uiDelegate))) 534 return; 535 536 COMPtr<WebElementPropertyBag> element; 537 element.adoptRef(WebElementPropertyBag::createInstance(result)); 538 539 uiDelegate->mouseDidMoveOverElement(m_webView, element.get(), modifierFlags); 540} 541 542bool WebChromeClient::shouldUnavailablePluginMessageBeButton(RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason) const 543{ 544 if (pluginUnavailabilityReason != RenderEmbeddedObject::PluginMissing) 545 return false; 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 557void WebChromeClient::unavailablePluginButtonClicked(Element* element, RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason) const 558{ 559 ASSERT_UNUSED(pluginUnavailabilityReason, pluginUnavailabilityReason == RenderEmbeddedObject::PluginMissing); 560 561 COMPtr<IWebUIDelegate> uiDelegate; 562 if (FAILED(m_webView->uiDelegate(&uiDelegate))) 563 return; 564 565 COMPtr<IWebUIDelegatePrivate3> uiDelegatePrivate3(Query, uiDelegate); 566 if (!uiDelegatePrivate3) 567 return; 568 569 COMPtr<IDOMElement> e(AdoptCOM, DOMElement::createInstance(element)); 570 uiDelegatePrivate3->didPressMissingPluginButton(e.get()); 571} 572 573void WebChromeClient::setToolTip(const String& toolTip, TextDirection) 574{ 575 m_webView->setToolTip(toolTip); 576} 577 578void WebChromeClient::print(Frame* frame) 579{ 580 COMPtr<IWebUIDelegate> uiDelegate; 581 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) 582 uiDelegate->printFrame(m_webView, kit(frame)); 583} 584 585#if ENABLE(SQL_DATABASE) 586void WebChromeClient::exceededDatabaseQuota(Frame* frame, const String& databaseIdentifier, DatabaseDetails) 587{ 588 COMPtr<WebSecurityOrigin> origin(AdoptCOM, WebSecurityOrigin::createInstance(frame->document()->securityOrigin())); 589 COMPtr<IWebUIDelegate> uiDelegate; 590 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 591 COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate(Query, uiDelegate); 592 if (uiDelegatePrivate) 593 uiDelegatePrivate->exceededDatabaseQuota(m_webView, kit(frame), origin.get(), BString(databaseIdentifier)); 594 else { 595 // FIXME: remove this workaround once shipping Safari has the necessary delegate implemented. 596 WCHAR path[MAX_PATH]; 597 HMODULE safariHandle = GetModuleHandleW(L"Safari.exe"); 598 if (!safariHandle) 599 return; 600 GetModuleFileName(safariHandle, path, WTF_ARRAY_LENGTH(path)); 601 DWORD handle; 602 DWORD versionSize = GetFileVersionInfoSize(path, &handle); 603 if (!versionSize) 604 return; 605 Vector<char> data(versionSize); 606 if (!GetFileVersionInfo(path, 0, versionSize, data.data())) 607 return; 608 609 LPCTSTR productVersion; 610 UINT productVersionLength; 611 if (!VerQueryValueW(data.data(), L"\\StringFileInfo\\040904b0\\ProductVersion", (void**)&productVersion, &productVersionLength)) 612 return; 613 if (wcsncmp(L"3.1", productVersion, productVersionLength) > 0) { 614 const unsigned long long defaultQuota = 5 * 1024 * 1024; // 5 megabytes should hopefully be enough to test storage support. 615 origin->setQuota(defaultQuota); 616 } 617 } 618 } 619} 620#endif 621 622// FIXME: Move this include to the top of the file with the other includes. 623#include "ApplicationCacheStorage.h" 624 625void WebChromeClient::reachedMaxAppCacheSize(int64_t spaceNeeded) 626{ 627 // FIXME: Free some space. 628 notImplemented(); 629} 630 631void WebChromeClient::reachedApplicationCacheOriginQuota(SecurityOrigin*, int64_t) 632{ 633 notImplemented(); 634} 635 636void WebChromeClient::populateVisitedLinks() 637{ 638 COMPtr<IWebHistoryDelegate> historyDelegate; 639 m_webView->historyDelegate(&historyDelegate); 640 if (historyDelegate) { 641 historyDelegate->populateVisitedLinksForWebView(m_webView); 642 return; 643 } 644 645 WebHistory* history = WebHistory::sharedHistory(); 646 if (!history) 647 return; 648 history->addVisitedLinksToPageGroup(m_webView->page()->group()); 649} 650 651void WebChromeClient::runOpenPanel(Frame*, PassRefPtr<FileChooser> prpFileChooser) 652{ 653 RefPtr<FileChooser> fileChooser = prpFileChooser; 654 655 HWND viewWindow; 656 if (FAILED(m_webView->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow)))) 657 return; 658 659 bool multiFile = fileChooser->settings().allowsMultipleFiles; 660 Vector<WCHAR> fileBuf(multiFile ? maxFilePathsListSize : MAX_PATH); 661 662 OPENFILENAME ofn; 663 664 memset(&ofn, 0, sizeof(ofn)); 665 666 // Need to zero out the first char of fileBuf so GetOpenFileName doesn't think it's an initialization string 667 fileBuf[0] = '\0'; 668 669 ofn.lStructSize = sizeof(ofn); 670 ofn.hwndOwner = viewWindow; 671 String allFiles = allFilesText(); 672 allFiles.append(L"\0*.*\0\0", 6); 673 ofn.lpstrFilter = allFiles.charactersWithNullTermination(); 674 ofn.lpstrFile = fileBuf.data(); 675 ofn.nMaxFile = fileBuf.size(); 676 String dialogTitle = uploadFileText(); 677 ofn.lpstrTitle = dialogTitle.charactersWithNullTermination(); 678 ofn.Flags = OFN_ENABLESIZING | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_EXPLORER; 679 if (multiFile) 680 ofn.Flags = ofn.Flags | OFN_ALLOWMULTISELECT; 681 682 if (GetOpenFileName(&ofn)) { 683 WCHAR* files = fileBuf.data(); 684 Vector<String> fileList; 685 String file(files); 686 if (multiFile) { 687 while (!file.isEmpty()) { 688 // When using the OFN_EXPLORER flag, the file list is null delimited. 689 // When you create a String from a ptr to this list, it will use strlen to look for the null character. 690 // Then we find the next file path string by using the length of the string we just created. 691 WCHAR* nextFilePtr = files + file.length() + 1; 692 String nextFile(nextFilePtr); 693 // If multiple files are selected, there will be a directory name first, which we don't want to add to the vector. 694 // We know a single file was selected if there is only one filename in the list. 695 // In that case, we don't want to skip adding the first (and only) name. 696 if (files != fileBuf.data() || nextFile.isEmpty()) 697 fileList.append(file); 698 files = nextFilePtr; 699 file = nextFile; 700 } 701 } else 702 fileList.append(file); 703 ASSERT(fileList.size()); 704 fileChooser->chooseFiles(fileList); 705 } 706 // FIXME: Show some sort of error if too many files are selected and the buffer is too small. For now, this will fail silently. 707} 708 709void WebChromeClient::loadIconForFiles(const Vector<WTF::String>& filenames, WebCore::FileIconLoader* loader) 710{ 711 loader->notifyFinished(Icon::createIconForFiles(filenames)); 712} 713 714void WebChromeClient::setCursor(const Cursor& cursor) 715{ 716 HCURSOR platformCursor = cursor.platformCursor()->nativeCursor(); 717 if (!platformCursor) 718 return; 719 720 bool shouldSetCursor = true; 721 if (COMPtr<IWebUIDelegate> delegate = uiDelegate()) { 722 COMPtr<IWebUIDelegatePrivate> delegatePrivate(Query, delegate); 723 if (delegatePrivate) { 724 if (SUCCEEDED(delegatePrivate->webViewSetCursor(m_webView, reinterpret_cast<OLE_HANDLE>(platformCursor)))) 725 shouldSetCursor = false; 726 } 727 } 728 729 if (shouldSetCursor) 730 ::SetCursor(platformCursor); 731 732 setLastSetCursorToCurrentCursor(); 733} 734 735void WebChromeClient::setCursorHiddenUntilMouseMoves(bool) 736{ 737 notImplemented(); 738} 739 740void WebChromeClient::setLastSetCursorToCurrentCursor() 741{ 742 m_webView->setLastCursor(::GetCursor()); 743} 744 745#if USE(ACCELERATED_COMPOSITING) 746void WebChromeClient::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* graphicsLayer) 747{ 748 m_webView->setRootChildLayer(graphicsLayer); 749} 750 751void WebChromeClient::scheduleCompositingLayerFlush() 752{ 753 m_webView->flushPendingGraphicsLayerChangesSoon(); 754} 755#endif 756 757#if PLATFORM(WIN) && USE(AVFOUNDATION) 758WebCore::GraphicsDeviceAdapter* WebChromeClient::graphicsDeviceAdapter() const 759{ 760 return m_webView->graphicsDeviceAdapter(); 761} 762#endif 763 764COMPtr<IWebUIDelegate> WebChromeClient::uiDelegate() 765{ 766 COMPtr<IWebUIDelegate> delegate; 767 m_webView->uiDelegate(&delegate); 768 return delegate; 769} 770 771#if ENABLE(VIDEO) 772 773bool WebChromeClient::supportsFullscreenForNode(const Node* node) 774{ 775 return node->hasTagName(HTMLNames::videoTag); 776} 777 778void WebChromeClient::enterFullscreenForNode(Node* node) 779{ 780 m_webView->enterFullscreenForNode(node); 781} 782 783void WebChromeClient::exitFullscreenForNode(Node*) 784{ 785 m_webView->exitFullscreen(); 786} 787 788#endif 789 790bool WebChromeClient::selectItemWritingDirectionIsNatural() 791{ 792 return true; 793} 794 795bool WebChromeClient::selectItemAlignmentFollowsMenuWritingDirection() 796{ 797 return false; 798} 799 800bool WebChromeClient::hasOpenedPopup() const 801{ 802 notImplemented(); 803 return false; 804} 805 806PassRefPtr<PopupMenu> WebChromeClient::createPopupMenu(PopupMenuClient* client) const 807{ 808 return adoptRef(new PopupMenuWin(client)); 809} 810 811PassRefPtr<SearchPopupMenu> WebChromeClient::createSearchPopupMenu(PopupMenuClient* client) const 812{ 813 return adoptRef(new SearchPopupMenuWin(client)); 814} 815 816#if ENABLE(FULLSCREEN_API) 817bool WebChromeClient::supportsFullScreenForElement(const Element* element, bool requestingKeyboardAccess) 818{ 819 COMPtr<IWebUIDelegate> uiDelegate; 820 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 821 COMPtr<IWebUIDelegatePrivate4> uiDelegatePrivate4(Query, uiDelegate); 822 BOOL supports = FALSE; 823 COMPtr<IDOMElement> domElement(AdoptCOM, DOMElement::createInstance(const_cast<Element*>(element))); 824 825 if (uiDelegatePrivate4 && SUCCEEDED(uiDelegatePrivate4->supportsFullScreenForElement(domElement.get(), requestingKeyboardAccess, &supports))) 826 return supports; 827 } 828 829 return m_webView->supportsFullScreenForElement(element, requestingKeyboardAccess); 830} 831 832void WebChromeClient::enterFullScreenForElement(Element* element) 833{ 834 COMPtr<IWebUIDelegate> uiDelegate; 835 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 836 COMPtr<IWebUIDelegatePrivate4> uiDelegatePrivate4(Query, uiDelegate); 837 COMPtr<IDOMElement> domElement(AdoptCOM, DOMElement::createInstance(element)); 838 if (uiDelegatePrivate4 && SUCCEEDED(uiDelegatePrivate4->enterFullScreenForElement(domElement.get()))) 839 return; 840 } 841 842 m_webView->setFullScreenElement(element); 843 m_webView->fullScreenController()->enterFullScreen(); 844} 845 846void WebChromeClient::exitFullScreenForElement(Element* element) 847{ 848 COMPtr<IWebUIDelegate> uiDelegate; 849 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 850 COMPtr<IWebUIDelegatePrivate4> uiDelegatePrivate4(Query, uiDelegate); 851 COMPtr<IDOMElement> domElement(AdoptCOM, DOMElement::createInstance(element)); 852 if (uiDelegatePrivate4 && SUCCEEDED(uiDelegatePrivate4->exitFullScreenForElement(domElement.get()))) 853 return; 854 } 855 856 ASSERT(element == m_webView->fullScreenElement()); 857 m_webView->fullScreenController()->exitFullScreen(); 858} 859 860void WebChromeClient::AXStartFrameLoad() 861{ 862 COMPtr<IAccessibilityDelegate> delegate; 863 m_webView->accessibilityDelegate(&delegate); 864 if (delegate) 865 delegate->fireFrameLoadStartedEvents(); 866} 867 868void WebChromeClient::AXFinishFrameLoad() 869{ 870 COMPtr<IAccessibilityDelegate> delegate; 871 m_webView->accessibilityDelegate(&delegate); 872 if (delegate) 873 delegate->fireFrameLoadFinishedEvents(); 874} 875 876#endif 877