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 72 WebChromeClient::WebChromeClient(WebView* webView) 73 : m_webView(webView) 74 #if ENABLE(NOTIFICATIONS) 75 , m_notificationsDelegate(new WebDesktopNotificationsDelegate(webView)) 76 #endif 77 { 78 } 79 80 void WebChromeClient::chromeDestroyed() 81 { 82 delete this; 83 } 84 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 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 111 FloatRect WebChromeClient::pageRect() 112 { 113 RECT rect; 114 m_webView->frameRect(&rect); 115 return rect; 116 } 117 118 float WebChromeClient::scaleFactor() 119 { 120 // Windows doesn't support UI scaling. 121 return 1.0; 122 } 123 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 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 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 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 169 void WebChromeClient::focusedNodeChanged(Node*) 170 { 171 } 172 173 void WebChromeClient::focusedFrameChanged(Frame*) 174 { 175 } 176 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 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 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 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 250 void WebChromeClient::runModal() 251 { 252 if (COMPtr<IWebUIDelegate> delegate = uiDelegate()) 253 delegate->runModal(m_webView); 254 } 255 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 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 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 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 296 void WebChromeClient::setScrollbarsVisible(bool b) 297 { 298 WebFrame* webFrame = m_webView->topLevelFrame(); 299 if (webFrame) 300 webFrame->setAllowsScrolling(b); 301 } 302 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 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 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 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 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 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 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 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 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 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 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 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 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 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 461 IntRect WebChromeClient::windowResizerRect() const 462 { 463 return IntRect(); 464 } 465 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 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 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 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 491 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 507 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 520 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 528 void WebChromeClient::contentsSizeChanged(Frame*, const IntSize&) const 529 { 530 notImplemented(); 531 } 532 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 545 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 557 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 571 void WebChromeClient::setToolTip(const String& toolTip, TextDirection) 572 { 573 m_webView->setToolTip(toolTip); 574 } 575 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) 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" 622 void WebChromeClient::reachedMaxAppCacheSize(int64_t spaceNeeded) 623 { 624 // FIXME: Free some space. 625 notImplemented(); 626 } 627 628 void WebChromeClient::reachedApplicationCacheOriginQuota(SecurityOrigin*) 629 { 630 notImplemented(); 631 } 632 #endif 633 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 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 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 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 790 void WebChromeClient::chooseIconForFiles(const Vector<WTF::String>& filenames, WebCore::FileChooser* chooser) 791 { 792 chooser->iconLoaded(Icon::createIconForFiles(filenames)); 793 } 794 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 816 void WebChromeClient::setLastSetCursorToCurrentCursor() 817 { 818 m_webView->setLastCursor(::GetCursor()); 819 } 820 821 #if USE(ACCELERATED_COMPOSITING) 822 void WebChromeClient::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* graphicsLayer) 823 { 824 m_webView->setRootChildLayer(graphicsLayer); 825 } 826 827 void WebChromeClient::scheduleCompositingLayerSync() 828 { 829 m_webView->flushPendingGraphicsLayerChangesSoon(); 830 } 831 832 #endif 833 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 843 bool WebChromeClient::supportsFullscreenForNode(const Node* node) 844 { 845 return node->hasTagName(HTMLNames::videoTag); 846 } 847 848 void WebChromeClient::enterFullscreenForNode(Node* node) 849 { 850 m_webView->enterFullscreenForNode(node); 851 } 852 853 void WebChromeClient::exitFullscreenForNode(Node*) 854 { 855 m_webView->exitFullscreen(); 856 } 857 858 #endif 859 860 bool WebChromeClient::selectItemWritingDirectionIsNatural() 861 { 862 return true; 863 } 864 865 bool WebChromeClient::selectItemAlignmentFollowsMenuWritingDirection() 866 { 867 return false; 868 } 869 870 PassRefPtr<PopupMenu> WebChromeClient::createPopupMenu(PopupMenuClient* client) const 871 { 872 return adoptRef(new PopupMenuWin(client)); 873 } 874 875 PassRefPtr<SearchPopupMenu> WebChromeClient::createSearchPopupMenu(PopupMenuClient* client) const 876 { 877 return adoptRef(new SearchPopupMenuWin(client)); 878 } 879 880