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