Home | History | Annotate | Download | only in web
      1 /*
      2  * Copyright (C) 2009 Google 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 are
      7  * met:
      8  *
      9  *     * Redistributions of source code must retain the above copyright
     10  * notice, this list of conditions and the following disclaimer.
     11  *     * Redistributions in binary form must reproduce the above
     12  * copyright notice, this list of conditions and the following disclaimer
     13  * in the documentation and/or other materials provided with the
     14  * distribution.
     15  *     * Neither the name of Google Inc. nor the names of its
     16  * contributors may be used to endorse or promote products derived from
     17  * this software without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include "config.h"
     33 #include "ChromeClientImpl.h"
     34 
     35 #include "ColorChooserPopupUIController.h"
     36 #include "ColorChooserUIController.h"
     37 #include "DateTimeChooserImpl.h"
     38 #include "ExternalDateTimeChooser.h"
     39 #include "ExternalPopupMenu.h"
     40 #include "HTMLNames.h"
     41 #include "PopupContainer.h"
     42 #include "PopupMenuChromium.h"
     43 #include "RuntimeEnabledFeatures.h"
     44 #include "WebAccessibilityObject.h"
     45 #include "WebAutofillClient.h"
     46 #include "WebColorChooser.h"
     47 #include "WebConsoleMessage.h"
     48 #include "WebCursorInfo.h"
     49 #include "WebFileChooserCompletionImpl.h"
     50 #include "WebFrameClient.h"
     51 #include "WebFrameImpl.h"
     52 #include "WebInputElement.h"
     53 #include "WebInputEvent.h"
     54 #include "WebKit.h"
     55 #include "WebNode.h"
     56 #include "WebPasswordGeneratorClient.h"
     57 #include "WebPlugin.h"
     58 #include "WebPluginContainerImpl.h"
     59 #include "WebPopupMenuImpl.h"
     60 #include "WebPopupMenuInfo.h"
     61 #include "WebPopupType.h"
     62 #include "WebSettings.h"
     63 #include "WebSettingsImpl.h"
     64 #include "WebTextDirection.h"
     65 #include "WebUserGestureIndicator.h"
     66 #include "WebUserGestureToken.h"
     67 #include "WebViewClient.h"
     68 #include "WebViewImpl.h"
     69 #include "WebWindowFeatures.h"
     70 #include "bindings/v8/ScriptController.h"
     71 #include "core/accessibility/AXObjectCache.h"
     72 #include "core/accessibility/AccessibilityObject.h"
     73 #include "core/dom/Document.h"
     74 #include "core/dom/Node.h"
     75 #include "core/html/HTMLInputElement.h"
     76 #include "core/loader/DocumentLoader.h"
     77 #include "core/loader/FrameLoadRequest.h"
     78 #include "core/loader/NavigationAction.h"
     79 #include "core/page/Console.h"
     80 #include "core/page/FrameView.h"
     81 #include "core/page/Page.h"
     82 #include "core/page/PagePopupDriver.h"
     83 #include "core/page/Settings.h"
     84 #include "core/page/WindowFeatures.h"
     85 #include "core/platform/ColorChooser.h"
     86 #include "core/platform/ColorChooserClient.h"
     87 #include "core/platform/Cursor.h"
     88 #include "core/platform/DateTimeChooser.h"
     89 #include "core/platform/FileChooser.h"
     90 #include "core/platform/PlatformScreen.h"
     91 #include "core/platform/chromium/support/WrappedResourceRequest.h"
     92 #include "core/platform/graphics/FloatRect.h"
     93 #include "core/platform/graphics/GraphicsLayer.h"
     94 #include "core/platform/graphics/IntRect.h"
     95 #include "core/rendering/HitTestResult.h"
     96 #include "core/rendering/RenderWidget.h"
     97 #include "modules/geolocation/Geolocation.h"
     98 #include "public/platform/Platform.h"
     99 #include "public/platform/WebRect.h"
    100 #include "public/platform/WebURLRequest.h"
    101 #include "weborigin/SecurityOrigin.h"
    102 #include "wtf/text/CString.h"
    103 #include "wtf/text/StringBuilder.h"
    104 #include "wtf/text/StringConcatenate.h"
    105 #include "wtf/unicode/CharacterNames.h"
    106 
    107 using namespace WebCore;
    108 
    109 namespace WebKit {
    110 
    111 // Converts a WebCore::PopupContainerType to a WebKit::WebPopupType.
    112 static WebPopupType convertPopupType(PopupContainer::PopupType type)
    113 {
    114     switch (type) {
    115     case PopupContainer::Select:
    116         return WebPopupTypeSelect;
    117     case PopupContainer::Suggestion:
    118         return WebPopupTypeSuggestion;
    119     default:
    120         ASSERT_NOT_REACHED();
    121         return WebPopupTypeNone;
    122     }
    123 }
    124 
    125 // Converts a WebCore::AXObjectCache::AXNotification to a WebKit::WebAccessibilityNotification
    126 static WebAccessibilityNotification toWebAccessibilityNotification(AXObjectCache::AXNotification notification)
    127 {
    128     // These enums have the same values; enforced in AssertMatchingEnums.cpp.
    129     return static_cast<WebAccessibilityNotification>(notification);
    130 }
    131 
    132 ChromeClientImpl::ChromeClientImpl(WebViewImpl* webView)
    133     : m_webView(webView)
    134     , m_toolbarsVisible(true)
    135     , m_statusbarVisible(true)
    136     , m_scrollbarsVisible(true)
    137     , m_menubarVisible(true)
    138     , m_resizable(true)
    139     , m_pagePopupDriver(webView)
    140 {
    141 }
    142 
    143 ChromeClientImpl::~ChromeClientImpl()
    144 {
    145 }
    146 
    147 void* ChromeClientImpl::webView() const
    148 {
    149     return static_cast<void*>(m_webView);
    150 }
    151 
    152 void ChromeClientImpl::chromeDestroyed()
    153 {
    154     // Our lifetime is bound to the WebViewImpl.
    155 }
    156 
    157 void ChromeClientImpl::setWindowRect(const FloatRect& r)
    158 {
    159     if (m_webView->client())
    160         m_webView->client()->setWindowRect(IntRect(r));
    161 }
    162 
    163 FloatRect ChromeClientImpl::windowRect()
    164 {
    165     WebRect rect;
    166     if (m_webView->client())
    167         rect = m_webView->client()->rootWindowRect();
    168     else {
    169         // These numbers will be fairly wrong. The window's x/y coordinates will
    170         // be the top left corner of the screen and the size will be the content
    171         // size instead of the window size.
    172         rect.width = m_webView->size().width;
    173         rect.height = m_webView->size().height;
    174     }
    175     return FloatRect(rect);
    176 }
    177 
    178 FloatRect ChromeClientImpl::pageRect()
    179 {
    180     // We hide the details of the window's border thickness from the web page by
    181     // simple re-using the window position here.  So, from the point-of-view of
    182     // the web page, the window has no border.
    183     return windowRect();
    184 }
    185 
    186 void ChromeClientImpl::focus()
    187 {
    188     if (m_webView->client())
    189         m_webView->client()->didFocus();
    190 }
    191 
    192 void ChromeClientImpl::unfocus()
    193 {
    194     if (m_webView->client())
    195         m_webView->client()->didBlur();
    196 }
    197 
    198 bool ChromeClientImpl::canTakeFocus(FocusDirection)
    199 {
    200     // For now the browser can always take focus if we're not running layout
    201     // tests.
    202     return !layoutTestMode();
    203 }
    204 
    205 void ChromeClientImpl::takeFocus(FocusDirection direction)
    206 {
    207     if (!m_webView->client())
    208         return;
    209     if (direction == FocusDirectionBackward)
    210         m_webView->client()->focusPrevious();
    211     else
    212         m_webView->client()->focusNext();
    213 }
    214 
    215 void ChromeClientImpl::focusedNodeChanged(Node* node)
    216 {
    217     m_webView->client()->focusedNodeChanged(WebNode(node));
    218 
    219     WebURL focusURL;
    220     if (node && node->isLink()) {
    221         // This HitTestResult hack is the easiest way to get a link URL out of a
    222         // WebCore::Node.
    223         HitTestResult hitTest(IntPoint(0, 0));
    224         // This cast must be valid because of the isLink() check.
    225         hitTest.setURLElement(toElement(node));
    226         if (hitTest.isLiveLink())
    227             focusURL = hitTest.absoluteLinkURL();
    228     }
    229     m_webView->client()->setKeyboardFocusURL(focusURL);
    230 }
    231 
    232 Page* ChromeClientImpl::createWindow(
    233     Frame* frame, const FrameLoadRequest& r, const WindowFeatures& features, const NavigationAction& action, NavigationPolicy navigationPolicy)
    234 {
    235     if (!m_webView->client())
    236         return 0;
    237 
    238     WebNavigationPolicy policy = static_cast<WebNavigationPolicy>(navigationPolicy);
    239     if (policy == WebNavigationPolicyIgnore)
    240         policy = getNavigationPolicy();
    241 
    242     WrappedResourceRequest request;
    243     if (!r.resourceRequest().isEmpty())
    244         request.bind(r.resourceRequest());
    245     else if (!action.resourceRequest().isEmpty())
    246         request.bind(action.resourceRequest());
    247     WebViewImpl* newView = static_cast<WebViewImpl*>(
    248         m_webView->client()->createView(WebFrameImpl::fromFrame(frame), request, features, r.frameName(), policy));
    249     if (!newView)
    250         return 0;
    251     return newView->page();
    252 }
    253 
    254 static inline void updatePolicyForEvent(const WebInputEvent* inputEvent, NavigationPolicy* policy)
    255 {
    256     if (!inputEvent || inputEvent->type != WebInputEvent::MouseUp)
    257         return;
    258 
    259     const WebMouseEvent* mouseEvent = static_cast<const WebMouseEvent*>(inputEvent);
    260 
    261     unsigned short buttonNumber;
    262     switch (mouseEvent->button) {
    263     case WebMouseEvent::ButtonLeft:
    264         buttonNumber = 0;
    265         break;
    266     case WebMouseEvent::ButtonMiddle:
    267         buttonNumber = 1;
    268         break;
    269     case WebMouseEvent::ButtonRight:
    270         buttonNumber = 2;
    271         break;
    272     default:
    273         return;
    274     }
    275     bool ctrl = mouseEvent->modifiers & WebMouseEvent::ControlKey;
    276     bool shift = mouseEvent->modifiers & WebMouseEvent::ShiftKey;
    277     bool alt = mouseEvent->modifiers & WebMouseEvent::AltKey;
    278     bool meta = mouseEvent->modifiers & WebMouseEvent::MetaKey;
    279 
    280     NavigationPolicy userPolicy = *policy;
    281     navigationPolicyFromMouseEvent(buttonNumber, ctrl, shift, alt, meta, &userPolicy);
    282     // User and app agree that we want a new window; let the app override the decorations.
    283     if (userPolicy == NavigationPolicyNewWindow && *policy == NavigationPolicyNewPopup)
    284         return;
    285     *policy = userPolicy;
    286 }
    287 
    288 WebNavigationPolicy ChromeClientImpl::getNavigationPolicy()
    289 {
    290     // If our default configuration was modified by a script or wasn't
    291     // created by a user gesture, then show as a popup. Else, let this
    292     // new window be opened as a toplevel window.
    293     bool asPopup = !m_toolbarsVisible
    294         || !m_statusbarVisible
    295         || !m_scrollbarsVisible
    296         || !m_menubarVisible
    297         || !m_resizable;
    298 
    299     NavigationPolicy policy = NavigationPolicyNewForegroundTab;
    300     if (asPopup)
    301         policy = NavigationPolicyNewPopup;
    302     updatePolicyForEvent(WebViewImpl::currentInputEvent(), &policy);
    303 
    304     return static_cast<WebNavigationPolicy>(policy);
    305 }
    306 
    307 void ChromeClientImpl::show(NavigationPolicy navigationPolicy)
    308 {
    309     if (!m_webView->client())
    310         return;
    311 
    312     WebNavigationPolicy policy = static_cast<WebNavigationPolicy>(navigationPolicy);
    313     if (policy == WebNavigationPolicyIgnore)
    314         policy = getNavigationPolicy();
    315     m_webView->client()->show(policy);
    316 }
    317 
    318 bool ChromeClientImpl::canRunModal()
    319 {
    320     return !!m_webView->client();
    321 }
    322 
    323 void ChromeClientImpl::runModal()
    324 {
    325     if (m_webView->client())
    326         m_webView->client()->runModal();
    327 }
    328 
    329 void ChromeClientImpl::setToolbarsVisible(bool value)
    330 {
    331     m_toolbarsVisible = value;
    332 }
    333 
    334 bool ChromeClientImpl::toolbarsVisible()
    335 {
    336     return m_toolbarsVisible;
    337 }
    338 
    339 void ChromeClientImpl::setStatusbarVisible(bool value)
    340 {
    341     m_statusbarVisible = value;
    342 }
    343 
    344 bool ChromeClientImpl::statusbarVisible()
    345 {
    346     return m_statusbarVisible;
    347 }
    348 
    349 void ChromeClientImpl::setScrollbarsVisible(bool value)
    350 {
    351     m_scrollbarsVisible = value;
    352     WebFrameImpl* webFrame = static_cast<WebFrameImpl*>(m_webView->mainFrame());
    353     if (webFrame)
    354         webFrame->setCanHaveScrollbars(value);
    355 }
    356 
    357 bool ChromeClientImpl::scrollbarsVisible()
    358 {
    359     return m_scrollbarsVisible;
    360 }
    361 
    362 void ChromeClientImpl::setMenubarVisible(bool value)
    363 {
    364     m_menubarVisible = value;
    365 }
    366 
    367 bool ChromeClientImpl::menubarVisible()
    368 {
    369     return m_menubarVisible;
    370 }
    371 
    372 void ChromeClientImpl::setResizable(bool value)
    373 {
    374     m_resizable = value;
    375 }
    376 
    377 void ChromeClientImpl::addMessageToConsole(MessageSource source,
    378                                            MessageLevel level,
    379                                            const String& message,
    380                                            unsigned lineNumber,
    381                                            const String& sourceID)
    382 {
    383     if (m_webView->client()) {
    384         m_webView->client()->didAddMessageToConsole(
    385             WebConsoleMessage(static_cast<WebConsoleMessage::Level>(level), message),
    386             sourceID,
    387             lineNumber);
    388     }
    389 }
    390 
    391 bool ChromeClientImpl::canRunBeforeUnloadConfirmPanel()
    392 {
    393     return !!m_webView->client();
    394 }
    395 
    396 bool ChromeClientImpl::runBeforeUnloadConfirmPanel(const String& message, Frame* frame)
    397 {
    398     if (m_webView->client()) {
    399         return m_webView->client()->runModalBeforeUnloadDialog(
    400             WebFrameImpl::fromFrame(frame), message);
    401     }
    402     return false;
    403 }
    404 
    405 void ChromeClientImpl::closeWindowSoon()
    406 {
    407     // Make sure this Page can no longer be found by JS.
    408     m_webView->page()->clearPageGroup();
    409 
    410     // Make sure that all loading is stopped.  Ensures that JS stops executing!
    411     m_webView->mainFrame()->stopLoading();
    412 
    413     if (m_webView->client())
    414         m_webView->client()->closeWidgetSoon();
    415 }
    416 
    417 // Although a Frame is passed in, we don't actually use it, since we
    418 // already know our own m_webView.
    419 void ChromeClientImpl::runJavaScriptAlert(Frame* frame, const String& message)
    420 {
    421     if (m_webView->client()) {
    422         if (WebUserGestureIndicator::isProcessingUserGesture())
    423             WebUserGestureIndicator::currentUserGestureToken().setJavascriptPrompt();
    424         m_webView->client()->runModalAlertDialog(
    425             WebFrameImpl::fromFrame(frame), message);
    426     }
    427 }
    428 
    429 // See comments for runJavaScriptAlert().
    430 bool ChromeClientImpl::runJavaScriptConfirm(Frame* frame, const String& message)
    431 {
    432     if (m_webView->client()) {
    433         if (WebUserGestureIndicator::isProcessingUserGesture())
    434             WebUserGestureIndicator::currentUserGestureToken().setJavascriptPrompt();
    435         return m_webView->client()->runModalConfirmDialog(
    436             WebFrameImpl::fromFrame(frame), message);
    437     }
    438     return false;
    439 }
    440 
    441 // See comments for runJavaScriptAlert().
    442 bool ChromeClientImpl::runJavaScriptPrompt(Frame* frame,
    443                                            const String& message,
    444                                            const String& defaultValue,
    445                                            String& result)
    446 {
    447     if (m_webView->client()) {
    448         if (WebUserGestureIndicator::isProcessingUserGesture())
    449             WebUserGestureIndicator::currentUserGestureToken().setJavascriptPrompt();
    450         WebString actualValue;
    451         bool ok = m_webView->client()->runModalPromptDialog(
    452             WebFrameImpl::fromFrame(frame),
    453             message,
    454             defaultValue,
    455             &actualValue);
    456         if (ok)
    457             result = actualValue;
    458         return ok;
    459     }
    460     return false;
    461 }
    462 
    463 void ChromeClientImpl::setStatusbarText(const String& message)
    464 {
    465     if (m_webView->client())
    466         m_webView->client()->setStatusText(message);
    467 }
    468 
    469 bool ChromeClientImpl::tabsToLinks()
    470 {
    471     return m_webView->tabsToLinks();
    472 }
    473 
    474 IntRect ChromeClientImpl::windowResizerRect() const
    475 {
    476     IntRect result;
    477     if (m_webView->client())
    478         result = m_webView->client()->windowResizerRect();
    479     return result;
    480 }
    481 
    482 void ChromeClientImpl::invalidateContentsAndRootView(const IntRect& updateRect)
    483 {
    484     if (updateRect.isEmpty())
    485         return;
    486     m_webView->invalidateRect(updateRect);
    487 }
    488 
    489 void ChromeClientImpl::invalidateContentsForSlowScroll(const IntRect& updateRect)
    490 {
    491     invalidateContentsAndRootView(updateRect);
    492 }
    493 
    494 void ChromeClientImpl::scheduleAnimation()
    495 {
    496     m_webView->scheduleAnimation();
    497 }
    498 
    499 void ChromeClientImpl::scroll(
    500     const IntSize& scrollDelta, const IntRect& scrollRect,
    501     const IntRect& clipRect)
    502 {
    503     if (!m_webView->isAcceleratedCompositingActive()) {
    504         if (m_webView->client()) {
    505             int dx = scrollDelta.width();
    506             int dy = scrollDelta.height();
    507             m_webView->client()->didScrollRect(dx, dy, intersection(scrollRect, clipRect));
    508         }
    509     } else
    510         m_webView->scrollRootLayerRect(scrollDelta, clipRect);
    511 }
    512 
    513 IntPoint ChromeClientImpl::screenToRootView(const IntPoint& point) const
    514 {
    515     IntPoint windowPoint(point);
    516 
    517     if (m_webView->client()) {
    518         WebRect windowRect = m_webView->client()->windowRect();
    519         windowPoint.move(-windowRect.x, -windowRect.y);
    520     }
    521 
    522     return windowPoint;
    523 }
    524 
    525 IntRect ChromeClientImpl::rootViewToScreen(const IntRect& rect) const
    526 {
    527     IntRect screenRect(rect);
    528 
    529     if (m_webView->client()) {
    530         WebRect windowRect = m_webView->client()->windowRect();
    531         screenRect.move(windowRect.x, windowRect.y);
    532     }
    533 
    534     return screenRect;
    535 }
    536 
    537 WebScreenInfo ChromeClientImpl::screenInfo() const
    538 {
    539     return m_webView->client() ? m_webView->client()->screenInfo() : WebScreenInfo();
    540 }
    541 
    542 void ChromeClientImpl::contentsSizeChanged(Frame* frame, const IntSize& size) const
    543 {
    544     m_webView->didChangeContentsSize();
    545 
    546     WebFrameImpl* webframe = WebFrameImpl::fromFrame(frame);
    547     webframe->didChangeContentsSize(size);
    548     if (webframe->client())
    549         webframe->client()->didChangeContentsSize(webframe, size);
    550 }
    551 
    552 void ChromeClientImpl::deviceOrPageScaleFactorChanged() const
    553 {
    554     m_webView->deviceOrPageScaleFactorChanged();
    555 }
    556 
    557 void ChromeClientImpl::didProgrammaticallyScroll(Frame* frame, const IntPoint& scrollPoint) const
    558 {
    559     ASSERT(frame->view()->inProgrammaticScroll());
    560     if (frame->page()->mainFrame() == frame)
    561         m_webView->didProgrammaticallyScroll(scrollPoint);
    562 }
    563 
    564 void ChromeClientImpl::layoutUpdated(Frame* frame) const
    565 {
    566     m_webView->layoutUpdated(WebFrameImpl::fromFrame(frame));
    567 }
    568 
    569 void ChromeClientImpl::mouseDidMoveOverElement(
    570     const HitTestResult& result, unsigned modifierFlags)
    571 {
    572     if (!m_webView->client())
    573         return;
    574 
    575     WebURL url;
    576     // Find out if the mouse is over a link, and if so, let our UI know...
    577     if (result.isLiveLink() && !result.absoluteLinkURL().string().isEmpty())
    578         url = result.absoluteLinkURL();
    579     else if (result.innerNonSharedNode()
    580              && (result.innerNonSharedNode()->hasTagName(HTMLNames::objectTag)
    581                  || result.innerNonSharedNode()->hasTagName(HTMLNames::embedTag))) {
    582         RenderObject* object = result.innerNonSharedNode()->renderer();
    583         if (object && object->isWidget()) {
    584             Widget* widget = toRenderWidget(object)->widget();
    585             if (widget && widget->isPluginContainer()) {
    586                 WebPluginContainerImpl* plugin = static_cast<WebPluginContainerImpl*>(widget);
    587                 url = plugin->plugin()->linkAtPosition(result.roundedPointInInnerNodeFrame());
    588             }
    589         }
    590     }
    591 
    592     m_webView->client()->setMouseOverURL(url);
    593 }
    594 
    595 void ChromeClientImpl::setToolTip(const String& tooltipText, TextDirection dir)
    596 {
    597     if (!m_webView->client())
    598         return;
    599     WebTextDirection textDirection = (dir == RTL) ?
    600         WebTextDirectionRightToLeft :
    601         WebTextDirectionLeftToRight;
    602     m_webView->client()->setToolTipText(
    603         tooltipText, textDirection);
    604 }
    605 
    606 void ChromeClientImpl::dispatchViewportPropertiesDidChange(const ViewportArguments& arguments) const
    607 {
    608     m_webView->updatePageDefinedPageScaleConstraints(arguments);
    609 }
    610 
    611 void ChromeClientImpl::print(Frame* frame)
    612 {
    613     if (m_webView->client())
    614         m_webView->client()->printPage(WebFrameImpl::fromFrame(frame));
    615 }
    616 
    617 PassOwnPtr<ColorChooser> ChromeClientImpl::createColorChooser(ColorChooserClient* chooserClient, const Color&)
    618 {
    619     OwnPtr<ColorChooserUIController> controller;
    620     if (RuntimeEnabledFeatures::pagePopupEnabled())
    621         controller = adoptPtr(new ColorChooserPopupUIController(this, chooserClient));
    622     else
    623         controller = adoptPtr(new ColorChooserUIController(this, chooserClient));
    624     controller->openUI();
    625     return controller.release();
    626 }
    627 PassOwnPtr<WebColorChooser> ChromeClientImpl::createWebColorChooser(WebColorChooserClient* chooserClient, const WebColor& initialColor)
    628 {
    629     WebViewClient* client = m_webView->client();
    630     if (!client)
    631         return nullptr;
    632     return adoptPtr(client->createColorChooser(chooserClient, initialColor));
    633 }
    634 
    635 PassRefPtr<DateTimeChooser> ChromeClientImpl::openDateTimeChooser(DateTimeChooserClient* pickerClient, const DateTimeChooserParameters& parameters)
    636 {
    637 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
    638     return DateTimeChooserImpl::create(this, pickerClient, parameters);
    639 #else
    640     return ExternalDateTimeChooser::create(this, m_webView->client(), pickerClient, parameters);
    641 #endif
    642 }
    643 
    644 void ChromeClientImpl::runOpenPanel(Frame* frame, PassRefPtr<FileChooser> fileChooser)
    645 {
    646     WebViewClient* client = m_webView->client();
    647     if (!client)
    648         return;
    649 
    650     WebFileChooserParams params;
    651     params.multiSelect = fileChooser->settings().allowsMultipleFiles;
    652     params.directory = fileChooser->settings().allowsDirectoryUpload;
    653     params.acceptTypes = fileChooser->settings().acceptTypes();
    654     params.selectedFiles = fileChooser->settings().selectedFiles;
    655     if (params.selectedFiles.size() > 0)
    656         params.initialValue = params.selectedFiles[0];
    657 #if ENABLE(MEDIA_CAPTURE)
    658     params.useMediaCapture = fileChooser->settings().useMediaCapture;
    659 #endif
    660     WebFileChooserCompletionImpl* chooserCompletion =
    661         new WebFileChooserCompletionImpl(fileChooser);
    662 
    663     if (client->runFileChooser(params, chooserCompletion))
    664         return;
    665 
    666     // Choosing failed, so do callback with an empty list.
    667     chooserCompletion->didChooseFile(WebVector<WebString>());
    668 }
    669 
    670 void ChromeClientImpl::enumerateChosenDirectory(FileChooser* fileChooser)
    671 {
    672     WebViewClient* client = m_webView->client();
    673     if (!client)
    674         return;
    675 
    676     WebFileChooserCompletionImpl* chooserCompletion =
    677         new WebFileChooserCompletionImpl(fileChooser);
    678 
    679     ASSERT(fileChooser && fileChooser->settings().selectedFiles.size());
    680 
    681     // If the enumeration can't happen, call the callback with an empty list.
    682     if (!client->enumerateChosenDirectory(fileChooser->settings().selectedFiles[0], chooserCompletion))
    683         chooserCompletion->didChooseFile(WebVector<WebString>());
    684 }
    685 
    686 void ChromeClientImpl::popupOpened(PopupContainer* popupContainer,
    687                                    const IntRect& bounds,
    688                                    bool handleExternally)
    689 {
    690     // For Autofill popups, if the popup will not be fully visible, we shouldn't
    691     // show it at all. Among other things, this prevents users from being able
    692     // to interact via the keyboard with an invisible popup.
    693     if (popupContainer->popupType() == PopupContainer::Suggestion) {
    694         FrameView* view = m_webView->page()->mainFrame()->view();
    695         IntRect visibleRect = view->visibleContentRect(ScrollableArea::IncludeScrollbars);
    696         // |bounds| is in screen coordinates, so make sure to convert it to
    697         // content coordinates prior to comparing to |visibleRect|.
    698         IntRect screenRect = bounds;
    699         screenRect.setLocation(view->screenToContents(bounds.location()));
    700         if (!visibleRect.contains(screenRect)) {
    701             m_webView->hideAutofillPopup();
    702             return;
    703         }
    704     }
    705 
    706     if (!m_webView->client())
    707         return;
    708 
    709     WebWidget* webwidget;
    710     if (handleExternally) {
    711         WebPopupMenuInfo popupInfo;
    712         getPopupMenuInfo(popupContainer, &popupInfo);
    713         webwidget = m_webView->client()->createPopupMenu(popupInfo);
    714     } else {
    715         webwidget = m_webView->client()->createPopupMenu(
    716             convertPopupType(popupContainer->popupType()));
    717         // We only notify when the WebView has to handle the popup, as when
    718         // the popup is handled externally, the fact that a popup is showing is
    719         // transparent to the WebView.
    720         m_webView->popupOpened(popupContainer);
    721     }
    722     static_cast<WebPopupMenuImpl*>(webwidget)->initialize(popupContainer, bounds);
    723 }
    724 
    725 void ChromeClientImpl::popupClosed(WebCore::PopupContainer* popupContainer)
    726 {
    727     m_webView->popupClosed(popupContainer);
    728 }
    729 
    730 void ChromeClientImpl::setCursor(const WebCore::Cursor& cursor)
    731 {
    732     setCursor(WebCursorInfo(cursor));
    733 }
    734 
    735 void ChromeClientImpl::setCursor(const WebCursorInfo& cursor)
    736 {
    737 #if OS(DARWIN)
    738     // On Mac the mousemove event propagates to both the popup and main window.
    739     // If a popup is open we don't want the main window to change the cursor.
    740     if (m_webView->hasOpenedPopup())
    741         return;
    742 #endif
    743     if (m_webView->client())
    744         m_webView->client()->didChangeCursor(cursor);
    745 }
    746 
    747 void ChromeClientImpl::setCursorForPlugin(const WebCursorInfo& cursor)
    748 {
    749     setCursor(cursor);
    750 }
    751 
    752 void ChromeClientImpl::formStateDidChange(const Node* node)
    753 {
    754     if (m_webView->client())
    755         m_webView->client()->didChangeFormState(WebNode(const_cast<Node*>(node)));
    756 
    757     // The current history item is not updated yet.  That happens lazily when
    758     // WebFrame::currentHistoryItem is requested.
    759     WebFrameImpl* webframe = WebFrameImpl::fromFrame(node->document()->frame());
    760     if (webframe->client())
    761         webframe->client()->didUpdateCurrentHistoryItem(webframe);
    762 }
    763 
    764 void ChromeClientImpl::getPopupMenuInfo(PopupContainer* popupContainer,
    765                                         WebPopupMenuInfo* info)
    766 {
    767     const Vector<PopupItem*>& inputItems = popupContainer->popupData();
    768 
    769     WebVector<WebMenuItemInfo> outputItems(inputItems.size());
    770 
    771     for (size_t i = 0; i < inputItems.size(); ++i) {
    772         const PopupItem& inputItem = *inputItems[i];
    773         WebMenuItemInfo& outputItem = outputItems[i];
    774 
    775         outputItem.label = inputItem.label;
    776         outputItem.enabled = inputItem.enabled;
    777         if (inputItem.textDirection == WebCore::RTL)
    778             outputItem.textDirection = WebTextDirectionRightToLeft;
    779         else
    780             outputItem.textDirection = WebTextDirectionLeftToRight;
    781         outputItem.hasTextDirectionOverride = inputItem.hasTextDirectionOverride;
    782 
    783         switch (inputItem.type) {
    784         case PopupItem::TypeOption:
    785             outputItem.type = WebMenuItemInfo::Option;
    786             break;
    787         case PopupItem::TypeGroup:
    788             outputItem.type = WebMenuItemInfo::Group;
    789             break;
    790         case PopupItem::TypeSeparator:
    791             outputItem.type = WebMenuItemInfo::Separator;
    792             break;
    793         default:
    794             ASSERT_NOT_REACHED();
    795         }
    796     }
    797 
    798     info->itemHeight = popupContainer->menuItemHeight();
    799     info->itemFontSize = popupContainer->menuItemFontSize();
    800     info->selectedIndex = popupContainer->selectedIndex();
    801     info->items.swap(outputItems);
    802     info->rightAligned = popupContainer->menuStyle().textDirection() == RTL;
    803 }
    804 
    805 void ChromeClientImpl::postAccessibilityNotification(AccessibilityObject* obj, AXObjectCache::AXNotification notification)
    806 {
    807     // Alert assistive technology about the accessibility object notification.
    808     if (obj)
    809         m_webView->client()->postAccessibilityNotification(WebAccessibilityObject(obj), toWebAccessibilityNotification(notification));
    810 }
    811 
    812 String ChromeClientImpl::acceptLanguages()
    813 {
    814     return m_webView->client()->acceptLanguages();
    815 }
    816 
    817 bool ChromeClientImpl::paintCustomOverhangArea(GraphicsContext* context, const IntRect& horizontalOverhangArea, const IntRect& verticalOverhangArea, const IntRect& dirtyRect)
    818 {
    819     Frame* frame = m_webView->mainFrameImpl()->frame();
    820     WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame);
    821     if (pluginContainer)
    822         return pluginContainer->paintCustomOverhangArea(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect);
    823     return false;
    824 }
    825 
    826 GraphicsLayerFactory* ChromeClientImpl::graphicsLayerFactory() const
    827 {
    828     return m_webView->graphicsLayerFactory();
    829 }
    830 
    831 void ChromeClientImpl::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* graphicsLayer)
    832 {
    833     m_webView->setRootGraphicsLayer(graphicsLayer);
    834 }
    835 
    836 void ChromeClientImpl::scheduleCompositingLayerFlush()
    837 {
    838     m_webView->scheduleCompositingLayerSync();
    839 }
    840 
    841 ChromeClient::CompositingTriggerFlags ChromeClientImpl::allowedCompositingTriggers() const
    842 {
    843     if (!m_webView->allowsAcceleratedCompositing())
    844         return 0;
    845 
    846     CompositingTriggerFlags flags = 0;
    847     Settings* settings = m_webView->page()->settings();
    848     if (settings->acceleratedCompositingFor3DTransformsEnabled())
    849         flags |= ThreeDTransformTrigger;
    850     if (settings->acceleratedCompositingForVideoEnabled())
    851         flags |= VideoTrigger;
    852     if (settings->acceleratedCompositingForPluginsEnabled())
    853         flags |= PluginTrigger;
    854     if (settings->acceleratedCompositingForAnimationEnabled())
    855         flags |= AnimationTrigger;
    856     if (settings->acceleratedCompositingForCanvasEnabled())
    857         flags |= CanvasTrigger;
    858     if (settings->acceleratedCompositingForScrollableFramesEnabled())
    859         flags |= ScrollableInnerFrameTrigger;
    860     if (settings->acceleratedCompositingForFiltersEnabled())
    861         flags |= FilterTrigger;
    862 
    863     return flags;
    864 }
    865 
    866 void ChromeClientImpl::enterFullScreenForElement(Element* element)
    867 {
    868     m_webView->enterFullScreenForElement(element);
    869 }
    870 
    871 void ChromeClientImpl::exitFullScreenForElement(Element* element)
    872 {
    873     m_webView->exitFullScreenForElement(element);
    874 }
    875 
    876 bool ChromeClientImpl::hasOpenedPopup() const
    877 {
    878     return m_webView->hasOpenedPopup();
    879 }
    880 
    881 PassRefPtr<PopupMenu> ChromeClientImpl::createPopupMenu(Frame& frame, PopupMenuClient* client) const
    882 {
    883     if (WebViewImpl::useExternalPopupMenus())
    884         return adoptRef(new ExternalPopupMenu(frame, client, m_webView->client()));
    885 
    886     return adoptRef(new PopupMenuChromium(frame, client));
    887 }
    888 
    889 PagePopup* ChromeClientImpl::openPagePopup(PagePopupClient* client, const IntRect& originBoundsInRootView)
    890 {
    891     ASSERT(m_pagePopupDriver);
    892     return m_pagePopupDriver->openPagePopup(client, originBoundsInRootView);
    893 }
    894 
    895 void ChromeClientImpl::closePagePopup(PagePopup* popup)
    896 {
    897     ASSERT(m_pagePopupDriver);
    898     m_pagePopupDriver->closePagePopup(popup);
    899 }
    900 
    901 void ChromeClientImpl::setPagePopupDriver(PagePopupDriver* driver)
    902 {
    903     ASSERT(driver);
    904     m_pagePopupDriver = driver;
    905 }
    906 
    907 void ChromeClientImpl::resetPagePopupDriver()
    908 {
    909     m_pagePopupDriver = m_webView;
    910 }
    911 
    912 bool ChromeClientImpl::isPasswordGenerationEnabled() const
    913 {
    914     return m_webView->passwordGeneratorClient();
    915 }
    916 
    917 void ChromeClientImpl::openPasswordGenerator(HTMLInputElement* input)
    918 {
    919     ASSERT(isPasswordGenerationEnabled());
    920     WebInputElement webInput(input);
    921     m_webView->passwordGeneratorClient()->openPasswordGenerator(webInput);
    922 }
    923 
    924 bool ChromeClientImpl::shouldRunModalDialogDuringPageDismissal(const DialogType& dialogType, const String& dialogMessage, FrameLoader::PageDismissalType dismissalType) const
    925 {
    926     const char* kDialogs[] = {"alert", "confirm", "prompt", "showModalDialog"};
    927     int dialog = static_cast<int>(dialogType);
    928     ASSERT_WITH_SECURITY_IMPLICATION(0 <= dialog && dialog < static_cast<int>(arraysize(kDialogs)));
    929 
    930     const char* kDismissals[] = {"beforeunload", "pagehide", "unload"};
    931     int dismissal = static_cast<int>(dismissalType) - 1; // Exclude NoDismissal.
    932     ASSERT_WITH_SECURITY_IMPLICATION(0 <= dismissal && dismissal < static_cast<int>(arraysize(kDismissals)));
    933 
    934     WebKit::Platform::current()->histogramEnumeration("Renderer.ModalDialogsDuringPageDismissal", dismissal * arraysize(kDialogs) + dialog, arraysize(kDialogs) * arraysize(kDismissals));
    935 
    936     String message = String("Blocked ") + kDialogs[dialog] + "('" + dialogMessage + "') during " + kDismissals[dismissal] + ".";
    937     m_webView->mainFrame()->addMessageToConsole(WebConsoleMessage(WebConsoleMessage::LevelError, message));
    938 
    939     return false;
    940 }
    941 
    942 bool ChromeClientImpl::shouldRubberBandInDirection(WebCore::ScrollDirection direction) const
    943 {
    944     ASSERT(direction != WebCore::ScrollUp && direction != WebCore::ScrollDown);
    945 
    946     if (!m_webView->client())
    947         return false;
    948 
    949     if (direction == WebCore::ScrollLeft)
    950         return !m_webView->client()->historyBackListCount();
    951     if (direction == WebCore::ScrollRight)
    952         return !m_webView->client()->historyForwardListCount();
    953 
    954     ASSERT_NOT_REACHED();
    955     return true;
    956 }
    957 
    958 void ChromeClientImpl::numWheelEventHandlersChanged(unsigned numberOfWheelHandlers)
    959 {
    960     m_webView->numberOfWheelEventHandlersChanged(numberOfWheelHandlers);
    961 }
    962 
    963 void ChromeClientImpl::needTouchEvents(bool needsTouchEvents)
    964 {
    965     m_webView->hasTouchEventHandlers(needsTouchEvents);
    966 }
    967 
    968 bool ChromeClientImpl::requestPointerLock()
    969 {
    970     return m_webView->requestPointerLock();
    971 }
    972 
    973 void ChromeClientImpl::requestPointerUnlock()
    974 {
    975     return m_webView->requestPointerUnlock();
    976 }
    977 
    978 bool ChromeClientImpl::isPointerLocked()
    979 {
    980     return m_webView->isPointerLocked();
    981 }
    982 
    983 void ChromeClientImpl::annotatedRegionsChanged()
    984 {
    985     WebViewClient* client = m_webView->client();
    986     if (client)
    987         client->draggableRegionsChanged();
    988 }
    989 
    990 void ChromeClientImpl::didAssociateFormControls(const Vector<RefPtr<Element> >& elements)
    991 {
    992     if (!m_webView->autofillClient())
    993         return;
    994     WebVector<WebNode> elementVector(static_cast<size_t>(elements.size()));
    995     size_t elementsCount = elements.size();
    996     for (size_t i = 0; i < elementsCount; ++i)
    997         elementVector[i] = elements[i];
    998     m_webView->autofillClient()->didAssociateFormControls(elementVector);
    999 }
   1000 
   1001 #if ENABLE(NAVIGATOR_CONTENT_UTILS)
   1002 PassOwnPtr<NavigatorContentUtilsClientImpl> NavigatorContentUtilsClientImpl::create(WebViewImpl* webView)
   1003 {
   1004     return adoptPtr(new NavigatorContentUtilsClientImpl(webView));
   1005 }
   1006 
   1007 NavigatorContentUtilsClientImpl::NavigatorContentUtilsClientImpl(WebViewImpl* webView)
   1008     : m_webView(webView)
   1009 {
   1010 }
   1011 
   1012 void NavigatorContentUtilsClientImpl::registerProtocolHandler(const String& scheme, const String& baseURL, const String& url, const String& title)
   1013 {
   1014     m_webView->client()->registerProtocolHandler(scheme, baseURL, url, title);
   1015 }
   1016 #endif
   1017 
   1018 } // namespace WebKit
   1019