1 /* 2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "WebChromeClient.h" 28 29 #include "COMPropertyBag.h" 30 #include "COMVariantSetter.h" 31 #include "WebElementPropertyBag.h" 32 #include "WebFrame.h" 33 #include "WebGeolocationPolicyListener.h" 34 #include "WebHistory.h" 35 #include "WebMutableURLRequest.h" 36 #include "WebDesktopNotificationsDelegate.h" 37 #include "WebSecurityOrigin.h" 38 #include "WebView.h" 39 #pragma warning(push, 0) 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/Geolocation.h> 49 #include <WebCore/HTMLNames.h> 50 #include <WebCore/LocalizedStrings.h> 51 #include <WebCore/NotImplemented.h> 52 #include <WebCore/Page.h> 53 #include <WebCore/WindowFeatures.h> 54 #pragma warning(pop) 55 56 #include <tchar.h> 57 58 using namespace WebCore; 59 60 // When you call GetOpenFileName, if the size of the buffer is too small, 61 // MSDN says that the first two bytes of the buffer contain the required size for the file selection, in bytes or characters 62 // So we can assume the required size can't be more than the maximum value for a short. 63 static const size_t maxFilePathsListSize = USHRT_MAX; 64 65 WebChromeClient::WebChromeClient(WebView* webView) 66 : m_webView(webView) 67 #if ENABLE(NOTIFICATIONS) 68 , m_notificationsDelegate(new WebDesktopNotificationsDelegate(webView)) 69 #endif 70 { 71 } 72 73 void WebChromeClient::chromeDestroyed() 74 { 75 delete this; 76 } 77 78 void WebChromeClient::setWindowRect(const FloatRect& r) 79 { 80 IWebUIDelegate* uiDelegate = 0; 81 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 82 RECT rect = IntRect(r); 83 uiDelegate->setFrame(m_webView, &rect); 84 uiDelegate->Release(); 85 } 86 } 87 88 FloatRect WebChromeClient::windowRect() 89 { 90 IWebUIDelegate* uiDelegate = 0; 91 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 92 RECT rect; 93 HRESULT retval = uiDelegate->webViewFrame(m_webView, &rect); 94 95 uiDelegate->Release(); 96 97 if (SUCCEEDED(retval)) 98 return rect; 99 } 100 101 return FloatRect(); 102 } 103 104 FloatRect WebChromeClient::pageRect() 105 { 106 RECT rect; 107 m_webView->frameRect(&rect); 108 return rect; 109 } 110 111 float WebChromeClient::scaleFactor() 112 { 113 // Windows doesn't support UI scaling. 114 return 1.0; 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::focusedNodeChanged(Node*) 163 { 164 } 165 166 static COMPtr<IPropertyBag> createWindowFeaturesPropertyBag(const WindowFeatures& features) 167 { 168 HashMap<String, COMVariant> map; 169 if (features.xSet) 170 map.set(WebWindowFeaturesXKey, features.x); 171 if (features.ySet) 172 map.set(WebWindowFeaturesYKey, features.y); 173 if (features.widthSet) 174 map.set(WebWindowFeaturesWidthKey, features.width); 175 if (features.heightSet) 176 map.set(WebWindowFeaturesHeightKey, features.height); 177 map.set(WebWindowFeaturesMenuBarVisibleKey, features.menuBarVisible); 178 map.set(WebWindowFeaturesStatusBarVisibleKey, features.statusBarVisible); 179 map.set(WebWindowFeaturesToolBarVisibleKey, features.toolBarVisible); 180 map.set(WebWindowFeaturesScrollbarsVisibleKey, features.scrollbarsVisible); 181 map.set(WebWindowFeaturesResizableKey, features.resizable); 182 map.set(WebWindowFeaturesFullscreenKey, features.fullscreen); 183 map.set(WebWindowFeaturesDialogKey, features.dialog); 184 185 return COMPtr<IPropertyBag>(AdoptCOM, COMPropertyBag<COMVariant>::adopt(map)); 186 } 187 188 Page* WebChromeClient::createWindow(Frame*, const FrameLoadRequest& frameLoadRequest, const WindowFeatures& features) 189 { 190 COMPtr<IWebUIDelegate> delegate = uiDelegate(); 191 if (!delegate) 192 return 0; 193 194 COMPtr<IWebMutableURLRequest> request(AdoptCOM, WebMutableURLRequest::createInstance(frameLoadRequest.resourceRequest())); 195 196 COMPtr<IWebUIDelegatePrivate2> delegatePrivate(Query, delegate); 197 if (delegatePrivate) { 198 COMPtr<IWebView> newWebView; 199 HRESULT hr = delegatePrivate->createWebViewWithRequest(m_webView, request.get(), createWindowFeaturesPropertyBag(features).get(), &newWebView); 200 201 if (SUCCEEDED(hr) && newWebView) 202 return core(newWebView.get()); 203 204 // If the delegate doesn't implement the IWebUIDelegatePrivate2 version of the call, fall back 205 // to the old versions (even if they support the IWebUIDelegatePrivate2 interface). 206 if (hr != E_NOTIMPL) 207 return 0; 208 } 209 210 COMPtr<IWebView> newWebView; 211 212 if (features.dialog) { 213 if (FAILED(delegate->createModalDialog(m_webView, request.get(), &newWebView))) 214 return 0; 215 } else if (FAILED(delegate->createWebViewWithRequest(m_webView, request.get(), &newWebView))) 216 return 0; 217 218 return newWebView ? core(newWebView.get()) : 0; 219 } 220 221 void WebChromeClient::show() 222 { 223 IWebUIDelegate* uiDelegate = 0; 224 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 225 uiDelegate->webViewShow(m_webView); 226 uiDelegate->Release(); 227 } 228 } 229 230 bool WebChromeClient::canRunModal() 231 { 232 BOOL result = FALSE; 233 if (COMPtr<IWebUIDelegate> delegate = uiDelegate()) 234 delegate->canRunModal(m_webView, &result); 235 return result; 236 } 237 238 void WebChromeClient::runModal() 239 { 240 if (COMPtr<IWebUIDelegate> delegate = uiDelegate()) 241 delegate->runModal(m_webView); 242 } 243 244 void WebChromeClient::setToolbarsVisible(bool visible) 245 { 246 IWebUIDelegate* uiDelegate = 0; 247 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 248 uiDelegate->setToolbarsVisible(m_webView, visible); 249 uiDelegate->Release(); 250 } 251 } 252 253 bool WebChromeClient::toolbarsVisible() 254 { 255 BOOL result = false; 256 IWebUIDelegate* uiDelegate = 0; 257 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 258 uiDelegate->webViewAreToolbarsVisible(m_webView, &result); 259 uiDelegate->Release(); 260 } 261 return result != false; 262 } 263 264 void WebChromeClient::setStatusbarVisible(bool visible) 265 { 266 IWebUIDelegate* uiDelegate = 0; 267 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 268 uiDelegate->setStatusBarVisible(m_webView, visible); 269 uiDelegate->Release(); 270 } 271 } 272 273 bool WebChromeClient::statusbarVisible() 274 { 275 BOOL result = false; 276 IWebUIDelegate* uiDelegate = 0; 277 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 278 uiDelegate->webViewIsStatusBarVisible(m_webView, &result); 279 uiDelegate->Release(); 280 } 281 return result != false; 282 } 283 284 void WebChromeClient::setScrollbarsVisible(bool b) 285 { 286 WebFrame* webFrame = m_webView->topLevelFrame(); 287 if (webFrame) 288 webFrame->setAllowsScrolling(b); 289 } 290 291 bool WebChromeClient::scrollbarsVisible() 292 { 293 WebFrame* webFrame = m_webView->topLevelFrame(); 294 BOOL b = false; 295 if (webFrame) 296 webFrame->allowsScrolling(&b); 297 298 return !!b; 299 } 300 301 void WebChromeClient::setMenubarVisible(bool visible) 302 { 303 COMPtr<IWebUIDelegate> delegate = uiDelegate(); 304 if (!delegate) 305 return; 306 delegate->setMenuBarVisible(m_webView, visible); 307 } 308 309 bool WebChromeClient::menubarVisible() 310 { 311 COMPtr<IWebUIDelegate> delegate = uiDelegate(); 312 if (!delegate) 313 return true; 314 BOOL result = true; 315 delegate->isMenuBarVisible(m_webView, &result); 316 return result; 317 } 318 319 void WebChromeClient::setResizable(bool resizable) 320 { 321 IWebUIDelegate* uiDelegate = 0; 322 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 323 uiDelegate->setResizable(m_webView, resizable); 324 uiDelegate->Release(); 325 } 326 } 327 328 void WebChromeClient::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned line, const String& url) 329 { 330 COMPtr<IWebUIDelegate> uiDelegate; 331 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 332 COMPtr<IWebUIDelegatePrivate> uiPrivate; 333 if (SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&uiPrivate))) 334 uiPrivate->webViewAddMessageToConsole(m_webView, BString(message), line, BString(url), true); 335 } 336 } 337 338 bool WebChromeClient::canRunBeforeUnloadConfirmPanel() 339 { 340 IWebUIDelegate* ui; 341 if (SUCCEEDED(m_webView->uiDelegate(&ui)) && ui) { 342 ui->Release(); 343 return true; 344 } 345 return false; 346 } 347 348 bool WebChromeClient::runBeforeUnloadConfirmPanel(const String& message, Frame* frame) 349 { 350 BOOL result = TRUE; 351 IWebUIDelegate* ui; 352 if (SUCCEEDED(m_webView->uiDelegate(&ui)) && ui) { 353 WebFrame* webFrame = kit(frame); 354 ui->runBeforeUnloadConfirmPanelWithMessage(m_webView, BString(message), webFrame, &result); 355 ui->Release(); 356 } 357 return !!result; 358 } 359 360 void WebChromeClient::closeWindowSoon() 361 { 362 // We need to remove the parent WebView from WebViewSets here, before it actually 363 // closes, to make sure that JavaScript code that executes before it closes 364 // can't find it. Otherwise, window.open will select a closed WebView instead of 365 // opening a new one <rdar://problem/3572585>. 366 367 // We also need to stop the load to prevent further parsing or JavaScript execution 368 // after the window has torn down <rdar://problem/4161660>. 369 370 // FIXME: This code assumes that the UI delegate will respond to a webViewClose 371 // message by actually closing the WebView. Safari guarantees this behavior, but other apps might not. 372 // This approach is an inherent limitation of not making a close execute immediately 373 // after a call to window.close. 374 375 m_webView->setGroupName(0); 376 m_webView->stopLoading(0); 377 m_webView->closeWindowSoon(); 378 } 379 380 void WebChromeClient::runJavaScriptAlert(Frame*, const String& message) 381 { 382 COMPtr<IWebUIDelegate> ui; 383 if (SUCCEEDED(m_webView->uiDelegate(&ui))) 384 ui->runJavaScriptAlertPanelWithMessage(m_webView, BString(message)); 385 } 386 387 bool WebChromeClient::runJavaScriptConfirm(Frame*, const String& message) 388 { 389 BOOL result = FALSE; 390 COMPtr<IWebUIDelegate> ui; 391 if (SUCCEEDED(m_webView->uiDelegate(&ui))) 392 ui->runJavaScriptConfirmPanelWithMessage(m_webView, BString(message), &result); 393 return !!result; 394 } 395 396 bool WebChromeClient::runJavaScriptPrompt(Frame*, const String& message, const String& defaultValue, String& result) 397 { 398 COMPtr<IWebUIDelegate> ui; 399 if (FAILED(m_webView->uiDelegate(&ui))) 400 return false; 401 402 TimerBase::fireTimersInNestedEventLoop(); 403 404 BSTR resultBSTR = 0; 405 if (FAILED(ui->runJavaScriptTextInputPanelWithPrompt(m_webView, BString(message), BString(defaultValue), &resultBSTR))) 406 return false; 407 408 if (resultBSTR) { 409 result = String(resultBSTR, SysStringLen(resultBSTR)); 410 SysFreeString(resultBSTR); 411 return true; 412 } 413 414 return false; 415 } 416 417 void WebChromeClient::setStatusbarText(const String& statusText) 418 { 419 COMPtr<IWebUIDelegate> uiDelegate; 420 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 421 uiDelegate->setStatusText(m_webView, BString(statusText)); 422 } 423 } 424 425 bool WebChromeClient::shouldInterruptJavaScript() 426 { 427 COMPtr<IWebUIDelegate> uiDelegate; 428 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 429 COMPtr<IWebUIDelegatePrivate> uiPrivate; 430 if (SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&uiPrivate))) { 431 BOOL result; 432 if (SUCCEEDED(uiPrivate->webViewShouldInterruptJavaScript(m_webView, &result))) 433 return !!result; 434 } 435 } 436 return false; 437 } 438 439 bool WebChromeClient::tabsToLinks() const 440 { 441 BOOL enabled = FALSE; 442 IWebPreferences* preferences; 443 if (SUCCEEDED(m_webView->preferences(&preferences))) 444 preferences->tabsToLinks(&enabled); 445 446 return !!enabled; 447 } 448 449 IntRect WebChromeClient::windowResizerRect() const 450 { 451 return IntRect(); 452 } 453 454 void WebChromeClient::repaint(const IntRect& windowRect, bool contentChanged, bool immediate, bool repaintContentOnly) 455 { 456 ASSERT(core(m_webView->topLevelFrame())); 457 m_webView->repaint(windowRect, contentChanged, immediate, repaintContentOnly); 458 } 459 460 void WebChromeClient::scroll(const IntSize& delta, const IntRect& scrollViewRect, const IntRect& clipRect) 461 { 462 ASSERT(core(m_webView->topLevelFrame())); 463 464 m_webView->scrollBackingStore(core(m_webView->topLevelFrame())->view(), delta.width(), delta.height(), scrollViewRect, clipRect); 465 } 466 467 IntRect WebChromeClient::windowToScreen(const IntRect& rect) const 468 { 469 HWND viewWindow; 470 if (FAILED(m_webView->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow)))) 471 return rect; 472 473 // Find the top left corner of the Widget's containing window in screen coords, 474 // and adjust the result rect's position by this amount. 475 POINT topLeft = {0, 0}; 476 IntRect result = rect; 477 ::ClientToScreen(viewWindow, &topLeft); 478 result.move(topLeft.x, topLeft.y); 479 480 return result; 481 } 482 483 IntPoint WebChromeClient::screenToWindow(const IntPoint& point) const 484 { 485 POINT result = point; 486 487 HWND viewWindow; 488 if (FAILED(m_webView->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow)))) 489 return point; 490 491 ::ScreenToClient(viewWindow, &result); 492 493 return result; 494 } 495 496 PlatformPageClient WebChromeClient::platformPageClient() const 497 { 498 HWND viewWindow; 499 if (FAILED(m_webView->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow)))) 500 return 0; 501 return viewWindow; 502 } 503 504 void WebChromeClient::contentsSizeChanged(Frame*, const IntSize&) const 505 { 506 notImplemented(); 507 } 508 509 void WebChromeClient::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags) 510 { 511 COMPtr<IWebUIDelegate> uiDelegate; 512 if (FAILED(m_webView->uiDelegate(&uiDelegate))) 513 return; 514 515 COMPtr<WebElementPropertyBag> element; 516 element.adoptRef(WebElementPropertyBag::createInstance(result)); 517 518 uiDelegate->mouseDidMoveOverElement(m_webView, element.get(), modifierFlags); 519 } 520 521 void WebChromeClient::setToolTip(const String& toolTip, TextDirection) 522 { 523 m_webView->setToolTip(toolTip); 524 } 525 526 void WebChromeClient::print(Frame* frame) 527 { 528 COMPtr<IWebUIDelegate> uiDelegate; 529 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) 530 uiDelegate->printFrame(m_webView, kit(frame)); 531 } 532 533 #if ENABLE(DATABASE) 534 void WebChromeClient::exceededDatabaseQuota(Frame* frame, const String& databaseIdentifier) 535 { 536 COMPtr<WebSecurityOrigin> origin(AdoptCOM, WebSecurityOrigin::createInstance(frame->document()->securityOrigin())); 537 COMPtr<IWebUIDelegate> uiDelegate; 538 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { 539 COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate(Query, uiDelegate); 540 if (uiDelegatePrivate) 541 uiDelegatePrivate->exceededDatabaseQuota(m_webView, kit(frame), origin.get(), BString(databaseIdentifier)); 542 else { 543 // FIXME: remove this workaround once shipping Safari has the necessary delegate implemented. 544 TCHAR path[MAX_PATH]; 545 HMODULE safariHandle = GetModuleHandle(TEXT("Safari.exe")); 546 if (!safariHandle) 547 return; 548 GetModuleFileName(safariHandle, path, ARRAYSIZE(path)); 549 DWORD handle; 550 DWORD versionSize = GetFileVersionInfoSize(path, &handle); 551 if (!versionSize) 552 return; 553 Vector<char> data(versionSize); 554 if (!GetFileVersionInfo(path, 0, versionSize, data.data())) 555 return; 556 557 LPCTSTR productVersion; 558 UINT productVersionLength; 559 if (!VerQueryValue(data.data(), TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), (void**)&productVersion, &productVersionLength)) 560 return; 561 if (_tcsncmp(TEXT("3.1"), productVersion, productVersionLength) > 0) { 562 const unsigned long long defaultQuota = 5 * 1024 * 1024; // 5 megabytes should hopefully be enough to test storage support. 563 origin->setQuota(defaultQuota); 564 } 565 } 566 } 567 } 568 #endif 569 570 #if ENABLE(OFFLINE_WEB_APPLICATIONS) 571 #include "ApplicationCacheStorage.h" 572 void WebChromeClient::reachedMaxAppCacheSize(int64_t spaceNeeded) 573 { 574 // FIXME: Free some space. 575 notImplemented(); 576 } 577 #endif 578 579 void WebChromeClient::populateVisitedLinks() 580 { 581 COMPtr<IWebHistoryDelegate> historyDelegate; 582 m_webView->historyDelegate(&historyDelegate); 583 if (historyDelegate) { 584 historyDelegate->populateVisitedLinksForWebView(m_webView); 585 return; 586 } 587 588 WebHistory* history = WebHistory::sharedHistory(); 589 if (!history) 590 return; 591 history->addVisitedLinksToPageGroup(m_webView->page()->group()); 592 } 593 594 bool WebChromeClient::paintCustomScrollbar(GraphicsContext* context, const FloatRect& rect, ScrollbarControlSize size, 595 ScrollbarControlState state, ScrollbarPart pressedPart, bool vertical, 596 float value, float proportion, ScrollbarControlPartMask parts) 597 { 598 if (context->paintingDisabled()) 599 return false; 600 601 COMPtr<IWebUIDelegate> delegate = uiDelegate(); 602 if (!delegate) 603 return false; 604 605 WebScrollbarControlPartMask webParts = WebNoScrollPart; 606 if (parts & BackButtonStartPart) // FIXME: Hyatt, what about BackButtonEndPart? 607 webParts |= WebBackButtonPart; 608 if (parts & BackTrackPart) 609 webParts |= WebBackTrackPart; 610 if (parts & ThumbPart) 611 webParts |= WebThumbPart; 612 if (parts & ForwardTrackPart) 613 webParts |= WebForwardTrackPart; 614 if (parts & ForwardButtonStartPart) // FIXME: Hyatt, what about ForwardButtonEndPart? 615 webParts |= WebForwardButtonPart; 616 617 WebScrollbarControlPart webPressedPart = WebNoScrollPart; 618 switch (pressedPart) { 619 case BackButtonStartPart: // FIXME: Hyatt, what about BackButtonEndPart? 620 webPressedPart = WebBackButtonPart; 621 break; 622 case BackTrackPart: 623 webPressedPart = WebBackTrackPart; 624 break; 625 case ThumbPart: 626 webPressedPart = WebThumbPart; 627 break; 628 case ForwardTrackPart: 629 webPressedPart = WebForwardTrackPart; 630 break; 631 case ForwardButtonStartPart: // FIXME: Hyatt, what about ForwardButtonEndPart? 632 webPressedPart = WebForwardButtonPart; 633 break; 634 default: 635 break; 636 } 637 638 WebScrollBarControlSize webSize; 639 switch (size) { 640 case SmallScrollbar: 641 webSize = WebSmallScrollbar; 642 break; 643 case RegularScrollbar: 644 default: 645 webSize = WebRegularScrollbar; 646 } 647 WebScrollbarControlState webState = 0; 648 if (state & ActiveScrollbarState) 649 webState |= WebActiveScrollbarState; 650 if (state & EnabledScrollbarState) 651 webState |= WebEnabledScrollbarState; 652 if (state & PressedScrollbarState) 653 webState |= WebPressedScrollbarState; 654 655 RECT webRect = enclosingIntRect(rect); 656 HDC hDC = context->getWindowsContext(webRect); 657 HRESULT hr = delegate->paintCustomScrollbar(m_webView, hDC, webRect, webSize, webState, webPressedPart, 658 vertical, value, proportion, webParts); 659 context->releaseWindowsContext(hDC, webRect); 660 return SUCCEEDED(hr); 661 } 662 663 bool WebChromeClient::paintCustomScrollCorner(GraphicsContext* context, const FloatRect& rect) 664 { 665 if (context->paintingDisabled()) 666 return false; 667 668 COMPtr<IWebUIDelegate> delegate = uiDelegate(); 669 if (!delegate) 670 return false; 671 672 RECT webRect = enclosingIntRect(rect); 673 HDC hDC = context->getWindowsContext(webRect); 674 HRESULT hr = delegate->paintCustomScrollCorner(m_webView, hDC, webRect); 675 context->releaseWindowsContext(hDC, webRect); 676 return SUCCEEDED(hr); 677 } 678 679 void WebChromeClient::runOpenPanel(Frame*, PassRefPtr<FileChooser> prpFileChooser) 680 { 681 RefPtr<FileChooser> fileChooser = prpFileChooser; 682 683 HWND viewWindow; 684 if (FAILED(m_webView->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow)))) 685 return; 686 687 bool multiFile = fileChooser->allowsMultipleFiles(); 688 Vector<TCHAR> fileBuf(multiFile ? maxFilePathsListSize : MAX_PATH); 689 690 OPENFILENAME ofn; 691 692 memset(&ofn, 0, sizeof(ofn)); 693 694 // Need to zero out the first char of fileBuf so GetOpenFileName doesn't think it's an initialization string 695 fileBuf[0] = '\0'; 696 697 ofn.lStructSize = sizeof(ofn); 698 ofn.hwndOwner = viewWindow; 699 String allFiles = allFilesText(); 700 allFiles.append(TEXT("\0*.*\0\0"), 6); 701 ofn.lpstrFilter = allFiles.charactersWithNullTermination(); 702 ofn.lpstrFile = fileBuf.data(); 703 ofn.nMaxFile = fileBuf.size(); 704 String dialogTitle = uploadFileText(); 705 ofn.lpstrTitle = dialogTitle.charactersWithNullTermination(); 706 ofn.Flags = OFN_ENABLESIZING | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_EXPLORER; 707 if (multiFile) 708 ofn.Flags = ofn.Flags | OFN_ALLOWMULTISELECT; 709 710 if (GetOpenFileName(&ofn)) { 711 TCHAR* files = fileBuf.data(); 712 Vector<String> fileList; 713 String file(files); 714 if (multiFile) { 715 while (!file.isEmpty()) { 716 // When using the OFN_EXPLORER flag, the file list is null delimited. 717 // When you create a String from a ptr to this list, it will use strlen to look for the null character. 718 // Then we find the next file path string by using the length of the string we just created. 719 TCHAR* nextFilePtr = files + file.length() + 1; 720 String nextFile(nextFilePtr); 721 // If multiple files are selected, there will be a directory name first, which we don't want to add to the vector. 722 // We know a single file was selected if there is only one filename in the list. 723 // In that case, we don't want to skip adding the first (and only) name. 724 if (files != fileBuf.data() || nextFile.isEmpty()) 725 fileList.append(file); 726 files = nextFilePtr; 727 file = nextFile; 728 } 729 } else 730 fileList.append(file); 731 ASSERT(fileList.size()); 732 fileChooser->chooseFiles(fileList); 733 } 734 // FIXME: Show some sort of error if too many files are selected and the buffer is too small. For now, this will fail silently. 735 } 736 737 bool WebChromeClient::setCursor(PlatformCursorHandle cursor) 738 { 739 if (!cursor) 740 return false; 741 742 if (COMPtr<IWebUIDelegate> delegate = uiDelegate()) { 743 COMPtr<IWebUIDelegatePrivate> delegatePrivate(Query, delegate); 744 if (delegatePrivate) { 745 if (SUCCEEDED(delegatePrivate->webViewSetCursor(m_webView, reinterpret_cast<OLE_HANDLE>(cursor)))) 746 return true; 747 } 748 } 749 750 ::SetCursor(cursor); 751 return true; 752 } 753 754 void WebChromeClient::requestGeolocationPermissionForFrame(Frame* frame, Geolocation* geolocation) 755 { 756 COMPtr<IWebUIDelegate> uiDelegate; 757 if (FAILED(m_webView->uiDelegate(&uiDelegate))) { 758 geolocation->setIsAllowed(false); 759 return; 760 } 761 762 COMPtr<IWebUIDelegatePrivate2> uiDelegatePrivate2(Query, uiDelegate); 763 if (!uiDelegatePrivate2) { 764 geolocation->setIsAllowed(false); 765 return; 766 } 767 768 COMPtr<WebSecurityOrigin> origin(AdoptCOM, WebSecurityOrigin::createInstance(frame->document()->securityOrigin())); 769 COMPtr<WebGeolocationPolicyListener> listener = WebGeolocationPolicyListener::createInstance(geolocation); 770 HRESULT hr = uiDelegatePrivate2->decidePolicyForGeolocationRequest(m_webView, kit(frame), origin.get(), listener.get()); 771 if (hr != E_NOTIMPL) 772 return; 773 774 geolocation->setIsAllowed(false); 775 } 776 777 #if USE(ACCELERATED_COMPOSITING) 778 void WebChromeClient::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* graphicsLayer) 779 { 780 m_webView->setRootChildLayer(graphicsLayer ? graphicsLayer->platformLayer() : 0); 781 } 782 783 void WebChromeClient::scheduleCompositingLayerSync() 784 { 785 m_webView->setRootLayerNeedsDisplay(); 786 } 787 788 #endif 789 790 COMPtr<IWebUIDelegate> WebChromeClient::uiDelegate() 791 { 792 COMPtr<IWebUIDelegate> delegate; 793 m_webView->uiDelegate(&delegate); 794 return delegate; 795 } 796 797 #if ENABLE(VIDEO) 798 799 bool WebChromeClient::supportsFullscreenForNode(const Node* node) 800 { 801 return node->hasTagName(HTMLNames::videoTag); 802 } 803 804 void WebChromeClient::enterFullscreenForNode(Node* node) 805 { 806 m_webView->enterFullscreenForNode(node); 807 } 808 809 void WebChromeClient::exitFullscreenForNode(Node*) 810 { 811 m_webView->exitFullscreen(); 812 } 813 814 #endif 815 816