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