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 "WebAXObject.h"
     45 #include "WebAutofillClient.h"
     46 #include "WebColorChooser.h"
     47 #include "WebColorSuggestion.h"
     48 #include "WebConsoleMessage.h"
     49 #include "WebFileChooserCompletionImpl.h"
     50 #include "WebFrameClient.h"
     51 #include "WebFrameImpl.h"
     52 #include "WebInputElement.h"
     53 #include "WebInputEvent.h"
     54 #include "WebInputEventConversion.h"
     55 #include "WebKit.h"
     56 #include "WebNode.h"
     57 #include "WebPasswordGeneratorClient.h"
     58 #include "WebPlugin.h"
     59 #include "WebPluginContainerImpl.h"
     60 #include "WebPopupMenuImpl.h"
     61 #include "WebPopupMenuInfo.h"
     62 #include "WebPopupType.h"
     63 #include "WebSettings.h"
     64 #include "WebSettingsImpl.h"
     65 #include "WebTextDirection.h"
     66 #include "WebUserGestureIndicator.h"
     67 #include "WebUserGestureToken.h"
     68 #include "WebViewClient.h"
     69 #include "WebViewImpl.h"
     70 #include "WebWindowFeatures.h"
     71 #include "bindings/v8/ScriptController.h"
     72 #include "core/accessibility/AXObject.h"
     73 #include "core/accessibility/AXObjectCache.h"
     74 #include "core/dom/Document.h"
     75 #include "core/dom/DocumentFullscreen.h"
     76 #include "core/dom/Node.h"
     77 #include "core/html/HTMLInputElement.h"
     78 #include "core/loader/DocumentLoader.h"
     79 #include "core/loader/FrameLoadRequest.h"
     80 #include "core/frame/Console.h"
     81 #include "core/frame/FrameView.h"
     82 #include "core/page/Page.h"
     83 #include "core/page/PagePopupDriver.h"
     84 #include "core/frame/Settings.h"
     85 #include "core/page/WindowFeatures.h"
     86 #include "core/rendering/HitTestResult.h"
     87 #include "core/rendering/RenderWidget.h"
     88 #include "modules/geolocation/Geolocation.h"
     89 #include "platform/ColorChooser.h"
     90 #include "platform/ColorChooserClient.h"
     91 #include "platform/Cursor.h"
     92 #include "platform/DateTimeChooser.h"
     93 #include "platform/FileChooser.h"
     94 #include "platform/PlatformScreen.h"
     95 #include "platform/exported/WrappedResourceRequest.h"
     96 #include "platform/geometry/FloatRect.h"
     97 #include "platform/geometry/IntRect.h"
     98 #include "platform/graphics/GraphicsLayer.h"
     99 #include "platform/weborigin/SecurityOrigin.h"
    100 #include "public/platform/Platform.h"
    101 #include "public/platform/WebCursorInfo.h"
    102 #include "public/platform/WebRect.h"
    103 #include "public/platform/WebURLRequest.h"
    104 #include "public/web/WebTouchAction.h"
    105 #include "wtf/text/CString.h"
    106 #include "wtf/text/StringBuilder.h"
    107 #include "wtf/text/StringConcatenate.h"
    108 #include "wtf/unicode/CharacterNames.h"
    109 
    110 using namespace WebCore;
    111 
    112 namespace blink {
    113 
    114 // Converts a WebCore::PopupContainerType to a blink::WebPopupType.
    115 static WebPopupType convertPopupType(PopupContainer::PopupType type)
    116 {
    117     switch (type) {
    118     case PopupContainer::Select:
    119         return WebPopupTypeSelect;
    120     case PopupContainer::Suggestion:
    121         return WebPopupTypeSuggestion;
    122     default:
    123         ASSERT_NOT_REACHED();
    124         return WebPopupTypeNone;
    125     }
    126 }
    127 
    128 // Converts a WebCore::AXObjectCache::AXNotification to a blink::WebAXEvent
    129 static WebAXEvent toWebAXEvent(AXObjectCache::AXNotification notification)
    130 {
    131     // These enums have the same values; enforced in AssertMatchingEnums.cpp.
    132     return static_cast<WebAXEvent>(notification);
    133 }
    134 
    135 ChromeClientImpl::ChromeClientImpl(WebViewImpl* webView)
    136     : m_webView(webView)
    137     , m_toolbarsVisible(true)
    138     , m_statusbarVisible(true)
    139     , m_scrollbarsVisible(true)
    140     , m_menubarVisible(true)
    141     , m_resizable(true)
    142     , m_pagePopupDriver(webView)
    143 {
    144 }
    145 
    146 ChromeClientImpl::~ChromeClientImpl()
    147 {
    148 }
    149 
    150 void* ChromeClientImpl::webView() const
    151 {
    152     return static_cast<void*>(m_webView);
    153 }
    154 
    155 void ChromeClientImpl::chromeDestroyed()
    156 {
    157     // Our lifetime is bound to the WebViewImpl.
    158 }
    159 
    160 void ChromeClientImpl::setWindowRect(const FloatRect& r)
    161 {
    162     if (m_webView->client())
    163         m_webView->client()->setWindowRect(IntRect(r));
    164 }
    165 
    166 FloatRect ChromeClientImpl::windowRect()
    167 {
    168     WebRect rect;
    169     if (m_webView->client())
    170         rect = m_webView->client()->rootWindowRect();
    171     else {
    172         // These numbers will be fairly wrong. The window's x/y coordinates will
    173         // be the top left corner of the screen and the size will be the content
    174         // size instead of the window size.
    175         rect.width = m_webView->size().width;
    176         rect.height = m_webView->size().height;
    177     }
    178     return FloatRect(rect);
    179 }
    180 
    181 FloatRect ChromeClientImpl::pageRect()
    182 {
    183     // We hide the details of the window's border thickness from the web page by
    184     // simple re-using the window position here.  So, from the point-of-view of
    185     // the web page, the window has no border.
    186     return windowRect();
    187 }
    188 
    189 void ChromeClientImpl::focus()
    190 {
    191     if (m_webView->client())
    192         m_webView->client()->didFocus();
    193 }
    194 
    195 void ChromeClientImpl::unfocus()
    196 {
    197     if (m_webView->client())
    198         m_webView->client()->didBlur();
    199 }
    200 
    201 bool ChromeClientImpl::canTakeFocus(FocusDirection)
    202 {
    203     // For now the browser can always take focus if we're not running layout
    204     // tests.
    205     return !layoutTestMode();
    206 }
    207 
    208 void ChromeClientImpl::takeFocus(FocusDirection direction)
    209 {
    210     if (!m_webView->client())
    211         return;
    212     if (direction == FocusDirectionBackward)
    213         m_webView->client()->focusPrevious();
    214     else
    215         m_webView->client()->focusNext();
    216 }
    217 
    218 void ChromeClientImpl::focusedNodeChanged(Node* node)
    219 {
    220     m_webView->client()->focusedNodeChanged(WebNode(node));
    221 
    222     WebURL focusURL;
    223     if (node && node->isLink()) {
    224         // This HitTestResult hack is the easiest way to get a link URL out of a
    225         // WebCore::Node.
    226         HitTestResult hitTest(IntPoint(0, 0));
    227         // This cast must be valid because of the isLink() check.
    228         hitTest.setURLElement(toElement(node));
    229         if (hitTest.isLiveLink())
    230             focusURL = hitTest.absoluteLinkURL();
    231     }
    232     m_webView->client()->setKeyboardFocusURL(focusURL);
    233 }
    234 
    235 Page* ChromeClientImpl::createWindow(Frame* frame, const FrameLoadRequest& r, const WindowFeatures& features,
    236     NavigationPolicy navigationPolicy, ShouldSendReferrer shouldSendReferrer)
    237 {
    238     if (!m_webView->client())
    239         return 0;
    240 
    241     WebNavigationPolicy policy = static_cast<WebNavigationPolicy>(navigationPolicy);
    242     if (policy == WebNavigationPolicyIgnore)
    243         policy = getNavigationPolicy();
    244 
    245     DocumentFullscreen::webkitCancelFullScreen(frame->document());
    246 
    247     WebViewImpl* newView = toWebViewImpl(
    248         m_webView->client()->createView(WebFrameImpl::fromFrame(frame), WrappedResourceRequest(r.resourceRequest()), features, r.frameName(), policy, shouldSendReferrer == NeverSendReferrer));
    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 = toWebFrameImpl(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 bool ChromeClientImpl::shouldReportDetailedMessageForSource(const String& url)
    378 {
    379     return m_webView->client() && m_webView->client()->shouldReportDetailedMessageForSource(url);
    380 }
    381 
    382 void ChromeClientImpl::addMessageToConsole(MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceID, const String& stackTrace)
    383 {
    384     if (m_webView->client()) {
    385         m_webView->client()->didAddMessageToConsole(
    386             WebConsoleMessage(static_cast<WebConsoleMessage::Level>(level), message),
    387             sourceID,
    388             lineNumber,
    389             stackTrace);
    390     }
    391 }
    392 
    393 bool ChromeClientImpl::canRunBeforeUnloadConfirmPanel()
    394 {
    395     return !!m_webView->client();
    396 }
    397 
    398 bool ChromeClientImpl::runBeforeUnloadConfirmPanel(const String& message, Frame* frame)
    399 {
    400     if (m_webView->client()) {
    401         return m_webView->client()->runModalBeforeUnloadDialog(
    402             WebFrameImpl::fromFrame(frame), message);
    403     }
    404     return false;
    405 }
    406 
    407 void ChromeClientImpl::closeWindowSoon()
    408 {
    409     // Make sure this Page can no longer be found by JS.
    410     m_webView->page()->clearPageGroup();
    411 
    412     // Make sure that all loading is stopped.  Ensures that JS stops executing!
    413     m_webView->mainFrame()->stopLoading();
    414 
    415     if (m_webView->client())
    416         m_webView->client()->closeWidgetSoon();
    417 }
    418 
    419 // Although a Frame is passed in, we don't actually use it, since we
    420 // already know our own m_webView.
    421 void ChromeClientImpl::runJavaScriptAlert(Frame* frame, const String& message)
    422 {
    423     if (m_webView->client()) {
    424         if (WebUserGestureIndicator::isProcessingUserGesture())
    425             WebUserGestureIndicator::currentUserGestureToken().setJavascriptPrompt();
    426         m_webView->client()->runModalAlertDialog(
    427             WebFrameImpl::fromFrame(frame), message);
    428     }
    429 }
    430 
    431 // See comments for runJavaScriptAlert().
    432 bool ChromeClientImpl::runJavaScriptConfirm(Frame* frame, const String& message)
    433 {
    434     if (m_webView->client()) {
    435         if (WebUserGestureIndicator::isProcessingUserGesture())
    436             WebUserGestureIndicator::currentUserGestureToken().setJavascriptPrompt();
    437         return m_webView->client()->runModalConfirmDialog(
    438             WebFrameImpl::fromFrame(frame), message);
    439     }
    440     return false;
    441 }
    442 
    443 // See comments for runJavaScriptAlert().
    444 bool ChromeClientImpl::runJavaScriptPrompt(Frame* frame,
    445                                            const String& message,
    446                                            const String& defaultValue,
    447                                            String& result)
    448 {
    449     if (m_webView->client()) {
    450         if (WebUserGestureIndicator::isProcessingUserGesture())
    451             WebUserGestureIndicator::currentUserGestureToken().setJavascriptPrompt();
    452         WebString actualValue;
    453         bool ok = m_webView->client()->runModalPromptDialog(
    454             WebFrameImpl::fromFrame(frame),
    455             message,
    456             defaultValue,
    457             &actualValue);
    458         if (ok)
    459             result = actualValue;
    460         return ok;
    461     }
    462     return false;
    463 }
    464 
    465 void ChromeClientImpl::setStatusbarText(const String& message)
    466 {
    467     if (m_webView->client())
    468         m_webView->client()->setStatusText(message);
    469 }
    470 
    471 bool ChromeClientImpl::tabsToLinks()
    472 {
    473     return m_webView->tabsToLinks();
    474 }
    475 
    476 IntRect ChromeClientImpl::windowResizerRect() const
    477 {
    478     IntRect result;
    479     if (m_webView->client())
    480         result = m_webView->client()->windowResizerRect();
    481     return result;
    482 }
    483 
    484 void ChromeClientImpl::invalidateContentsAndRootView(const IntRect& updateRect)
    485 {
    486     if (updateRect.isEmpty())
    487         return;
    488     m_webView->invalidateRect(updateRect);
    489 }
    490 
    491 void ChromeClientImpl::invalidateContentsForSlowScroll(const IntRect& updateRect)
    492 {
    493     invalidateContentsAndRootView(updateRect);
    494 }
    495 
    496 void ChromeClientImpl::scheduleAnimation()
    497 {
    498     m_webView->scheduleAnimation();
    499 }
    500 
    501 bool ChromeClientImpl::isCompositorFramePending() const
    502 {
    503     return m_webView->client()->isCompositorFramePending();
    504 }
    505 
    506 void ChromeClientImpl::scroll(
    507     const IntSize& scrollDelta, const IntRect& scrollRect,
    508     const IntRect& clipRect)
    509 {
    510     if (!m_webView->isAcceleratedCompositingActive()) {
    511         if (m_webView->client()) {
    512             int dx = scrollDelta.width();
    513             int dy = scrollDelta.height();
    514             m_webView->client()->didScrollRect(dx, dy, intersection(scrollRect, clipRect));
    515         }
    516     } else
    517         m_webView->scrollRootLayerRect(scrollDelta, clipRect);
    518 }
    519 
    520 IntPoint ChromeClientImpl::screenToRootView(const IntPoint& point) const
    521 {
    522     IntPoint windowPoint(point);
    523 
    524     if (m_webView->client()) {
    525         WebRect windowRect = m_webView->client()->windowRect();
    526         windowPoint.move(-windowRect.x, -windowRect.y);
    527     }
    528 
    529     return windowPoint;
    530 }
    531 
    532 IntRect ChromeClientImpl::rootViewToScreen(const IntRect& rect) const
    533 {
    534     IntRect screenRect(rect);
    535 
    536     if (m_webView->client()) {
    537         WebRect windowRect = m_webView->client()->windowRect();
    538         screenRect.move(windowRect.x, windowRect.y);
    539     }
    540 
    541     return screenRect;
    542 }
    543 
    544 WebScreenInfo ChromeClientImpl::screenInfo() const
    545 {
    546     return m_webView->client() ? m_webView->client()->screenInfo() : WebScreenInfo();
    547 }
    548 
    549 void ChromeClientImpl::contentsSizeChanged(Frame* frame, const IntSize& size) const
    550 {
    551     m_webView->didChangeContentsSize();
    552 
    553     WebFrameImpl* webframe = WebFrameImpl::fromFrame(frame);
    554     webframe->didChangeContentsSize(size);
    555     if (webframe->client())
    556         webframe->client()->didChangeContentsSize(webframe, size);
    557 }
    558 
    559 void ChromeClientImpl::deviceOrPageScaleFactorChanged() const
    560 {
    561     m_webView->deviceOrPageScaleFactorChanged();
    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 = toPluginContainerImpl(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 ViewportDescription& description) const
    607 {
    608     m_webView->updatePageDefinedViewportConstraints(description);
    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 
    628 PassRefPtr<DateTimeChooser> ChromeClientImpl::openDateTimeChooser(DateTimeChooserClient* pickerClient, const DateTimeChooserParameters& parameters)
    629 {
    630 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
    631     return DateTimeChooserImpl::create(this, pickerClient, parameters);
    632 #else
    633     return ExternalDateTimeChooser::create(this, m_webView->client(), pickerClient, parameters);
    634 #endif
    635 }
    636 
    637 void ChromeClientImpl::runOpenPanel(Frame* frame, PassRefPtr<FileChooser> fileChooser)
    638 {
    639     WebViewClient* client = m_webView->client();
    640     if (!client)
    641         return;
    642 
    643     WebFileChooserParams params;
    644     params.multiSelect = fileChooser->settings().allowsMultipleFiles;
    645     params.directory = fileChooser->settings().allowsDirectoryUpload;
    646     params.acceptTypes = fileChooser->settings().acceptTypes();
    647     params.selectedFiles = fileChooser->settings().selectedFiles;
    648     if (params.selectedFiles.size() > 0)
    649         params.initialValue = params.selectedFiles[0];
    650 #if ENABLE(MEDIA_CAPTURE)
    651     params.useMediaCapture = fileChooser->settings().useMediaCapture;
    652 #endif
    653     WebFileChooserCompletionImpl* chooserCompletion =
    654         new WebFileChooserCompletionImpl(fileChooser);
    655 
    656     if (client->runFileChooser(params, chooserCompletion))
    657         return;
    658 
    659     // Choosing failed, so do callback with an empty list.
    660     chooserCompletion->didChooseFile(WebVector<WebString>());
    661 }
    662 
    663 void ChromeClientImpl::enumerateChosenDirectory(FileChooser* fileChooser)
    664 {
    665     WebViewClient* client = m_webView->client();
    666     if (!client)
    667         return;
    668 
    669     WebFileChooserCompletionImpl* chooserCompletion =
    670         new WebFileChooserCompletionImpl(fileChooser);
    671 
    672     ASSERT(fileChooser && fileChooser->settings().selectedFiles.size());
    673 
    674     // If the enumeration can't happen, call the callback with an empty list.
    675     if (!client->enumerateChosenDirectory(fileChooser->settings().selectedFiles[0], chooserCompletion))
    676         chooserCompletion->didChooseFile(WebVector<WebString>());
    677 }
    678 
    679 void ChromeClientImpl::popupOpened(PopupContainer* popupContainer,
    680                                    const IntRect& bounds,
    681                                    bool handleExternally)
    682 {
    683     // For Autofill popups, if the popup will not be fully visible, we shouldn't
    684     // show it at all. Among other things, this prevents users from being able
    685     // to interact via the keyboard with an invisible popup.
    686     if (popupContainer->popupType() == PopupContainer::Suggestion) {
    687         FrameView* view = m_webView->page()->mainFrame()->view();
    688         IntRect visibleRect = view->visibleContentRect(ScrollableArea::IncludeScrollbars);
    689         // |bounds| is in screen coordinates, so make sure to convert it to
    690         // content coordinates prior to comparing to |visibleRect|.
    691         IntRect screenRect = bounds;
    692         screenRect.setLocation(view->screenToContents(bounds.location()));
    693         if (!visibleRect.contains(screenRect)) {
    694             m_webView->hideAutofillPopup();
    695             return;
    696         }
    697     }
    698 
    699     if (!m_webView->client())
    700         return;
    701 
    702     WebWidget* webwidget;
    703     if (handleExternally) {
    704         WebPopupMenuInfo popupInfo;
    705         getPopupMenuInfo(popupContainer, &popupInfo);
    706         webwidget = m_webView->client()->createPopupMenu(popupInfo);
    707     } else {
    708         webwidget = m_webView->client()->createPopupMenu(
    709             convertPopupType(popupContainer->popupType()));
    710         // We only notify when the WebView has to handle the popup, as when
    711         // the popup is handled externally, the fact that a popup is showing is
    712         // transparent to the WebView.
    713         m_webView->popupOpened(popupContainer);
    714     }
    715     toWebPopupMenuImpl(webwidget)->initialize(popupContainer, bounds);
    716 }
    717 
    718 void ChromeClientImpl::popupClosed(WebCore::PopupContainer* popupContainer)
    719 {
    720     m_webView->popupClosed(popupContainer);
    721 }
    722 
    723 void ChromeClientImpl::setCursor(const WebCore::Cursor& cursor)
    724 {
    725     setCursor(WebCursorInfo(cursor));
    726 }
    727 
    728 void ChromeClientImpl::setCursor(const WebCursorInfo& cursor)
    729 {
    730 #if OS(MACOSX)
    731     // On Mac the mousemove event propagates to both the popup and main window.
    732     // If a popup is open we don't want the main window to change the cursor.
    733     if (m_webView->hasOpenedPopup())
    734         return;
    735 #endif
    736     if (m_webView->client())
    737         m_webView->client()->didChangeCursor(cursor);
    738 }
    739 
    740 void ChromeClientImpl::setCursorForPlugin(const WebCursorInfo& cursor)
    741 {
    742     setCursor(cursor);
    743 }
    744 
    745 void ChromeClientImpl::formStateDidChange(const Node* node)
    746 {
    747     // The current history item is not updated yet.  That happens lazily when
    748     // WebFrame::currentHistoryItem is requested.
    749     WebFrameImpl* webframe = WebFrameImpl::fromFrame(node->document().frame());
    750     if (webframe->client())
    751         webframe->client()->didUpdateCurrentHistoryItem(webframe);
    752 }
    753 
    754 void ChromeClientImpl::getPopupMenuInfo(PopupContainer* popupContainer,
    755                                         WebPopupMenuInfo* info)
    756 {
    757     const Vector<PopupItem*>& inputItems = popupContainer->popupData();
    758 
    759     WebVector<WebMenuItemInfo> outputItems(inputItems.size());
    760 
    761     for (size_t i = 0; i < inputItems.size(); ++i) {
    762         const PopupItem& inputItem = *inputItems[i];
    763         WebMenuItemInfo& outputItem = outputItems[i];
    764 
    765         outputItem.label = inputItem.label;
    766         outputItem.enabled = inputItem.enabled;
    767         if (inputItem.textDirection == WebCore::RTL)
    768             outputItem.textDirection = WebTextDirectionRightToLeft;
    769         else
    770             outputItem.textDirection = WebTextDirectionLeftToRight;
    771         outputItem.hasTextDirectionOverride = inputItem.hasTextDirectionOverride;
    772 
    773         switch (inputItem.type) {
    774         case PopupItem::TypeOption:
    775             outputItem.type = WebMenuItemInfo::Option;
    776             break;
    777         case PopupItem::TypeGroup:
    778             outputItem.type = WebMenuItemInfo::Group;
    779             break;
    780         case PopupItem::TypeSeparator:
    781             outputItem.type = WebMenuItemInfo::Separator;
    782             break;
    783         default:
    784             ASSERT_NOT_REACHED();
    785         }
    786     }
    787 
    788     info->itemHeight = popupContainer->menuItemHeight();
    789     info->itemFontSize = popupContainer->menuItemFontSize();
    790     info->selectedIndex = popupContainer->selectedIndex();
    791     info->items.swap(outputItems);
    792     info->rightAligned = popupContainer->menuStyle().textDirection() == RTL;
    793 }
    794 
    795 void ChromeClientImpl::postAccessibilityNotification(AXObject* obj, AXObjectCache::AXNotification notification)
    796 {
    797     // Alert assistive technology about the accessibility object notification.
    798     if (!obj)
    799         return;
    800 
    801     m_webView->client()->postAccessibilityEvent(WebAXObject(obj), toWebAXEvent(notification));
    802 }
    803 
    804 String ChromeClientImpl::acceptLanguages()
    805 {
    806     return m_webView->client()->acceptLanguages();
    807 }
    808 
    809 bool ChromeClientImpl::paintCustomOverhangArea(GraphicsContext* context, const IntRect& horizontalOverhangArea, const IntRect& verticalOverhangArea, const IntRect& dirtyRect)
    810 {
    811     Frame* frame = m_webView->mainFrameImpl()->frame();
    812     WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame);
    813     if (pluginContainer)
    814         return pluginContainer->paintCustomOverhangArea(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect);
    815     return false;
    816 }
    817 
    818 GraphicsLayerFactory* ChromeClientImpl::graphicsLayerFactory() const
    819 {
    820     return m_webView->graphicsLayerFactory();
    821 }
    822 
    823 void ChromeClientImpl::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* graphicsLayer)
    824 {
    825     m_webView->setRootGraphicsLayer(graphicsLayer);
    826 }
    827 
    828 void ChromeClientImpl::scheduleCompositingLayerFlush()
    829 {
    830     m_webView->scheduleCompositingLayerSync();
    831 }
    832 
    833 ChromeClient::CompositingTriggerFlags ChromeClientImpl::allowedCompositingTriggers() const
    834 {
    835     if (!m_webView->allowsAcceleratedCompositing())
    836         return 0;
    837 
    838     CompositingTriggerFlags flags = 0;
    839     Settings& settings = m_webView->page()->settings();
    840     if (settings.acceleratedCompositingFor3DTransformsEnabled())
    841         flags |= ThreeDTransformTrigger;
    842     if (settings.acceleratedCompositingForVideoEnabled())
    843         flags |= VideoTrigger;
    844     if (settings.acceleratedCompositingForPluginsEnabled())
    845         flags |= PluginTrigger;
    846     if (settings.acceleratedCompositingForAnimationEnabled())
    847         flags |= AnimationTrigger;
    848     if (settings.acceleratedCompositingForCanvasEnabled())
    849         flags |= CanvasTrigger;
    850     if (settings.acceleratedCompositingForScrollableFramesEnabled())
    851         flags |= ScrollableInnerFrameTrigger;
    852     if (settings.acceleratedCompositingForFiltersEnabled())
    853         flags |= FilterTrigger;
    854 
    855     return flags;
    856 }
    857 
    858 void ChromeClientImpl::enterFullScreenForElement(Element* element)
    859 {
    860     m_webView->enterFullScreenForElement(element);
    861 }
    862 
    863 void ChromeClientImpl::exitFullScreenForElement(Element* element)
    864 {
    865     m_webView->exitFullScreenForElement(element);
    866 }
    867 
    868 bool ChromeClientImpl::hasOpenedPopup() const
    869 {
    870     return m_webView->hasOpenedPopup();
    871 }
    872 
    873 PassRefPtr<PopupMenu> ChromeClientImpl::createPopupMenu(Frame& frame, PopupMenuClient* client) const
    874 {
    875     if (WebViewImpl::useExternalPopupMenus())
    876         return adoptRef(new ExternalPopupMenu(frame, client, m_webView->client()));
    877 
    878     return adoptRef(new PopupMenuChromium(frame, client));
    879 }
    880 
    881 PagePopup* ChromeClientImpl::openPagePopup(PagePopupClient* client, const IntRect& originBoundsInRootView)
    882 {
    883     ASSERT(m_pagePopupDriver);
    884     return m_pagePopupDriver->openPagePopup(client, originBoundsInRootView);
    885 }
    886 
    887 void ChromeClientImpl::closePagePopup(PagePopup* popup)
    888 {
    889     ASSERT(m_pagePopupDriver);
    890     m_pagePopupDriver->closePagePopup(popup);
    891 }
    892 
    893 void ChromeClientImpl::setPagePopupDriver(PagePopupDriver* driver)
    894 {
    895     ASSERT(driver);
    896     m_pagePopupDriver = driver;
    897 }
    898 
    899 void ChromeClientImpl::resetPagePopupDriver()
    900 {
    901     m_pagePopupDriver = m_webView;
    902 }
    903 
    904 bool ChromeClientImpl::isPasswordGenerationEnabled() const
    905 {
    906     return m_webView->passwordGeneratorClient();
    907 }
    908 
    909 void ChromeClientImpl::openPasswordGenerator(HTMLInputElement* input)
    910 {
    911     ASSERT(isPasswordGenerationEnabled());
    912     WebInputElement webInput(input);
    913     m_webView->passwordGeneratorClient()->openPasswordGenerator(webInput);
    914 }
    915 
    916 bool ChromeClientImpl::shouldRunModalDialogDuringPageDismissal(const DialogType& dialogType, const String& dialogMessage, Document::PageDismissalType dismissalType) const
    917 {
    918     const char* kDialogs[] = {"alert", "confirm", "prompt", "showModalDialog"};
    919     int dialog = static_cast<int>(dialogType);
    920     ASSERT_WITH_SECURITY_IMPLICATION(0 <= dialog && dialog < static_cast<int>(arraysize(kDialogs)));
    921 
    922     const char* kDismissals[] = {"beforeunload", "pagehide", "unload"};
    923     int dismissal = static_cast<int>(dismissalType) - 1; // Exclude NoDismissal.
    924     ASSERT_WITH_SECURITY_IMPLICATION(0 <= dismissal && dismissal < static_cast<int>(arraysize(kDismissals)));
    925 
    926     blink::Platform::current()->histogramEnumeration("Renderer.ModalDialogsDuringPageDismissal", dismissal * arraysize(kDialogs) + dialog, arraysize(kDialogs) * arraysize(kDismissals));
    927 
    928     String message = String("Blocked ") + kDialogs[dialog] + "('" + dialogMessage + "') during " + kDismissals[dismissal] + ".";
    929     m_webView->mainFrame()->addMessageToConsole(WebConsoleMessage(WebConsoleMessage::LevelError, message));
    930 
    931     return false;
    932 }
    933 
    934 bool ChromeClientImpl::shouldRubberBandInDirection(WebCore::ScrollDirection direction) const
    935 {
    936     ASSERT(direction != WebCore::ScrollUp && direction != WebCore::ScrollDown);
    937 
    938     if (!m_webView->client())
    939         return false;
    940 
    941     if (direction == WebCore::ScrollLeft)
    942         return !m_webView->client()->historyBackListCount();
    943     if (direction == WebCore::ScrollRight)
    944         return !m_webView->client()->historyForwardListCount();
    945 
    946     ASSERT_NOT_REACHED();
    947     return true;
    948 }
    949 
    950 void ChromeClientImpl::numWheelEventHandlersChanged(unsigned numberOfWheelHandlers)
    951 {
    952     m_webView->numberOfWheelEventHandlersChanged(numberOfWheelHandlers);
    953 }
    954 
    955 void ChromeClientImpl::needTouchEvents(bool needsTouchEvents)
    956 {
    957     m_webView->hasTouchEventHandlers(needsTouchEvents);
    958 }
    959 
    960 void ChromeClientImpl::setTouchAction(TouchAction touchAction)
    961 {
    962     if (WebViewClient* client = m_webView->client()) {
    963         WebTouchAction webTouchAction = static_cast<WebTouchAction>(touchAction);
    964         client->setTouchAction(webTouchAction);
    965     }
    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 void ChromeClientImpl::didCancelCompositionOnSelectionChange()
   1002 {
   1003     if (m_webView->client())
   1004         m_webView->client()->didCancelCompositionOnSelectionChange();
   1005 }
   1006 
   1007 void ChromeClientImpl::willSetInputMethodState()
   1008 {
   1009     if (m_webView->client())
   1010         m_webView->client()->resetInputMethod();
   1011 }
   1012 
   1013 void ChromeClientImpl::handleKeyboardEventOnTextField(HTMLInputElement& inputElement, KeyboardEvent& event)
   1014 {
   1015     if (!m_webView->autofillClient())
   1016         return;
   1017     m_webView->autofillClient()->textFieldDidReceiveKeyDown(WebInputElement(&inputElement), WebKeyboardEventBuilder(event));
   1018 }
   1019 
   1020 void ChromeClientImpl::didChangeValueInTextField(HTMLInputElement& inputElement)
   1021 {
   1022     if (!m_webView->autofillClient())
   1023         return;
   1024     m_webView->autofillClient()->textFieldDidChange(WebInputElement(&inputElement));
   1025 }
   1026 
   1027 void ChromeClientImpl::didEndEditingOnTextField(HTMLInputElement& inputElement)
   1028 {
   1029     if (m_webView->autofillClient())
   1030         m_webView->autofillClient()->textFieldDidEndEditing(WebInputElement(&inputElement));
   1031 
   1032     // Notification that focus was lost. Be careful with this, it's also sent
   1033     // when the page is being closed.
   1034 
   1035     // Hide any showing popup.
   1036     m_webView->hideAutofillPopup();
   1037 }
   1038 
   1039 void ChromeClientImpl::openTextDataListChooser(HTMLInputElement& input)
   1040 {
   1041     if (m_webView->autofillClient())
   1042         m_webView->autofillClient()->openTextDataListChooser(WebInputElement(&input));
   1043 }
   1044 
   1045 #if ENABLE(NAVIGATOR_CONTENT_UTILS)
   1046 PassOwnPtr<NavigatorContentUtilsClientImpl> NavigatorContentUtilsClientImpl::create(WebViewImpl* webView)
   1047 {
   1048     return adoptPtr(new NavigatorContentUtilsClientImpl(webView));
   1049 }
   1050 
   1051 NavigatorContentUtilsClientImpl::NavigatorContentUtilsClientImpl(WebViewImpl* webView)
   1052     : m_webView(webView)
   1053 {
   1054 }
   1055 
   1056 void NavigatorContentUtilsClientImpl::registerProtocolHandler(const String& scheme, const String& baseURL, const String& url, const String& title)
   1057 {
   1058     m_webView->client()->registerProtocolHandler(scheme, baseURL, url, title);
   1059 }
   1060 #endif
   1061 
   1062 } // namespace blink
   1063