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