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