Home | History | Annotate | Download | only in WebCoreSupport
      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