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 "AXObjectCache.h"
36#include "AccessibilityObject.h"
37#include "Console.h"
38#include "Cursor.h"
39#include "DatabaseTracker.h"
40#include "Document.h"
41#include "DocumentLoader.h"
42#include "ExternalPopupMenu.h"
43#include "FileChooser.h"
44#include "FloatRect.h"
45#include "FrameLoadRequest.h"
46#include "FrameView.h"
47#include "Geolocation.h"
48#include "GeolocationService.h"
49#include "GraphicsLayer.h"
50#include "HTMLNames.h"
51#include "HitTestResult.h"
52#include "IntRect.h"
53#include "NavigationAction.h"
54#include "Node.h"
55#include "NotificationPresenterImpl.h"
56#include "Page.h"
57#include "PlatformBridge.h"
58#include "PopupMenuChromium.h"
59#include "RenderWidget.h"
60#include "ScriptController.h"
61#include "SearchPopupMenuChromium.h"
62#include "SecurityOrigin.h"
63#include "Settings.h"
64#if USE(V8)
65#include "V8Proxy.h"
66#endif
67#include "WebAccessibilityObject.h"
68#include "WebConsoleMessage.h"
69#include "WebCursorInfo.h"
70#include "WebFileChooserCompletionImpl.h"
71#include "WebFrameClient.h"
72#include "WebFrameImpl.h"
73#include "WebIconLoadingCompletionImpl.h"
74#include "WebInputEvent.h"
75#include "WebKit.h"
76#include "WebNode.h"
77#include "WebPlugin.h"
78#include "WebPluginContainerImpl.h"
79#include "WebPopupMenuImpl.h"
80#include "WebPopupMenuInfo.h"
81#include "WebPopupType.h"
82#include "WebRect.h"
83#include "WebSettings.h"
84#include "WebTextDirection.h"
85#include "WebURLRequest.h"
86#include "WebViewClient.h"
87#include "WebViewImpl.h"
88#include "WebWindowFeatures.h"
89#include "WindowFeatures.h"
90#include "WrappedResourceRequest.h"
91#include <wtf/unicode/CharacterNames.h>
92
93using namespace WebCore;
94
95namespace WebKit {
96
97// Converts a WebCore::PopupContainerType to a WebKit::WebPopupType.
98static WebPopupType convertPopupType(PopupContainer::PopupType type)
99{
100    switch (type) {
101    case PopupContainer::Select:
102        return WebPopupTypeSelect;
103    case PopupContainer::Suggestion:
104        return WebPopupTypeSuggestion;
105    default:
106        ASSERT_NOT_REACHED();
107        return WebPopupTypeNone;
108    }
109}
110
111// Converts a WebCore::AXObjectCache::AXNotification to a WebKit::WebAccessibilityNotification
112static WebAccessibilityNotification toWebAccessibilityNotification(AXObjectCache::AXNotification notification)
113{
114    switch (notification) {
115    case AXObjectCache::AXActiveDescendantChanged:
116        return WebAccessibilityNotificationActiveDescendantChanged;
117    case AXObjectCache::AXCheckedStateChanged:
118        return WebAccessibilityNotificationCheckedStateChanged;
119    case AXObjectCache::AXChildrenChanged:
120        return WebAccessibilityNotificationChildrenChanged;
121    case AXObjectCache::AXFocusedUIElementChanged:
122        return WebAccessibilityNotificationFocusedUIElementChanged;
123    case AXObjectCache::AXLayoutComplete:
124        return WebAccessibilityNotificationLayoutComplete;
125    case AXObjectCache::AXLoadComplete:
126        return WebAccessibilityNotificationLoadComplete;
127    case AXObjectCache::AXSelectedChildrenChanged:
128        return WebAccessibilityNotificationSelectedChildrenChanged;
129    case AXObjectCache::AXSelectedTextChanged:
130        return WebAccessibilityNotificationSelectedTextChanged;
131    case AXObjectCache::AXValueChanged:
132        return WebAccessibilityNotificationValueChanged;
133    case AXObjectCache::AXScrolledToAnchor:
134        return WebAccessibilityNotificationScrolledToAnchor;
135    case AXObjectCache::AXLiveRegionChanged:
136        return WebAccessibilityNotificationLiveRegionChanged;
137    case AXObjectCache::AXMenuListValueChanged:
138        return WebAccessibilityNotificationMenuListValueChanged;
139    case AXObjectCache::AXRowCountChanged:
140        return WebAccessibilityNotificationRowCountChanged;
141    case AXObjectCache::AXRowCollapsed:
142        return WebAccessibilityNotificationRowCollapsed;
143    case AXObjectCache::AXRowExpanded:
144        return WebAccessibilityNotificationRowExpanded;
145    default:
146        ASSERT_NOT_REACHED();
147        return WebAccessibilityNotificationInvalid;
148    }
149}
150
151ChromeClientImpl::ChromeClientImpl(WebViewImpl* webView)
152    : m_webView(webView)
153    , m_toolbarsVisible(true)
154    , m_statusbarVisible(true)
155    , m_scrollbarsVisible(true)
156    , m_menubarVisible(true)
157    , m_resizable(true)
158{
159}
160
161ChromeClientImpl::~ChromeClientImpl()
162{
163}
164
165void* ChromeClientImpl::webView() const
166{
167    return static_cast<void*>(m_webView);
168}
169
170void ChromeClientImpl::chromeDestroyed()
171{
172    // Our lifetime is bound to the WebViewImpl.
173}
174
175void ChromeClientImpl::setWindowRect(const FloatRect& r)
176{
177    if (m_webView->client())
178        m_webView->client()->setWindowRect(IntRect(r));
179}
180
181FloatRect ChromeClientImpl::windowRect()
182{
183    WebRect rect;
184    if (m_webView->client())
185        rect = m_webView->client()->rootWindowRect();
186    else {
187        // These numbers will be fairly wrong. The window's x/y coordinates will
188        // be the top left corner of the screen and the size will be the content
189        // size instead of the window size.
190        rect.width = m_webView->size().width;
191        rect.height = m_webView->size().height;
192    }
193    return FloatRect(rect);
194}
195
196FloatRect ChromeClientImpl::pageRect()
197{
198    // We hide the details of the window's border thickness from the web page by
199    // simple re-using the window position here.  So, from the point-of-view of
200    // the web page, the window has no border.
201    return windowRect();
202}
203
204float ChromeClientImpl::scaleFactor()
205{
206    // This is supposed to return the scale factor of the web page. It looks like
207    // the implementor of the graphics layer is responsible for doing most of the
208    // operations associated with scaling. However, this value is used ins some
209    // cases by WebCore. For example, this is used as a scaling factor in canvas
210    // so that things drawn in it are scaled just like the web page is.
211    //
212    // We don't currently implement scaling, so just return 1.0 (no scaling).
213    return 1.0;
214}
215
216void ChromeClientImpl::focus()
217{
218    if (m_webView->client())
219        m_webView->client()->didFocus();
220}
221
222void ChromeClientImpl::unfocus()
223{
224    if (m_webView->client())
225        m_webView->client()->didBlur();
226}
227
228bool ChromeClientImpl::canTakeFocus(FocusDirection)
229{
230    // For now the browser can always take focus if we're not running layout
231    // tests.
232    return !layoutTestMode();
233}
234
235void ChromeClientImpl::takeFocus(FocusDirection direction)
236{
237    if (!m_webView->client())
238        return;
239    if (direction == FocusDirectionBackward)
240        m_webView->client()->focusPrevious();
241    else
242        m_webView->client()->focusNext();
243}
244
245void ChromeClientImpl::focusedNodeChanged(Node* node)
246{
247    m_webView->client()->focusedNodeChanged(WebNode(node));
248
249    WebURL focusURL;
250    if (node && node->isLink()) {
251        // This HitTestResult hack is the easiest way to get a link URL out of a
252        // WebCore::Node.
253        HitTestResult hitTest(IntPoint(0, 0));
254        // This cast must be valid because of the isLink() check.
255        hitTest.setURLElement(static_cast<Element*>(node));
256        if (hitTest.isLiveLink())
257            focusURL = hitTest.absoluteLinkURL();
258    }
259    m_webView->client()->setKeyboardFocusURL(focusURL);
260}
261
262void ChromeClientImpl::focusedFrameChanged(Frame*)
263{
264}
265
266Page* ChromeClientImpl::createWindow(
267    Frame* frame, const FrameLoadRequest& r, const WindowFeatures& features, const NavigationAction&)
268{
269    if (!m_webView->client())
270        return 0;
271
272    WrappedResourceRequest request;
273    if (!r.resourceRequest().isEmpty())
274        request.bind(r.resourceRequest());
275    WebViewImpl* newView = static_cast<WebViewImpl*>(
276        m_webView->client()->createView(WebFrameImpl::fromFrame(frame), request, features, r.frameName()));
277    if (!newView)
278        return 0;
279
280    return newView->page();
281}
282
283static inline bool currentEventShouldCauseBackgroundTab(const WebInputEvent* inputEvent)
284{
285    if (!inputEvent)
286        return false;
287
288    if (inputEvent->type != WebInputEvent::MouseUp)
289        return false;
290
291    const WebMouseEvent* mouseEvent = static_cast<const WebMouseEvent*>(inputEvent);
292
293    WebNavigationPolicy policy;
294    unsigned short buttonNumber;
295    switch (mouseEvent->button) {
296    case WebMouseEvent::ButtonLeft:
297        buttonNumber = 0;
298        break;
299    case WebMouseEvent::ButtonMiddle:
300        buttonNumber = 1;
301        break;
302    case WebMouseEvent::ButtonRight:
303        buttonNumber = 2;
304        break;
305    default:
306        return false;
307    }
308    bool ctrl = mouseEvent->modifiers & WebMouseEvent::ControlKey;
309    bool shift = mouseEvent->modifiers & WebMouseEvent::ShiftKey;
310    bool alt = mouseEvent->modifiers & WebMouseEvent::AltKey;
311    bool meta = mouseEvent->modifiers & WebMouseEvent::MetaKey;
312
313    if (!WebViewImpl::navigationPolicyFromMouseEvent(buttonNumber, ctrl, shift, alt, meta, &policy))
314        return false;
315
316    return policy == WebNavigationPolicyNewBackgroundTab;
317}
318
319void ChromeClientImpl::show()
320{
321    if (!m_webView->client())
322        return;
323
324    // If our default configuration was modified by a script or wasn't
325    // created by a user gesture, then show as a popup. Else, let this
326    // new window be opened as a toplevel window.
327    bool asPopup = !m_toolbarsVisible
328        || !m_statusbarVisible
329        || !m_scrollbarsVisible
330        || !m_menubarVisible
331        || !m_resizable;
332
333    WebNavigationPolicy policy = WebNavigationPolicyNewForegroundTab;
334    if (asPopup)
335        policy = WebNavigationPolicyNewPopup;
336    if (currentEventShouldCauseBackgroundTab(WebViewImpl::currentInputEvent()))
337        policy = WebNavigationPolicyNewBackgroundTab;
338
339    m_webView->client()->show(policy);
340}
341
342bool ChromeClientImpl::canRunModal()
343{
344    return !!m_webView->client();
345}
346
347void ChromeClientImpl::runModal()
348{
349    if (m_webView->client())
350        m_webView->client()->runModal();
351}
352
353void ChromeClientImpl::setToolbarsVisible(bool value)
354{
355    m_toolbarsVisible = value;
356}
357
358bool ChromeClientImpl::toolbarsVisible()
359{
360    return m_toolbarsVisible;
361}
362
363void ChromeClientImpl::setStatusbarVisible(bool value)
364{
365    m_statusbarVisible = value;
366}
367
368bool ChromeClientImpl::statusbarVisible()
369{
370    return m_statusbarVisible;
371}
372
373void ChromeClientImpl::setScrollbarsVisible(bool value)
374{
375    m_scrollbarsVisible = value;
376    WebFrameImpl* webFrame = static_cast<WebFrameImpl*>(m_webView->mainFrame());
377    if (webFrame)
378        webFrame->setCanHaveScrollbars(value);
379}
380
381bool ChromeClientImpl::scrollbarsVisible()
382{
383    return m_scrollbarsVisible;
384}
385
386void ChromeClientImpl::setMenubarVisible(bool value)
387{
388    m_menubarVisible = value;
389}
390
391bool ChromeClientImpl::menubarVisible()
392{
393    return m_menubarVisible;
394}
395
396void ChromeClientImpl::setResizable(bool value)
397{
398    m_resizable = value;
399}
400
401void ChromeClientImpl::addMessageToConsole(MessageSource source,
402                                           MessageType type,
403                                           MessageLevel level,
404                                           const String& message,
405                                           unsigned lineNumber,
406                                           const String& sourceID)
407{
408    if (m_webView->client()) {
409        m_webView->client()->didAddMessageToConsole(
410            WebConsoleMessage(static_cast<WebConsoleMessage::Level>(level), message),
411            sourceID,
412            lineNumber);
413    }
414}
415
416bool ChromeClientImpl::canRunBeforeUnloadConfirmPanel()
417{
418    return !!m_webView->client();
419}
420
421bool ChromeClientImpl::runBeforeUnloadConfirmPanel(const String& message, Frame* frame)
422{
423    if (m_webView->client()) {
424        return m_webView->client()->runModalBeforeUnloadDialog(
425            WebFrameImpl::fromFrame(frame), message);
426    }
427    return false;
428}
429
430void ChromeClientImpl::closeWindowSoon()
431{
432    // Make sure this Page can no longer be found by JS.
433    m_webView->page()->setGroupName(String());
434
435    // Make sure that all loading is stopped.  Ensures that JS stops executing!
436    m_webView->mainFrame()->stopLoading();
437
438    if (m_webView->client())
439        m_webView->client()->closeWidgetSoon();
440}
441
442// Although a Frame is passed in, we don't actually use it, since we
443// already know our own m_webView.
444void ChromeClientImpl::runJavaScriptAlert(Frame* frame, const String& message)
445{
446    if (m_webView->client()) {
447        m_webView->client()->runModalAlertDialog(
448            WebFrameImpl::fromFrame(frame), message);
449    }
450}
451
452// See comments for runJavaScriptAlert().
453bool ChromeClientImpl::runJavaScriptConfirm(Frame* frame, const String& message)
454{
455    if (m_webView->client()) {
456        return m_webView->client()->runModalConfirmDialog(
457            WebFrameImpl::fromFrame(frame), message);
458    }
459    return false;
460}
461
462// See comments for runJavaScriptAlert().
463bool ChromeClientImpl::runJavaScriptPrompt(Frame* frame,
464                                           const String& message,
465                                           const String& defaultValue,
466                                           String& result)
467{
468    if (m_webView->client()) {
469        WebString actualValue;
470        bool ok = m_webView->client()->runModalPromptDialog(
471            WebFrameImpl::fromFrame(frame),
472            message,
473            defaultValue,
474            &actualValue);
475        if (ok)
476            result = actualValue;
477        return ok;
478    }
479    return false;
480}
481
482void ChromeClientImpl::setStatusbarText(const String& message)
483{
484    if (m_webView->client())
485        m_webView->client()->setStatusText(message);
486}
487
488bool ChromeClientImpl::shouldInterruptJavaScript()
489{
490    // FIXME: implement me
491    return false;
492}
493
494KeyboardUIMode ChromeClientImpl::keyboardUIMode()
495{
496    return m_webView->tabsToLinks() ? KeyboardAccessTabsToLinks : KeyboardAccessDefault;
497}
498
499IntRect ChromeClientImpl::windowResizerRect() const
500{
501    IntRect result;
502    if (m_webView->client())
503        result = m_webView->client()->windowResizerRect();
504    return result;
505}
506
507#if ENABLE(REGISTER_PROTOCOL_HANDLER)
508void ChromeClientImpl::registerProtocolHandler(const String& scheme, const String& baseURL, const String& url, const String& title)
509{
510    m_webView->client()->registerProtocolHandler(scheme, baseURL, url, title);
511}
512#endif
513
514void ChromeClientImpl::invalidateWindow(const IntRect&, bool)
515{
516    notImplemented();
517}
518
519void ChromeClientImpl::invalidateContentsAndWindow(const IntRect& updateRect, bool /*immediate*/)
520{
521    if (updateRect.isEmpty())
522        return;
523#if USE(ACCELERATED_COMPOSITING)
524    if (!m_webView->isAcceleratedCompositingActive()) {
525#endif
526        if (m_webView->client())
527            m_webView->client()->didInvalidateRect(updateRect);
528#if USE(ACCELERATED_COMPOSITING)
529    } else
530        m_webView->invalidateRootLayerRect(updateRect);
531#endif
532}
533
534void ChromeClientImpl::invalidateContentsForSlowScroll(const IntRect& updateRect, bool immediate)
535{
536    m_webView->hidePopups();
537    invalidateContentsAndWindow(updateRect, immediate);
538}
539
540#if ENABLE(REQUEST_ANIMATION_FRAME)
541void ChromeClientImpl::scheduleAnimation()
542{
543    m_webView->client()->scheduleAnimation();
544}
545#endif
546
547void ChromeClientImpl::scroll(
548    const IntSize& scrollDelta, const IntRect& scrollRect,
549    const IntRect& clipRect)
550{
551    m_webView->hidePopups();
552#if USE(ACCELERATED_COMPOSITING)
553    if (!m_webView->isAcceleratedCompositingActive()) {
554#endif
555        if (m_webView->client()) {
556            int dx = scrollDelta.width();
557            int dy = scrollDelta.height();
558            m_webView->client()->didScrollRect(dx, dy, clipRect);
559        }
560#if USE(ACCELERATED_COMPOSITING)
561    } else
562        m_webView->scrollRootLayerRect(scrollDelta, clipRect);
563#endif
564}
565
566IntPoint ChromeClientImpl::screenToWindow(const IntPoint&) const
567{
568    notImplemented();
569    return IntPoint();
570}
571
572IntRect ChromeClientImpl::windowToScreen(const IntRect& rect) const
573{
574    IntRect screenRect(rect);
575
576    if (m_webView->client()) {
577        WebRect windowRect = m_webView->client()->windowRect();
578        screenRect.move(windowRect.x, windowRect.y);
579    }
580
581    return screenRect;
582}
583
584void ChromeClientImpl::contentsSizeChanged(Frame* frame, const IntSize& size) const
585{
586    WebFrameImpl* webframe = WebFrameImpl::fromFrame(frame);
587    if (webframe->client())
588        webframe->client()->didChangeContentsSize(webframe, size);
589}
590
591void ChromeClientImpl::scrollbarsModeDidChange() const
592{
593}
594
595void ChromeClientImpl::mouseDidMoveOverElement(
596    const HitTestResult& result, unsigned modifierFlags)
597{
598    if (!m_webView->client())
599        return;
600
601    WebURL url;
602    // Find out if the mouse is over a link, and if so, let our UI know...
603    if (result.isLiveLink() && !result.absoluteLinkURL().string().isEmpty())
604        url = result.absoluteLinkURL();
605    else if (result.innerNonSharedNode()
606             && (result.innerNonSharedNode()->hasTagName(HTMLNames::objectTag)
607                 || result.innerNonSharedNode()->hasTagName(HTMLNames::embedTag))) {
608        RenderObject* object = result.innerNonSharedNode()->renderer();
609        if (object && object->isWidget()) {
610            Widget* widget = toRenderWidget(object)->widget();
611            if (widget && widget->isPluginContainer()) {
612                WebPluginContainerImpl* plugin = static_cast<WebPluginContainerImpl*>(widget);
613                url = plugin->plugin()->linkAtPosition(result.point());
614            }
615        }
616    }
617
618    m_webView->client()->setMouseOverURL(url);
619}
620
621void ChromeClientImpl::setToolTip(const String& tooltipText, TextDirection dir)
622{
623    if (!m_webView->client())
624        return;
625    WebTextDirection textDirection = (dir == RTL) ?
626        WebTextDirectionRightToLeft :
627        WebTextDirectionLeftToRight;
628    m_webView->client()->setToolTipText(
629        tooltipText, textDirection);
630}
631
632void ChromeClientImpl::print(Frame* frame)
633{
634    if (m_webView->client())
635        m_webView->client()->printPage(WebFrameImpl::fromFrame(frame));
636}
637
638void ChromeClientImpl::exceededDatabaseQuota(Frame* frame, const String& databaseName)
639{
640    // Chromium users cannot currently change the default quota
641}
642
643#if ENABLE(OFFLINE_WEB_APPLICATIONS)
644void ChromeClientImpl::reachedMaxAppCacheSize(int64_t spaceNeeded)
645{
646    ASSERT_NOT_REACHED();
647}
648
649void ChromeClientImpl::reachedApplicationCacheOriginQuota(SecurityOrigin*)
650{
651    ASSERT_NOT_REACHED();
652}
653#endif
654
655void ChromeClientImpl::runOpenPanel(Frame* frame, PassRefPtr<FileChooser> fileChooser)
656{
657    WebViewClient* client = m_webView->client();
658    if (!client)
659        return;
660
661    WebFileChooserParams params;
662    params.multiSelect = fileChooser->allowsMultipleFiles();
663#if ENABLE(DIRECTORY_UPLOAD)
664    params.directory = fileChooser->allowsDirectoryUpload();
665#else
666    params.directory = false;
667#endif
668    params.acceptTypes = fileChooser->acceptTypes();
669    params.selectedFiles = fileChooser->filenames();
670    if (params.selectedFiles.size() > 0)
671        params.initialValue = params.selectedFiles[0];
672    WebFileChooserCompletionImpl* chooserCompletion =
673        new WebFileChooserCompletionImpl(fileChooser);
674
675    if (client->runFileChooser(params, chooserCompletion))
676        return;
677
678    // Choosing failed, so do callback with an empty list.
679    chooserCompletion->didChooseFile(WebVector<WebString>());
680}
681
682void ChromeClientImpl::chooseIconForFiles(const Vector<String>& filenames, FileChooser* fileChooser)
683{
684    if (!m_webView->client())
685        return;
686    WebIconLoadingCompletionImpl* iconCompletion = new WebIconLoadingCompletionImpl(fileChooser);
687    if (!m_webView->client()->queryIconForFiles(filenames, iconCompletion))
688        iconCompletion->didLoadIcon(WebData());
689}
690
691#if ENABLE(DIRECTORY_UPLOAD)
692void ChromeClientImpl::enumerateChosenDirectory(const String& path, FileChooser* fileChooser)
693{
694    WebViewClient* client = m_webView->client();
695    if (!client)
696        return;
697
698    WebFileChooserCompletionImpl* chooserCompletion =
699        new WebFileChooserCompletionImpl(fileChooser);
700
701    // If the enumeration can't happen, call the callback with an empty list.
702    if (!client->enumerateChosenDirectory(path, chooserCompletion))
703        chooserCompletion->didChooseFile(WebVector<WebString>());
704}
705#endif
706
707void ChromeClientImpl::popupOpened(PopupContainer* popupContainer,
708                                   const IntRect& bounds,
709                                   bool handleExternally)
710{
711    if (!m_webView->client())
712        return;
713
714    WebWidget* webwidget;
715    if (handleExternally) {
716        WebPopupMenuInfo popupInfo;
717        getPopupMenuInfo(popupContainer, &popupInfo);
718        webwidget = m_webView->client()->createPopupMenu(popupInfo);
719    } else {
720        webwidget = m_webView->client()->createPopupMenu(
721            convertPopupType(popupContainer->popupType()));
722        // We only notify when the WebView has to handle the popup, as when
723        // the popup is handled externally, the fact that a popup is showing is
724        // transparent to the WebView.
725        m_webView->popupOpened(popupContainer);
726    }
727    static_cast<WebPopupMenuImpl*>(webwidget)->Init(popupContainer, bounds);
728}
729
730void ChromeClientImpl::popupClosed(WebCore::PopupContainer* popupContainer)
731{
732    m_webView->popupClosed(popupContainer);
733}
734
735void ChromeClientImpl::setCursor(const WebCore::Cursor& cursor)
736{
737    setCursor(WebCursorInfo(cursor));
738}
739
740void ChromeClientImpl::setCursor(const WebCursorInfo& cursor)
741{
742    if (m_webView->client())
743        m_webView->client()->didChangeCursor(cursor);
744}
745
746void ChromeClientImpl::setCursorForPlugin(const WebCursorInfo& cursor)
747{
748    setCursor(cursor);
749}
750
751void ChromeClientImpl::formStateDidChange(const Node* node)
752{
753    // The current history item is not updated yet.  That happens lazily when
754    // WebFrame::currentHistoryItem is requested.
755    WebFrameImpl* webframe = WebFrameImpl::fromFrame(node->document()->frame());
756    if (webframe->client())
757        webframe->client()->didUpdateCurrentHistoryItem(webframe);
758}
759
760void ChromeClientImpl::getPopupMenuInfo(PopupContainer* popupContainer,
761                                        WebPopupMenuInfo* info)
762{
763    const Vector<PopupItem*>& inputItems = popupContainer->popupData();
764
765    WebVector<WebMenuItemInfo> outputItems(inputItems.size());
766
767    for (size_t i = 0; i < inputItems.size(); ++i) {
768        const PopupItem& inputItem = *inputItems[i];
769        WebMenuItemInfo& outputItem = outputItems[i];
770
771        outputItem.label = inputItem.label;
772        outputItem.enabled = inputItem.enabled;
773        if (inputItem.textDirection == WebCore::RTL)
774            outputItem.textDirection = WebTextDirectionRightToLeft;
775        else
776            outputItem.textDirection = WebTextDirectionLeftToRight;
777        outputItem.hasTextDirectionOverride = inputItem.hasTextDirectionOverride;
778
779        switch (inputItem.type) {
780        case PopupItem::TypeOption:
781            outputItem.type = WebMenuItemInfo::Option;
782            break;
783        case PopupItem::TypeGroup:
784            outputItem.type = WebMenuItemInfo::Group;
785            break;
786        case PopupItem::TypeSeparator:
787            outputItem.type = WebMenuItemInfo::Separator;
788            break;
789        default:
790            ASSERT_NOT_REACHED();
791        }
792    }
793
794    info->itemHeight = popupContainer->menuItemHeight();
795    info->itemFontSize = popupContainer->menuItemFontSize();
796    info->selectedIndex = popupContainer->selectedIndex();
797    info->items.swap(outputItems);
798    info->rightAligned = popupContainer->menuStyle().textDirection() == RTL;
799}
800
801void ChromeClientImpl::postAccessibilityNotification(AccessibilityObject* obj, AXObjectCache::AXNotification notification)
802{
803    // Alert assistive technology about the accessibility object notification.
804    if (obj)
805        m_webView->client()->postAccessibilityNotification(WebAccessibilityObject(obj), toWebAccessibilityNotification(notification));
806}
807
808#if ENABLE(NOTIFICATIONS)
809NotificationPresenter* ChromeClientImpl::notificationPresenter() const
810{
811    return m_webView->notificationPresenterImpl();
812}
813#endif
814
815// FIXME: Remove ChromeClientImpl::requestGeolocationPermissionForFrame and ChromeClientImpl::cancelGeolocationPermissionRequestForFrame
816// once all ports have moved to client-based geolocation (see https://bugs.webkit.org/show_bug.cgi?id=40373 ).
817// For client-based geolocation, these methods are now implemented as WebGeolocationClient::requestPermission and WebGeolocationClient::cancelPermissionRequest.
818// (see https://bugs.webkit.org/show_bug.cgi?id=50061 ).
819void ChromeClientImpl::requestGeolocationPermissionForFrame(Frame* frame, Geolocation* geolocation)
820{
821    ASSERT_NOT_REACHED();
822}
823
824void ChromeClientImpl::cancelGeolocationPermissionRequestForFrame(Frame* frame, Geolocation* geolocation)
825{
826    ASSERT_NOT_REACHED();
827}
828
829#if USE(ACCELERATED_COMPOSITING)
830void ChromeClientImpl::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* graphicsLayer)
831{
832    m_webView->setRootGraphicsLayer(graphicsLayer ? graphicsLayer->platformLayer() : 0);
833}
834
835void ChromeClientImpl::scheduleCompositingLayerSync()
836{
837    m_webView->setRootLayerNeedsDisplay();
838}
839
840ChromeClient::CompositingTriggerFlags ChromeClientImpl::allowedCompositingTriggers() const
841{
842    // FIXME: RTL style not supported by the compositor yet.
843    if (!m_webView->allowsAcceleratedCompositing() || m_webView->pageHasRTLStyle())
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
859    return flags;
860}
861#endif
862
863bool ChromeClientImpl::supportsFullscreenForNode(const WebCore::Node* node)
864{
865    if (m_webView->client() && node->hasTagName(WebCore::HTMLNames::videoTag))
866        return m_webView->client()->supportsFullscreen();
867    return false;
868}
869
870void ChromeClientImpl::enterFullscreenForNode(WebCore::Node* node)
871{
872    if (m_webView->client())
873        m_webView->client()->enterFullscreenForNode(WebNode(node));
874}
875
876void ChromeClientImpl::exitFullscreenForNode(WebCore::Node* node)
877{
878    if (m_webView->client())
879        m_webView->client()->exitFullscreenForNode(WebNode(node));
880}
881
882#if ENABLE(FULLSCREEN_API)
883bool ChromeClientImpl::supportsFullScreenForElement(const WebCore::Element* element, bool withKeyboard)
884{
885    return m_webView->page()->settings()->fullScreenEnabled();
886}
887
888void ChromeClientImpl::enterFullScreenForElement(WebCore::Element* element)
889{
890    // FIXME: We may need to call these someplace else when window resizes.
891    element->document()->webkitWillEnterFullScreenForElement(element);
892    element->document()->webkitDidEnterFullScreenForElement(element);
893}
894
895void ChromeClientImpl::exitFullScreenForElement(WebCore::Element* element)
896{
897    // FIXME: We may need to call these someplace else when window resizes.
898    element->document()->webkitWillExitFullScreenForElement(element);
899    element->document()->webkitDidExitFullScreenForElement(element);
900}
901
902void ChromeClientImpl::fullScreenRendererChanged(RenderBox*)
903{
904    notImplemented();
905}
906#endif
907
908bool ChromeClientImpl::selectItemWritingDirectionIsNatural()
909{
910    return false;
911}
912
913bool ChromeClientImpl::selectItemAlignmentFollowsMenuWritingDirection()
914{
915    return true;
916}
917
918PassRefPtr<PopupMenu> ChromeClientImpl::createPopupMenu(PopupMenuClient* client) const
919{
920    if (WebViewImpl::useExternalPopupMenus())
921        return adoptRef(new ExternalPopupMenu(client, m_webView->client()));
922
923    return adoptRef(new PopupMenuChromium(client));
924}
925
926PassRefPtr<SearchPopupMenu> ChromeClientImpl::createSearchPopupMenu(PopupMenuClient* client) const
927{
928    return adoptRef(new SearchPopupMenuChromium(client));
929}
930
931void ChromeClientImpl::willRunModalDialogDuringPageDismissal(const DialogType& dialogType) const
932{
933    PlatformBridge::histogramEnumeration("Renderer.ModalDialogsDuringPageDismissal", static_cast<int>(dialogType), static_cast<int>(NumDialogTypes));
934}
935
936} // namespace WebKit
937