b9709f5bb81f7ca0b270cb3de64fabbbf56f4727
[WebKit-https.git] / Source / WebKit / mac / WebCoreSupport / WebChromeClient.mm
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2008, 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
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #import "WebChromeClient.h"
31
32 #import "DOMElementInternal.h"
33 #import "DOMNodeInternal.h"
34 #import "PopupMenuMac.h"
35 #import "SearchPopupMenuMac.h"
36 #import "WebBasePluginPackage.h"
37 #import "WebDefaultUIDelegate.h"
38 #import "WebDelegateImplementationCaching.h"
39 #import "WebElementDictionary.h"
40 #import "WebFrameInternal.h"
41 #import "WebFrameView.h"
42 #import "WebHTMLViewInternal.h"
43 #import "WebHistoryInternal.h"
44 #import "WebKitFullScreenListener.h"
45 #import "WebKitPrefix.h"
46 #import "WebKitSystemInterface.h"
47 #import "WebNSURLRequestExtras.h"
48 #import "WebOpenPanelResultListener.h"
49 #import "WebPlugin.h"
50 #import "WebQuotaManager.h"
51 #import "WebSecurityOriginInternal.h"
52 #import "WebSelectionServiceController.h"
53 #import "WebUIDelegatePrivate.h"
54 #import "WebView.h"
55 #import "WebViewInternal.h"
56 #import <Foundation/Foundation.h>
57 #import <WebCore/BlockExceptions.h>
58 #import <WebCore/ColorChooser.h>
59 #import <WebCore/ContextMenu.h>
60 #import <WebCore/ContextMenuController.h>
61 #import <WebCore/Cursor.h>
62 #import <WebCore/Element.h>
63 #import <WebCore/FileChooser.h>
64 #import <WebCore/FileIconLoader.h>
65 #import <WebCore/FloatRect.h>
66 #import <WebCore/Frame.h>
67 #import <WebCore/FrameLoadRequest.h>
68 #import <WebCore/FrameView.h>
69 #import <WebCore/GraphicsLayer.h>
70 #import <WebCore/HTMLInputElement.h>
71 #import <WebCore/HTMLNames.h>
72 #import <WebCore/HTMLPlugInImageElement.h>
73 #import <WebCore/HitTestResult.h>
74 #import <WebCore/Icon.h>
75 #import <WebCore/IntPoint.h>
76 #import <WebCore/IntRect.h>
77 #import <WebCore/NavigationAction.h>
78 #import <WebCore/NotImplemented.h>
79 #import <WebCore/Page.h>
80 #import <WebCore/PlatformScreen.h>
81 #import <WebCore/ResourceRequest.h>
82 #import <WebCore/SerializedCryptoKeyWrap.h>
83 #import <WebCore/Widget.h>
84 #import <WebCore/WindowFeatures.h>
85 #import <wtf/PassRefPtr.h>
86 #import <wtf/Vector.h>
87 #import <wtf/text/WTFString.h>
88
89 #if USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API)
90 #import "NetscapePluginHostManager.h"
91 #endif
92
93 #if PLATFORM(IOS) && ENABLE(GEOLOCATION)
94 #import <WebCore/Geolocation.h>
95 #endif
96
97 #if PLATFORM(IOS)
98 #import <WebCore/WAKClipView.h>
99 #import <WebCore/WAKWindow.h>
100 #import <WebCore/WebCoreThreadMessage.h>
101 #endif
102
103 NSString *WebConsoleMessageXMLMessageSource = @"XMLMessageSource";
104 NSString *WebConsoleMessageJSMessageSource = @"JSMessageSource";
105 NSString *WebConsoleMessageNetworkMessageSource = @"NetworkMessageSource";
106 NSString *WebConsoleMessageConsoleAPIMessageSource = @"ConsoleAPIMessageSource";
107 NSString *WebConsoleMessageStorageMessageSource = @"StorageMessageSource";
108 NSString *WebConsoleMessageAppCacheMessageSource = @"AppCacheMessageSource";
109 NSString *WebConsoleMessageRenderingMessageSource = @"RenderingMessageSource";
110 NSString *WebConsoleMessageCSSMessageSource = @"CSSMessageSource";
111 NSString *WebConsoleMessageSecurityMessageSource = @"SecurityMessageSource";
112 NSString *WebConsoleMessageOtherMessageSource = @"OtherMessageSource";
113
114 NSString *WebConsoleMessageDebugMessageLevel = @"DebugMessageLevel";
115 NSString *WebConsoleMessageLogMessageLevel = @"LogMessageLevel";
116 NSString *WebConsoleMessageWarningMessageLevel = @"WarningMessageLevel";
117 NSString *WebConsoleMessageErrorMessageLevel = @"ErrorMessageLevel";
118
119
120 #if !PLATFORM(IOS)
121 @interface NSApplication (WebNSApplicationDetails)
122 - (NSCursor *)_cursorRectCursor;
123 @end
124 #endif
125
126 @interface NSView (WebNSViewDetails)
127 - (NSView *)_findLastViewInKeyViewLoop;
128 @end
129
130 // For compatibility with old SPI.
131 @interface NSView (WebOldWebKitPlugInDetails)
132 - (void)setIsSelected:(BOOL)isSelected;
133 @end
134
135 #if !PLATFORM(IOS)
136 @interface NSWindow (AppKitSecretsIKnowAbout)
137 - (NSRect)_growBoxRect;
138 @end
139 #endif
140
141 using namespace WebCore;
142 using namespace HTMLNames;
143
144 WebChromeClient::WebChromeClient(WebView *webView) 
145     : m_webView(webView)
146 {
147 }
148
149 void WebChromeClient::chromeDestroyed()
150 {
151     delete this;
152 }
153
154 // These functions scale between window and WebView coordinates because JavaScript/DOM operations 
155 // assume that the WebView and the window share the same coordinate system.
156
157 void WebChromeClient::setWindowRect(const FloatRect& rect)
158 {
159 #if !PLATFORM(IOS)
160     NSRect windowRect = toDeviceSpace(rect, [m_webView window]);
161     [[m_webView _UIDelegateForwarder] webView:m_webView setFrame:windowRect];
162 #endif
163 }
164
165 FloatRect WebChromeClient::windowRect()
166 {
167 #if !PLATFORM(IOS)
168     NSRect windowRect = [[m_webView _UIDelegateForwarder] webViewFrame:m_webView];
169     return toUserSpace(windowRect, [m_webView window]);
170 #else
171     return FloatRect();
172 #endif
173 }
174
175 // FIXME: We need to add API for setting and getting this.
176 FloatRect WebChromeClient::pageRect()
177 {
178     return [m_webView frame];
179 }
180
181 void WebChromeClient::focus()
182 {
183     [[m_webView _UIDelegateForwarder] webViewFocus:m_webView];
184 }
185
186 void WebChromeClient::unfocus()
187 {
188     [[m_webView _UIDelegateForwarder] webViewUnfocus:m_webView];
189 }
190
191 bool WebChromeClient::canTakeFocus(FocusDirection)
192 {
193     // There's unfortunately no way to determine if we will become first responder again
194     // once we give it up, so we just have to guess that we won't.
195     return true;
196 }
197
198 void WebChromeClient::takeFocus(FocusDirection direction)
199 {
200 #if !PLATFORM(IOS)
201     if (direction == FocusDirectionForward) {
202         // Since we're trying to move focus out of m_webView, and because
203         // m_webView may contain subviews within it, we ask it for the next key
204         // view of the last view in its key view loop. This makes m_webView
205         // behave as if it had no subviews, which is the behavior we want.
206         NSView *lastView = [m_webView _findLastViewInKeyViewLoop];
207         // avoid triggering assertions if the WebView is the only thing in the key loop
208         if ([m_webView _becomingFirstResponderFromOutside] && m_webView == [lastView nextValidKeyView])
209             return;
210         [[m_webView window] selectKeyViewFollowingView:lastView];
211     } else {
212         // avoid triggering assertions if the WebView is the only thing in the key loop
213         if ([m_webView _becomingFirstResponderFromOutside] && m_webView == [m_webView previousValidKeyView])
214             return;
215         [[m_webView window] selectKeyViewPrecedingView:m_webView];
216     }
217 #endif
218 }
219
220 void WebChromeClient::focusedElementChanged(Element* element)
221 {
222     if (!is<HTMLInputElement>(element))
223         return;
224
225     HTMLInputElement& inputElement = downcast<HTMLInputElement>(*element);
226     if (!inputElement.isText())
227         return;
228
229     CallFormDelegate(m_webView, @selector(didFocusTextField:inFrame:), kit(&inputElement), kit(inputElement.document().frame()));
230 }
231
232 void WebChromeClient::focusedFrameChanged(Frame*)
233 {
234 }
235
236 Page* WebChromeClient::createWindow(Frame* frame, const FrameLoadRequest&, const WindowFeatures& features, const NavigationAction&)
237 {
238     id delegate = [m_webView UIDelegate];
239     WebView *newWebView;
240
241 #if ENABLE(FULLSCREEN_API)
242     if (frame->document() && frame->document()->webkitCurrentFullScreenElement())
243         frame->document()->webkitCancelFullScreen();
244 #endif
245     
246     if ([delegate respondsToSelector:@selector(webView:createWebViewWithRequest:windowFeatures:)]) {
247         NSNumber *x = features.xSet ? [[NSNumber alloc] initWithFloat:features.x] : nil;
248         NSNumber *y = features.ySet ? [[NSNumber alloc] initWithFloat:features.y] : nil;
249         NSNumber *width = features.widthSet ? [[NSNumber alloc] initWithFloat:features.width] : nil;
250         NSNumber *height = features.heightSet ? [[NSNumber alloc] initWithFloat:features.height] : nil;
251         NSNumber *menuBarVisible = [[NSNumber alloc] initWithBool:features.menuBarVisible];
252         NSNumber *statusBarVisible = [[NSNumber alloc] initWithBool:features.statusBarVisible];
253         NSNumber *toolBarVisible = [[NSNumber alloc] initWithBool:features.toolBarVisible];
254         NSNumber *scrollbarsVisible = [[NSNumber alloc] initWithBool:features.scrollbarsVisible];
255         NSNumber *resizable = [[NSNumber alloc] initWithBool:features.resizable];
256         NSNumber *fullscreen = [[NSNumber alloc] initWithBool:features.fullscreen];
257         NSNumber *dialog = [[NSNumber alloc] initWithBool:features.dialog];
258         
259         NSMutableDictionary *dictFeatures = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
260                                              menuBarVisible, @"menuBarVisible", 
261                                              statusBarVisible, @"statusBarVisible",
262                                              toolBarVisible, @"toolBarVisible",
263                                              scrollbarsVisible, @"scrollbarsVisible",
264                                              resizable, @"resizable",
265                                              fullscreen, @"fullscreen",
266                                              dialog, @"dialog",
267                                              nil];
268         
269         if (x)
270             [dictFeatures setObject:x forKey:@"x"];
271         if (y)
272             [dictFeatures setObject:y forKey:@"y"];
273         if (width)
274             [dictFeatures setObject:width forKey:@"width"];
275         if (height)
276             [dictFeatures setObject:height forKey:@"height"];
277         
278         newWebView = CallUIDelegate(m_webView, @selector(webView:createWebViewWithRequest:windowFeatures:), nil, dictFeatures);
279         
280         [dictFeatures release];
281         [x release];
282         [y release];
283         [width release];
284         [height release];
285         [menuBarVisible release];
286         [statusBarVisible release];
287         [toolBarVisible release];
288         [scrollbarsVisible release];
289         [resizable release];
290         [fullscreen release];
291         [dialog release];
292     } else if (features.dialog && [delegate respondsToSelector:@selector(webView:createWebViewModalDialogWithRequest:)]) {
293         newWebView = CallUIDelegate(m_webView, @selector(webView:createWebViewModalDialogWithRequest:), nil);
294     } else {
295         newWebView = CallUIDelegate(m_webView, @selector(webView:createWebViewWithRequest:), nil);
296     }
297
298 #if USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API)
299     if (newWebView)
300         WebKit::NetscapePluginHostManager::singleton().didCreateWindow();
301 #endif
302     
303     return core(newWebView);
304 }
305
306 void WebChromeClient::show()
307 {
308     [[m_webView _UIDelegateForwarder] webViewShow:m_webView];
309 }
310
311 bool WebChromeClient::canRunModal()
312 {
313     return [[m_webView UIDelegate] respondsToSelector:@selector(webViewRunModal:)];
314 }
315
316 void WebChromeClient::runModal()
317 {
318     CallUIDelegate(m_webView, @selector(webViewRunModal:));
319 }
320
321 void WebChromeClient::setToolbarsVisible(bool b)
322 {
323     [[m_webView _UIDelegateForwarder] webView:m_webView setToolbarsVisible:b];
324 }
325
326 bool WebChromeClient::toolbarsVisible()
327 {
328     return CallUIDelegateReturningBoolean(NO, m_webView, @selector(webViewAreToolbarsVisible:));
329 }
330
331 void WebChromeClient::setStatusbarVisible(bool b)
332 {
333     [[m_webView _UIDelegateForwarder] webView:m_webView setStatusBarVisible:b];
334 }
335
336 bool WebChromeClient::statusbarVisible()
337 {
338     return CallUIDelegateReturningBoolean(NO, m_webView, @selector(webViewIsStatusBarVisible:));
339 }
340
341 void WebChromeClient::setScrollbarsVisible(bool b)
342 {
343     [[[m_webView mainFrame] frameView] setAllowsScrolling:b];
344 }
345
346 bool WebChromeClient::scrollbarsVisible()
347 {
348     return [[[m_webView mainFrame] frameView] allowsScrolling];
349 }
350
351 void WebChromeClient::setMenubarVisible(bool)
352 {
353     // The menubar is always visible in Mac OS X.
354     return;
355 }
356
357 bool WebChromeClient::menubarVisible()
358 {
359     // The menubar is always visible in Mac OS X.
360     return true;
361 }
362
363 void WebChromeClient::setResizable(bool b)
364 {
365     [[m_webView _UIDelegateForwarder] webView:m_webView setResizable:b];
366 }
367
368 inline static NSString *stringForMessageSource(MessageSource source)
369 {
370     switch (source) {
371     case MessageSource::XML:
372         return WebConsoleMessageXMLMessageSource;
373     case MessageSource::JS:
374         return WebConsoleMessageJSMessageSource;
375     case MessageSource::Network:
376         return WebConsoleMessageNetworkMessageSource;
377     case MessageSource::ConsoleAPI:
378         return WebConsoleMessageConsoleAPIMessageSource;
379     case MessageSource::Storage:
380         return WebConsoleMessageStorageMessageSource;
381     case MessageSource::AppCache:
382         return WebConsoleMessageAppCacheMessageSource;
383     case MessageSource::Rendering:
384         return WebConsoleMessageRenderingMessageSource;
385     case MessageSource::CSS:
386         return WebConsoleMessageCSSMessageSource;
387     case MessageSource::Security:
388         return WebConsoleMessageSecurityMessageSource;
389     case MessageSource::Other:
390         return WebConsoleMessageOtherMessageSource;
391     }
392     ASSERT_NOT_REACHED();
393     return @"";
394 }
395
396 inline static NSString *stringForMessageLevel(MessageLevel level)
397 {
398     switch (level) {
399     case MessageLevel::Debug:
400         return WebConsoleMessageDebugMessageLevel;
401     case MessageLevel::Log:
402         return WebConsoleMessageLogMessageLevel;
403     case MessageLevel::Warning:
404         return WebConsoleMessageWarningMessageLevel;
405     case MessageLevel::Error:
406         return WebConsoleMessageErrorMessageLevel;
407     }
408     ASSERT_NOT_REACHED();
409     return @"";
410 }
411
412 void WebChromeClient::addMessageToConsole(MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, unsigned columnNumber, const String& sourceURL)
413 {
414 #if !PLATFORM(IOS)
415     id delegate = [m_webView UIDelegate];
416 #else
417     if (![m_webView _allowsMessaging])
418         return;
419
420     id delegate = [m_webView _UIKitDelegate];
421     // No delegate means nothing to send this data to so bail.
422     if (!delegate)
423         return;
424 #endif
425
426     BOOL respondsToNewSelector = NO;
427
428     SEL selector = @selector(webView:addMessageToConsole:withSource:);
429     if ([delegate respondsToSelector:selector])
430         respondsToNewSelector = YES;
431     else {
432         // The old selector only takes JSMessageSource messages.
433         if (source != MessageSource::JS)
434             return;
435         selector = @selector(webView:addMessageToConsole:);
436         if (![delegate respondsToSelector:selector])
437             return;
438     }
439
440     NSString *messageSource = stringForMessageSource(source);
441     NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:
442         (NSString *)message, @"message",
443         [NSNumber numberWithUnsignedInt:lineNumber], @"lineNumber",
444         [NSNumber numberWithUnsignedInt:columnNumber], @"columnNumber",
445         (NSString *)sourceURL, @"sourceURL",
446         messageSource, @"MessageSource",
447         stringForMessageLevel(level), @"MessageLevel",
448         NULL];
449
450 #if PLATFORM(IOS)
451     [[[m_webView _UIKitDelegateForwarder] asyncForwarder] webView:m_webView addMessageToConsole:dictionary withSource:messageSource];
452 #else
453     if (respondsToNewSelector)
454         CallUIDelegate(m_webView, selector, dictionary, messageSource);
455     else
456         CallUIDelegate(m_webView, selector, dictionary);
457 #endif
458
459     [dictionary release];
460 }
461
462 bool WebChromeClient::canRunBeforeUnloadConfirmPanel()
463 {
464     return [[m_webView UIDelegate] respondsToSelector:@selector(webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:)];
465 }
466
467 bool WebChromeClient::runBeforeUnloadConfirmPanel(const String& message, Frame* frame)
468 {
469     return CallUIDelegateReturningBoolean(true, m_webView, @selector(webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:), message, kit(frame));
470 }
471
472 void WebChromeClient::closeWindowSoon()
473 {
474     // We need to remove the parent WebView from WebViewSets here, before it actually
475     // closes, to make sure that JavaScript code that executes before it closes
476     // can't find it. Otherwise, window.open will select a closed WebView instead of 
477     // opening a new one <rdar://problem/3572585>.
478
479     // We also need to stop the load to prevent further parsing or JavaScript execution
480     // after the window has torn down <rdar://problem/4161660>.
481   
482     // FIXME: This code assumes that the UI delegate will respond to a webViewClose
483     // message by actually closing the WebView. Safari guarantees this behavior, but other apps might not.
484     // This approach is an inherent limitation of not making a close execute immediately
485     // after a call to window.close.
486
487     [m_webView setGroupName:nil];
488     [m_webView stopLoading:nil];
489     [m_webView performSelector:@selector(_closeWindow) withObject:nil afterDelay:0.0];
490 }
491
492 void WebChromeClient::runJavaScriptAlert(Frame* frame, const String& message)
493 {
494     id delegate = [m_webView UIDelegate];
495     SEL selector = @selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:);
496     if ([delegate respondsToSelector:selector]) {
497         CallUIDelegate(m_webView, selector, message, kit(frame));
498         return;
499     }
500
501     // Call the old version of the delegate method if it is implemented.
502     selector = @selector(webView:runJavaScriptAlertPanelWithMessage:);
503     if ([delegate respondsToSelector:selector]) {
504         CallUIDelegate(m_webView, selector, message);
505         return;
506     }
507 }
508
509 bool WebChromeClient::runJavaScriptConfirm(Frame* frame, const String& message)
510 {
511     id delegate = [m_webView UIDelegate];
512     SEL selector = @selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:);
513     if ([delegate respondsToSelector:selector])
514         return CallUIDelegateReturningBoolean(NO, m_webView, selector, message, kit(frame));
515
516     // Call the old version of the delegate method if it is implemented.
517     selector = @selector(webView:runJavaScriptConfirmPanelWithMessage:);
518     if ([delegate respondsToSelector:selector])
519         return CallUIDelegateReturningBoolean(NO, m_webView, selector, message);
520
521     return NO;
522 }
523
524 bool WebChromeClient::runJavaScriptPrompt(Frame* frame, const String& prompt, const String& defaultText, String& result)
525 {
526     id delegate = [m_webView UIDelegate];
527     SEL selector = @selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:);
528     NSString *defaultString = defaultText;
529     if ([delegate respondsToSelector:selector]) {
530         result = (NSString *)CallUIDelegate(m_webView, selector, prompt, defaultString, kit(frame));
531         return !result.isNull();
532     }
533
534     // Call the old version of the delegate method if it is implemented.
535     selector = @selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:);
536     if ([delegate respondsToSelector:selector]) {
537         result = (NSString *)CallUIDelegate(m_webView, selector, prompt, defaultString);
538         return !result.isNull();
539     }
540
541     result = [[WebDefaultUIDelegate sharedUIDelegate] webView:m_webView runJavaScriptTextInputPanelWithPrompt:prompt defaultText:defaultString initiatedByFrame:kit(frame)];
542     return !result.isNull();
543 }
544
545 bool WebChromeClient::shouldInterruptJavaScript()
546 {
547     return CallUIDelegateReturningBoolean(NO, m_webView, @selector(webViewShouldInterruptJavaScript:));
548 }
549
550 void WebChromeClient::setStatusbarText(const String& status)
551 {
552     // We want the temporaries allocated here to be released even before returning to the 
553     // event loop; see <http://bugs.webkit.org/show_bug.cgi?id=9880>.
554     NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init];
555     CallUIDelegate(m_webView, @selector(webView:setStatusText:), (NSString *)status);
556     [localPool drain];
557 }
558
559 IntRect WebChromeClient::windowResizerRect() const
560 {
561 #if !PLATFORM(IOS)
562     return enclosingIntRect([[m_webView window] _growBoxRect]);
563 #else
564     return IntRect();
565 #endif
566 }
567
568 bool WebChromeClient::supportsImmediateInvalidation()
569 {
570     return true;
571 }
572
573 void WebChromeClient::invalidateRootView(const IntRect&)
574 {
575 }
576
577 void WebChromeClient::invalidateContentsAndRootView(const IntRect& rect)
578 {
579 }
580
581 void WebChromeClient::invalidateContentsForSlowScroll(const IntRect& rect)
582 {
583     invalidateContentsAndRootView(rect);
584 }
585
586 void WebChromeClient::scroll(const IntSize&, const IntRect&, const IntRect&)
587 {
588 }
589
590 IntPoint WebChromeClient::screenToRootView(const IntPoint& p) const
591 {
592     // FIXME: Implement this.
593     return p;
594 }
595
596 IntRect WebChromeClient::rootViewToScreen(const IntRect& r) const
597 {
598     // FIXME: Implement this.
599     return r;
600 }
601
602 #if PLATFORM(IOS)
603 IntPoint WebChromeClient::accessibilityScreenToRootView(const IntPoint& p) const
604 {
605     return p;
606 }
607
608 IntRect WebChromeClient::rootViewToAccessibilityScreen(const IntRect& r) const
609 {
610     return r;
611 }
612 #endif
613
614 PlatformPageClient WebChromeClient::platformPageClient() const
615 {
616     return 0;
617 }
618
619 void WebChromeClient::contentsSizeChanged(Frame*, const IntSize&) const
620 {
621 }
622
623 void WebChromeClient::scrollRectIntoView(const IntRect& r) const
624 {
625     // FIXME: This scrolling behavior should be under the control of the embedding client,
626     // perhaps in a delegate method, rather than something WebKit does unconditionally.
627     NSView *coordinateView = [[[m_webView mainFrame] frameView] documentView];
628     NSRect rect = r;
629     for (NSView *view = m_webView; view; view = [view superview]) {
630         if ([view isKindOfClass:[NSClipView class]]) {
631             NSClipView *clipView = (NSClipView *)view;
632             NSView *documentView = [clipView documentView];
633             [documentView scrollRectToVisible:[documentView convertRect:rect fromView:coordinateView]];
634         }
635     }
636 }
637
638 // End host window methods.
639
640 bool WebChromeClient::shouldUnavailablePluginMessageBeButton(RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason) const
641 {
642     if (pluginUnavailabilityReason == RenderEmbeddedObject::PluginMissing)
643         return [[m_webView UIDelegate] respondsToSelector:@selector(webView:didPressMissingPluginButton:)];
644
645     return false;
646 }
647
648 void WebChromeClient::unavailablePluginButtonClicked(Element* element, RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason) const
649 {
650     ASSERT(element->hasTagName(objectTag) || element->hasTagName(embedTag) || element->hasTagName(appletTag));
651
652     ASSERT(pluginUnavailabilityReason == RenderEmbeddedObject::PluginMissing);
653     CallUIDelegate(m_webView, @selector(webView:didPressMissingPluginButton:), kit(element));
654 }
655
656 void WebChromeClient::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags)
657 {
658     WebElementDictionary *element = [[WebElementDictionary alloc] initWithHitTestResult:result];
659     [m_webView _mouseDidMoveOverElement:element modifierFlags:modifierFlags];
660     [element release];
661 }
662
663 void WebChromeClient::setToolTip(const String& toolTip, TextDirection)
664 {
665     NSView<WebDocumentView> *documentView = [[[m_webView _selectedOrMainFrame] frameView] documentView];
666     if ([documentView isKindOfClass:[WebHTMLView class]])
667         [(WebHTMLView *)documentView _setToolTip:toolTip];
668 }
669
670 void WebChromeClient::print(Frame* frame)
671 {
672     WebFrame *webFrame = kit(frame);
673     if ([[m_webView UIDelegate] respondsToSelector:@selector(webView:printFrame:)])
674         CallUIDelegate(m_webView, @selector(webView:printFrame:), webFrame);
675     else
676         CallUIDelegate(m_webView, @selector(webView:printFrameView:), [webFrame frameView]);
677 }
678
679 void WebChromeClient::exceededDatabaseQuota(Frame* frame, const String& databaseName, DatabaseDetails)
680 {
681     BEGIN_BLOCK_OBJC_EXCEPTIONS;
682
683     WebSecurityOrigin *webOrigin = [[WebSecurityOrigin alloc] _initWithWebCoreSecurityOrigin:frame->document()->securityOrigin()];
684     CallUIDelegate(m_webView, @selector(webView:frame:exceededDatabaseQuotaForSecurityOrigin:database:), kit(frame), webOrigin, (NSString *)databaseName);
685     [webOrigin release];
686
687     END_BLOCK_OBJC_EXCEPTIONS;
688 }
689
690 void WebChromeClient::reachedMaxAppCacheSize(int64_t spaceNeeded)
691 {
692     // FIXME: Free some space.
693 }
694
695 void WebChromeClient::reachedApplicationCacheOriginQuota(SecurityOrigin* origin, int64_t totalSpaceNeeded)
696 {
697     BEGIN_BLOCK_OBJC_EXCEPTIONS;
698
699     WebSecurityOrigin *webOrigin = [[WebSecurityOrigin alloc] _initWithWebCoreSecurityOrigin:origin];
700     CallUIDelegate(m_webView, @selector(webView:exceededApplicationCacheOriginQuotaForSecurityOrigin:totalSpaceNeeded:), webOrigin, static_cast<NSUInteger>(totalSpaceNeeded));
701     [webOrigin release];
702
703     END_BLOCK_OBJC_EXCEPTIONS;
704 }
705
706 #if ENABLE(DASHBOARD_SUPPORT)
707
708 void WebChromeClient::annotatedRegionsChanged()
709 {
710     BEGIN_BLOCK_OBJC_EXCEPTIONS;
711     CallUIDelegate(m_webView, @selector(webView:dashboardRegionsChanged:), [m_webView _dashboardRegions]);
712     END_BLOCK_OBJC_EXCEPTIONS;
713 }
714
715 #endif
716
717 #if ENABLE(INPUT_TYPE_COLOR)
718 std::unique_ptr<ColorChooser> WebChromeClient::createColorChooser(ColorChooserClient* client, const Color& initialColor)
719 {
720     // FIXME: Implement <input type='color'> for WK1 (Bug 119094).
721     ASSERT_NOT_REACHED();
722     return nullptr;
723 }
724 #endif
725
726 void WebChromeClient::runOpenPanel(Frame*, PassRefPtr<FileChooser> chooser)
727 {
728     BEGIN_BLOCK_OBJC_EXCEPTIONS;
729     BOOL allowMultipleFiles = chooser->settings().allowsMultipleFiles;
730     WebOpenPanelResultListener *listener = [[WebOpenPanelResultListener alloc] initWithChooser:chooser];
731     id delegate = [m_webView UIDelegate];
732     if ([delegate respondsToSelector:@selector(webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:)])
733         CallUIDelegate(m_webView, @selector(webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:), listener, allowMultipleFiles);
734     else if ([delegate respondsToSelector:@selector(webView:runOpenPanelForFileButtonWithResultListener:)])
735         CallUIDelegate(m_webView, @selector(webView:runOpenPanelForFileButtonWithResultListener:), listener);
736     else
737         [listener cancel];
738     [listener release];
739     END_BLOCK_OBJC_EXCEPTIONS;
740 }
741
742 void WebChromeClient::loadIconForFiles(const Vector<String>& filenames, FileIconLoader* iconLoader)
743 {
744     iconLoader->notifyFinished(Icon::createIconForFiles(filenames));
745 }
746
747 #if !PLATFORM(IOS)
748
749 void WebChromeClient::setCursor(const WebCore::Cursor& cursor)
750 {
751     // FIXME: Would be nice to share this code with WebKit2's PageClientImpl.
752
753     if ([NSApp _cursorRectCursor])
754         return;
755
756     if (!m_webView)
757         return;
758
759     NSWindow *window = [m_webView window];
760     if (!window)
761         return;
762
763     if ([window windowNumber] != [NSWindow windowNumberAtPoint:[NSEvent mouseLocation] belowWindowWithWindowNumber:0])
764         return;
765
766     NSCursor *platformCursor = cursor.platformCursor();
767     if ([NSCursor currentCursor] == platformCursor)
768         return;
769
770     [platformCursor set];
771 }
772
773 void WebChromeClient::setCursorHiddenUntilMouseMoves(bool hiddenUntilMouseMoves)
774 {
775     [NSCursor setHiddenUntilMouseMoves:hiddenUntilMouseMoves];
776 }
777
778 #endif
779
780 KeyboardUIMode WebChromeClient::keyboardUIMode()
781 {
782     BEGIN_BLOCK_OBJC_EXCEPTIONS;
783     return [m_webView _keyboardUIMode];
784     END_BLOCK_OBJC_EXCEPTIONS;
785     return KeyboardAccessDefault;
786 }
787
788 NSResponder *WebChromeClient::firstResponder()
789 {
790     BEGIN_BLOCK_OBJC_EXCEPTIONS;
791     return [[m_webView _UIDelegateForwarder] webViewFirstResponder:m_webView];
792     END_BLOCK_OBJC_EXCEPTIONS;
793     return nil;
794 }
795
796 void WebChromeClient::makeFirstResponder(NSResponder *responder)
797 {
798     BEGIN_BLOCK_OBJC_EXCEPTIONS;
799     [m_webView _pushPerformingProgrammaticFocus];
800     [[m_webView _UIDelegateForwarder] webView:m_webView makeFirstResponder:responder];
801     [m_webView _popPerformingProgrammaticFocus];
802     END_BLOCK_OBJC_EXCEPTIONS;
803 }
804
805 void WebChromeClient::enableSuddenTermination()
806 {
807 #if !PLATFORM(IOS)
808     [[NSProcessInfo processInfo] enableSuddenTermination];
809 #endif
810 }
811
812 void WebChromeClient::disableSuddenTermination()
813 {
814 #if !PLATFORM(IOS)
815     [[NSProcessInfo processInfo] disableSuddenTermination];
816 #endif
817 }
818
819 bool WebChromeClient::shouldReplaceWithGeneratedFileForUpload(const String& path, String& generatedFilename)
820 {
821     NSString* filename;
822     if (![[m_webView _UIDelegateForwarder] webView:m_webView shouldReplaceUploadFile:path usingGeneratedFilename:&filename])
823         return false;
824     generatedFilename = filename;
825     return true;
826 }
827
828 String WebChromeClient::generateReplacementFile(const String& path)
829 {
830     return [[m_webView _UIDelegateForwarder] webView:m_webView generateReplacementFile:path];
831 }
832
833 void WebChromeClient::elementDidFocus(const WebCore::Node* node)
834 {
835     CallUIDelegate(m_webView, @selector(webView:formDidFocusNode:), kit(const_cast<WebCore::Node*>(node)));
836 }
837
838 void WebChromeClient::elementDidBlur(const WebCore::Node* node)
839 {
840     CallUIDelegate(m_webView, @selector(webView:formDidBlurNode:), kit(const_cast<WebCore::Node*>(node)));
841 }
842
843 bool WebChromeClient::selectItemWritingDirectionIsNatural()
844 {
845     return false;
846 }
847
848 bool WebChromeClient::selectItemAlignmentFollowsMenuWritingDirection()
849 {
850     return true;
851 }
852
853 bool WebChromeClient::hasOpenedPopup() const
854 {
855     notImplemented();
856     return false;
857 }
858
859 PassRefPtr<WebCore::PopupMenu> WebChromeClient::createPopupMenu(WebCore::PopupMenuClient* client) const
860 {
861 #if !PLATFORM(IOS)
862     return adoptRef(new PopupMenuMac(client));
863 #else
864     return nullptr;
865 #endif
866 }
867
868 PassRefPtr<WebCore::SearchPopupMenu> WebChromeClient::createSearchPopupMenu(WebCore::PopupMenuClient* client) const
869 {
870 #if !PLATFORM(IOS)
871     return adoptRef(new SearchPopupMenuMac(client));
872 #else
873     return nullptr;
874 #endif
875 }
876
877 bool WebChromeClient::shouldPaintEntireContents() const
878 {
879 #if PLATFORM(IOS)
880     return false;
881 #else
882     NSView *documentView = [[[m_webView mainFrame] frameView] documentView];
883     return [documentView layer];
884 #endif
885 }
886
887 void WebChromeClient::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* graphicsLayer)
888 {
889     BEGIN_BLOCK_OBJC_EXCEPTIONS;
890
891     NSView *documentView = [[kit(frame) frameView] documentView];
892     if (![documentView isKindOfClass:[WebHTMLView class]]) {
893         // We should never be attaching when we don't have a WebHTMLView.
894         ASSERT(!graphicsLayer);
895         return;
896     }
897
898     WebHTMLView *webHTMLView = (WebHTMLView *)documentView;
899     if (graphicsLayer)
900         [webHTMLView attachRootLayer:graphicsLayer->platformLayer()];
901     else
902         [webHTMLView detachRootLayer];
903     END_BLOCK_OBJC_EXCEPTIONS;
904 }
905
906 void WebChromeClient::attachViewOverlayGraphicsLayer(Frame*, GraphicsLayer*)
907 {
908     // FIXME: If we want view-relative page overlays in Legacy WebKit, this would be the place to hook them up.
909 }
910
911 void WebChromeClient::setNeedsOneShotDrawingSynchronization()
912 {
913     BEGIN_BLOCK_OBJC_EXCEPTIONS;
914     [m_webView _setNeedsOneShotDrawingSynchronization:YES];
915     END_BLOCK_OBJC_EXCEPTIONS;
916 }
917
918 void WebChromeClient::scheduleCompositingLayerFlush()
919 {
920     BEGIN_BLOCK_OBJC_EXCEPTIONS;
921     [m_webView _scheduleCompositingLayerFlush];
922     END_BLOCK_OBJC_EXCEPTIONS;
923 }
924
925 #if ENABLE(VIDEO)
926
927 bool WebChromeClient::supportsVideoFullscreen()
928 {
929 #if PLATFORM(IOS)
930     if (!Settings::avKitEnabled())
931         return false;
932 #endif
933     return true;
934 }
935
936 void WebChromeClient::enterVideoFullscreenForVideoElement(HTMLVideoElement& videoElement, HTMLMediaElement::VideoFullscreenMode mode)
937 {
938     ASSERT(mode != HTMLMediaElement::VideoFullscreenModeNone);
939     BEGIN_BLOCK_OBJC_EXCEPTIONS;
940     [m_webView _enterVideoFullscreenForVideoElement:&videoElement mode:mode];
941     END_BLOCK_OBJC_EXCEPTIONS;
942 }
943
944 void WebChromeClient::exitVideoFullscreenForVideoElement(WebCore::HTMLVideoElement&)
945 {
946     BEGIN_BLOCK_OBJC_EXCEPTIONS;
947     [m_webView _exitVideoFullscreen];
948     END_BLOCK_OBJC_EXCEPTIONS;    
949 }
950
951 #endif
952
953 #if ENABLE(FULLSCREEN_API)
954
955 bool WebChromeClient::supportsFullScreenForElement(const Element* element, bool withKeyboard)
956 {
957     SEL selector = @selector(webView:supportsFullScreenForElement:withKeyboard:);
958     if ([[m_webView UIDelegate] respondsToSelector:selector])
959         return CallUIDelegateReturningBoolean(false, m_webView, selector, kit(const_cast<WebCore::Element*>(element)), withKeyboard);
960 #if !PLATFORM(IOS)
961     return [m_webView _supportsFullScreenForElement:const_cast<WebCore::Element*>(element) withKeyboard:withKeyboard];
962 #else
963     return NO;
964 #endif
965 }
966
967 void WebChromeClient::enterFullScreenForElement(Element* element)
968 {
969     SEL selector = @selector(webView:enterFullScreenForElement:listener:);
970     if ([[m_webView UIDelegate] respondsToSelector:selector]) {
971         WebKitFullScreenListener* listener = [[WebKitFullScreenListener alloc] initWithElement:element];
972         CallUIDelegate(m_webView, selector, kit(element), listener);
973         [listener release];
974     }
975 #if !PLATFORM(IOS)
976     else
977         [m_webView _enterFullScreenForElement:element];
978 #endif
979 }
980
981 void WebChromeClient::exitFullScreenForElement(Element* element)
982 {
983     SEL selector = @selector(webView:exitFullScreenForElement:listener:);
984     if ([[m_webView UIDelegate] respondsToSelector:selector]) {
985         WebKitFullScreenListener* listener = [[WebKitFullScreenListener alloc] initWithElement:element];
986         CallUIDelegate(m_webView, selector, kit(element), listener);
987         [listener release];
988     }
989 #if !PLATFORM(IOS)
990     else
991         [m_webView _exitFullScreenForElement:element];
992 #endif
993 }
994
995 #endif // ENABLE(FULLSCREEN_API)
996
997 #if ENABLE(SUBTLE_CRYPTO)
998 bool WebChromeClient::wrapCryptoKey(const Vector<uint8_t>& key, Vector<uint8_t>& wrappedKey) const
999 {
1000     Vector<uint8_t> masterKey;
1001     SEL selector = @selector(webCryptoMasterKeyForWebView:);
1002     if ([[m_webView UIDelegate] respondsToSelector:selector]) {
1003         NSData *keyData = CallUIDelegate(m_webView, selector);
1004         masterKey.append((uint8_t*)[keyData bytes], [keyData length]);
1005     } else if (!getDefaultWebCryptoMasterKey(masterKey))
1006         return false;
1007
1008     return wrapSerializedCryptoKey(masterKey, key, wrappedKey);
1009 }
1010
1011 bool WebChromeClient::unwrapCryptoKey(const Vector<uint8_t>& wrappedKey, Vector<uint8_t>& key) const
1012 {
1013     Vector<uint8_t> masterKey;
1014     SEL selector = @selector(webCryptoMasterKeyForWebView:);
1015     if ([[m_webView UIDelegate] respondsToSelector:selector]) {
1016         NSData *keyData = CallUIDelegate(m_webView, selector);
1017         masterKey.append((uint8_t*)[keyData bytes], [keyData length]);
1018     } else if (!getDefaultWebCryptoMasterKey(masterKey))
1019         return false;
1020
1021     return unwrapSerializedCryptoKey(masterKey, wrappedKey, key);
1022 }
1023 #endif
1024
1025 #if ENABLE(SERVICE_CONTROLS)
1026 void WebChromeClient::handleSelectionServiceClick(WebCore::FrameSelection& selection, const Vector<String>& telephoneNumbers, const WebCore::IntPoint& point)
1027 {
1028     [m_webView _selectionServiceController].handleSelectionServiceClick(selection, telephoneNumbers, point);
1029 }
1030
1031 bool WebChromeClient::hasRelevantSelectionServices(bool isTextOnly) const
1032 {
1033     return [m_webView _selectionServiceController].hasRelevantSelectionServices(isTextOnly);
1034 }
1035
1036 #endif
1037
1038 #if ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS)
1039 void WebChromeClient::addPlaybackTargetPickerClient(uint64_t contextId)
1040 {
1041     [m_webView _addPlaybackTargetPickerClient:contextId];
1042 }
1043
1044 void WebChromeClient::removePlaybackTargetPickerClient(uint64_t contextId)
1045 {
1046     [m_webView _removePlaybackTargetPickerClient:contextId];
1047 }
1048
1049 void WebChromeClient::showPlaybackTargetPicker(uint64_t contextId, const WebCore::IntPoint& location, bool hasVideo)
1050 {
1051     [m_webView _showPlaybackTargetPicker:contextId location:location hasVideo:hasVideo];
1052 }
1053
1054 void WebChromeClient::playbackTargetPickerClientStateDidChange(uint64_t contextId, MediaProducer::MediaStateFlags state)
1055 {
1056     [m_webView _playbackTargetPickerClientStateDidChange:contextId state:state];
1057 }
1058 #endif