Move URL from WebCore to WTF
[WebKit-https.git] / Source / WebKitLegacy / mac / WebCoreSupport / WebChromeClient.mm
1 /*
2  * Copyright (C) 2006-2017 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 "DOMHTMLInputElementInternal.h"
34 #import "DOMNodeInternal.h"
35 #import "PopupMenuMac.h"
36 #import "SearchPopupMenuMac.h"
37 #import "WebBasePluginPackage.h"
38 #import "WebDefaultUIDelegate.h"
39 #import "WebDelegateImplementationCaching.h"
40 #import "WebElementDictionary.h"
41 #import "WebFormDelegate.h"
42 #import "WebFrameInternal.h"
43 #import "WebFrameView.h"
44 #import "WebHTMLViewInternal.h"
45 #import "WebHistoryInternal.h"
46 #import "WebKitFullScreenListener.h"
47 #import "WebKitPrefix.h"
48 #import "WebNSURLRequestExtras.h"
49 #import "WebOpenPanelResultListener.h"
50 #import "WebPlugin.h"
51 #import "WebQuotaManager.h"
52 #import "WebSecurityOriginInternal.h"
53 #import "WebSelectionServiceController.h"
54 #import "WebUIDelegatePrivate.h"
55 #import "WebView.h"
56 #import "WebViewInternal.h"
57 #import <Foundation/Foundation.h>
58 #import <WebCore/ColorChooser.h>
59 #import <WebCore/ContextMenu.h>
60 #import <WebCore/ContextMenuController.h>
61 #import <WebCore/Cursor.h>
62 #import <WebCore/DataListSuggestionPicker.h>
63 #import <WebCore/DeprecatedGlobalSettings.h>
64 #import <WebCore/Element.h>
65 #import <WebCore/FileChooser.h>
66 #import <WebCore/FileIconLoader.h>
67 #import <WebCore/FloatRect.h>
68 #import <WebCore/Frame.h>
69 #import <WebCore/FrameLoadRequest.h>
70 #import <WebCore/FrameView.h>
71 #import <WebCore/GraphicsLayer.h>
72 #import <WebCore/HTMLInputElement.h>
73 #import <WebCore/HTMLNames.h>
74 #import <WebCore/HTMLPlugInImageElement.h>
75 #import <WebCore/HitTestResult.h>
76 #import <WebCore/Icon.h>
77 #import <WebCore/IntPoint.h>
78 #import <WebCore/IntRect.h>
79 #import <WebCore/NavigationAction.h>
80 #import <WebCore/NotImplemented.h>
81 #import <WebCore/Page.h>
82 #import <WebCore/PlatformScreen.h>
83 #import <WebCore/ResourceRequest.h>
84 #import <WebCore/SSLKeyGenerator.h>
85 #import <WebCore/SerializedCryptoKeyWrap.h>
86 #import <WebCore/Widget.h>
87 #import <WebCore/WindowFeatures.h>
88 #import <wtf/BlockObjCExceptions.h>
89 #import <wtf/RefPtr.h>
90 #import <wtf/Vector.h>
91 #import <wtf/text/WTFString.h>
92
93 #if USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API)
94 #import "NetscapePluginHostManager.h"
95 #endif
96
97 #if PLATFORM(IOS_FAMILY) && ENABLE(GEOLOCATION)
98 #import <WebCore/Geolocation.h>
99 #endif
100
101 #if ENABLE(POINTER_LOCK)
102 #import <WebCore/PointerLockController.h>
103 #endif
104
105 #if PLATFORM(IOS_FAMILY)
106 #import <WebCore/WAKClipView.h>
107 #import <WebCore/WAKWindow.h>
108 #import <WebCore/WebCoreThreadMessage.h>
109 #endif
110
111 NSString *WebConsoleMessageXMLMessageSource = @"XMLMessageSource";
112 NSString *WebConsoleMessageJSMessageSource = @"JSMessageSource";
113 NSString *WebConsoleMessageNetworkMessageSource = @"NetworkMessageSource";
114 NSString *WebConsoleMessageConsoleAPIMessageSource = @"ConsoleAPIMessageSource";
115 NSString *WebConsoleMessageStorageMessageSource = @"StorageMessageSource";
116 NSString *WebConsoleMessageAppCacheMessageSource = @"AppCacheMessageSource";
117 NSString *WebConsoleMessageRenderingMessageSource = @"RenderingMessageSource";
118 NSString *WebConsoleMessageCSSMessageSource = @"CSSMessageSource";
119 NSString *WebConsoleMessageSecurityMessageSource = @"SecurityMessageSource";
120 NSString *WebConsoleMessageContentBlockerMessageSource = @"ContentBlockerMessageSource";
121 NSString *WebConsoleMessageOtherMessageSource = @"OtherMessageSource";
122 NSString *WebConsoleMessageMediaMessageSource = @"MediaMessageSource";
123 NSString *WebConsoleMessageWebRTCMessageSource = @"WebRTCMessageSource";
124
125 NSString *WebConsoleMessageDebugMessageLevel = @"DebugMessageLevel";
126 NSString *WebConsoleMessageLogMessageLevel = @"LogMessageLevel";
127 NSString *WebConsoleMessageInfoMessageLevel = @"InfoMessageLevel";
128 NSString *WebConsoleMessageWarningMessageLevel = @"WarningMessageLevel";
129 NSString *WebConsoleMessageErrorMessageLevel = @"ErrorMessageLevel";
130
131
132 #if !PLATFORM(IOS_FAMILY)
133 @interface NSApplication (WebNSApplicationDetails)
134 - (NSCursor *)_cursorRectCursor;
135 @end
136 #endif
137
138 @interface NSView (WebNSViewDetails)
139 - (NSView *)_findLastViewInKeyViewLoop;
140 @end
141
142 // For compatibility with old SPI.
143 @interface NSView (WebOldWebKitPlugInDetails)
144 - (void)setIsSelected:(BOOL)isSelected;
145 @end
146
147 using namespace WebCore;
148 using namespace HTMLNames;
149
150 WebChromeClient::WebChromeClient(WebView *webView) 
151     : m_webView(webView)
152 {
153 }
154
155 void WebChromeClient::chromeDestroyed()
156 {
157     delete this;
158 }
159
160 // These functions scale between window and WebView coordinates because JavaScript/DOM operations 
161 // assume that the WebView and the window share the same coordinate system.
162
163 void WebChromeClient::setWindowRect(const FloatRect& rect)
164 {
165 #if !PLATFORM(IOS_FAMILY)
166     NSRect windowRect = toDeviceSpace(rect, [m_webView window]);
167     [[m_webView _UIDelegateForwarder] webView:m_webView setFrame:windowRect];
168 #endif
169 }
170
171 FloatRect WebChromeClient::windowRect()
172 {
173 #if !PLATFORM(IOS_FAMILY)
174     NSRect windowRect = [[m_webView _UIDelegateForwarder] webViewFrame:m_webView];
175     return toUserSpace(windowRect, [m_webView window]);
176 #else
177     return FloatRect();
178 #endif
179 }
180
181 // FIXME: We need to add API for setting and getting this.
182 FloatRect WebChromeClient::pageRect()
183 {
184     return [m_webView frame];
185 }
186
187 void WebChromeClient::focus()
188 {
189     [[m_webView _UIDelegateForwarder] webViewFocus:m_webView];
190 }
191
192 void WebChromeClient::unfocus()
193 {
194     [[m_webView _UIDelegateForwarder] webViewUnfocus:m_webView];
195 }
196
197 bool WebChromeClient::canTakeFocus(FocusDirection)
198 {
199     // There's unfortunately no way to determine if we will become first responder again
200     // once we give it up, so we just have to guess that we won't.
201     return true;
202 }
203
204 void WebChromeClient::takeFocus(FocusDirection direction)
205 {
206 #if !PLATFORM(IOS_FAMILY)
207     if (direction == FocusDirectionForward) {
208         // Since we're trying to move focus out of m_webView, and because
209         // m_webView may contain subviews within it, we ask it for the next key
210         // view of the last view in its key view loop. This makes m_webView
211         // behave as if it had no subviews, which is the behavior we want.
212         NSView *lastView = [m_webView _findLastViewInKeyViewLoop];
213         // avoid triggering assertions if the WebView is the only thing in the key loop
214         if ([m_webView _becomingFirstResponderFromOutside] && m_webView == [lastView nextValidKeyView])
215             return;
216         [[m_webView window] selectKeyViewFollowingView:lastView];
217     } else {
218         // avoid triggering assertions if the WebView is the only thing in the key loop
219         if ([m_webView _becomingFirstResponderFromOutside] && m_webView == [m_webView previousValidKeyView])
220             return;
221         [[m_webView window] selectKeyViewPrecedingView:m_webView];
222     }
223 #endif
224 }
225
226 void WebChromeClient::focusedElementChanged(Element* element)
227 {
228     if (!is<HTMLInputElement>(element))
229         return;
230
231     auto& inputElement = downcast<HTMLInputElement>(*element);
232     if (!inputElement.isText())
233         return;
234
235     CallFormDelegate(m_webView, @selector(didFocusTextField:inFrame:), kit(&inputElement), kit(inputElement.document().frame()));
236 }
237
238 void WebChromeClient::focusedFrameChanged(Frame*)
239 {
240 }
241
242 Page* WebChromeClient::createWindow(Frame& frame, const FrameLoadRequest&, const WindowFeatures& features, const NavigationAction&)
243 {
244     id delegate = [m_webView UIDelegate];
245     WebView *newWebView;
246
247 #if ENABLE(FULLSCREEN_API)
248     if (frame.document() && frame.document()->webkitCurrentFullScreenElement())
249         frame.document()->webkitCancelFullScreen();
250 #endif
251     
252     if ([delegate respondsToSelector:@selector(webView:createWebViewWithRequest:windowFeatures:)]) {
253         NSNumber *x = features.x ? [[NSNumber alloc] initWithFloat:*features.x] : nil;
254         NSNumber *y = features.y ? [[NSNumber alloc] initWithFloat:*features.y] : nil;
255         NSNumber *width = features.width ? [[NSNumber alloc] initWithFloat:*features.width] : nil;
256         NSNumber *height = features.height ? [[NSNumber alloc] initWithFloat:*features.height] : nil;
257         NSNumber *menuBarVisible = [[NSNumber alloc] initWithBool:features.menuBarVisible];
258         NSNumber *statusBarVisible = [[NSNumber alloc] initWithBool:features.statusBarVisible];
259         NSNumber *toolBarVisible = [[NSNumber alloc] initWithBool:features.toolBarVisible];
260         NSNumber *scrollbarsVisible = [[NSNumber alloc] initWithBool:features.scrollbarsVisible];
261         NSNumber *resizable = [[NSNumber alloc] initWithBool:features.resizable];
262         NSNumber *fullscreen = [[NSNumber alloc] initWithBool:features.fullscreen];
263         NSNumber *dialog = [[NSNumber alloc] initWithBool:features.dialog];
264         
265         NSMutableDictionary *dictFeatures = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
266                                              menuBarVisible, @"menuBarVisible", 
267                                              statusBarVisible, @"statusBarVisible",
268                                              toolBarVisible, @"toolBarVisible",
269                                              scrollbarsVisible, @"scrollbarsVisible",
270                                              resizable, @"resizable",
271                                              fullscreen, @"fullscreen",
272                                              dialog, @"dialog",
273                                              nil];
274         
275         if (x)
276             [dictFeatures setObject:x forKey:@"x"];
277         if (y)
278             [dictFeatures setObject:y forKey:@"y"];
279         if (width)
280             [dictFeatures setObject:width forKey:@"width"];
281         if (height)
282             [dictFeatures setObject:height forKey:@"height"];
283         
284         newWebView = CallUIDelegate(m_webView, @selector(webView:createWebViewWithRequest:windowFeatures:), nil, dictFeatures);
285         
286         [dictFeatures release];
287         [x release];
288         [y release];
289         [width release];
290         [height release];
291         [menuBarVisible release];
292         [statusBarVisible release];
293         [toolBarVisible release];
294         [scrollbarsVisible release];
295         [resizable release];
296         [fullscreen release];
297         [dialog release];
298     } else if (features.dialog && [delegate respondsToSelector:@selector(webView:createWebViewModalDialogWithRequest:)]) {
299         newWebView = CallUIDelegate(m_webView, @selector(webView:createWebViewModalDialogWithRequest:), nil);
300     } else {
301         newWebView = CallUIDelegate(m_webView, @selector(webView:createWebViewWithRequest:), nil);
302     }
303
304 #if USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API)
305     if (newWebView)
306         WebKit::NetscapePluginHostManager::singleton().didCreateWindow();
307 #endif
308     
309     return core(newWebView);
310 }
311
312 void WebChromeClient::show()
313 {
314     [[m_webView _UIDelegateForwarder] webViewShow:m_webView];
315 }
316
317 bool WebChromeClient::canRunModal()
318 {
319     return [[m_webView UIDelegate] respondsToSelector:@selector(webViewRunModal:)];
320 }
321
322 void WebChromeClient::runModal()
323 {
324     CallUIDelegate(m_webView, @selector(webViewRunModal:));
325 }
326
327 void WebChromeClient::setToolbarsVisible(bool b)
328 {
329     [[m_webView _UIDelegateForwarder] webView:m_webView setToolbarsVisible:b];
330 }
331
332 bool WebChromeClient::toolbarsVisible()
333 {
334     return CallUIDelegateReturningBoolean(NO, m_webView, @selector(webViewAreToolbarsVisible:));
335 }
336
337 void WebChromeClient::setStatusbarVisible(bool b)
338 {
339     [[m_webView _UIDelegateForwarder] webView:m_webView setStatusBarVisible:b];
340 }
341
342 bool WebChromeClient::statusbarVisible()
343 {
344     return CallUIDelegateReturningBoolean(NO, m_webView, @selector(webViewIsStatusBarVisible:));
345 }
346
347 void WebChromeClient::setScrollbarsVisible(bool b)
348 {
349     [[[m_webView mainFrame] frameView] setAllowsScrolling:b];
350 }
351
352 bool WebChromeClient::scrollbarsVisible()
353 {
354     return [[[m_webView mainFrame] frameView] allowsScrolling];
355 }
356
357 void WebChromeClient::setMenubarVisible(bool)
358 {
359     // The menubar is always visible in Mac OS X.
360     return;
361 }
362
363 bool WebChromeClient::menubarVisible()
364 {
365     // The menubar is always visible in Mac OS X.
366     return true;
367 }
368
369 void WebChromeClient::setResizable(bool b)
370 {
371     [[m_webView _UIDelegateForwarder] webView:m_webView setResizable:b];
372 }
373
374 inline static NSString *stringForMessageSource(MessageSource source)
375 {
376     switch (source) {
377     case MessageSource::XML:
378         return WebConsoleMessageXMLMessageSource;
379     case MessageSource::JS:
380         return WebConsoleMessageJSMessageSource;
381     case MessageSource::Network:
382         return WebConsoleMessageNetworkMessageSource;
383     case MessageSource::ConsoleAPI:
384         return WebConsoleMessageConsoleAPIMessageSource;
385     case MessageSource::Storage:
386         return WebConsoleMessageStorageMessageSource;
387     case MessageSource::AppCache:
388         return WebConsoleMessageAppCacheMessageSource;
389     case MessageSource::Rendering:
390         return WebConsoleMessageRenderingMessageSource;
391     case MessageSource::CSS:
392         return WebConsoleMessageCSSMessageSource;
393     case MessageSource::Security:
394         return WebConsoleMessageSecurityMessageSource;
395     case MessageSource::ContentBlocker:
396         return WebConsoleMessageContentBlockerMessageSource;
397     case MessageSource::Other:
398         return WebConsoleMessageOtherMessageSource;
399     case MessageSource::Media:
400         return WebConsoleMessageMediaMessageSource;
401     case MessageSource::WebRTC:
402         return WebConsoleMessageWebRTCMessageSource;
403     }
404     ASSERT_NOT_REACHED();
405     return @"";
406 }
407
408 inline static NSString *stringForMessageLevel(MessageLevel level)
409 {
410     switch (level) {
411     case MessageLevel::Debug:
412         return WebConsoleMessageDebugMessageLevel;
413     case MessageLevel::Log:
414         return WebConsoleMessageLogMessageLevel;
415     case MessageLevel::Info:
416         return WebConsoleMessageInfoMessageLevel;
417     case MessageLevel::Warning:
418         return WebConsoleMessageWarningMessageLevel;
419     case MessageLevel::Error:
420         return WebConsoleMessageErrorMessageLevel;
421     }
422     ASSERT_NOT_REACHED();
423     return @"";
424 }
425
426 void WebChromeClient::addMessageToConsole(MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, unsigned columnNumber, const String& sourceURL)
427 {
428 #if !PLATFORM(IOS_FAMILY)
429     id delegate = [m_webView UIDelegate];
430 #else
431     if (![m_webView _allowsMessaging])
432         return;
433
434     id delegate = [m_webView _UIKitDelegate];
435     // No delegate means nothing to send this data to so bail.
436     if (!delegate)
437         return;
438 #endif
439
440     BOOL respondsToNewSelector = NO;
441
442     SEL selector = @selector(webView:addMessageToConsole:withSource:);
443     if ([delegate respondsToSelector:selector])
444         respondsToNewSelector = YES;
445     else {
446         // The old selector only takes JSMessageSource messages.
447         if (source != MessageSource::JS)
448             return;
449         selector = @selector(webView:addMessageToConsole:);
450         if (![delegate respondsToSelector:selector])
451             return;
452     }
453
454     NSString *messageSource = stringForMessageSource(source);
455     NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:
456         (NSString *)message, @"message",
457         [NSNumber numberWithUnsignedInt:lineNumber], @"lineNumber",
458         [NSNumber numberWithUnsignedInt:columnNumber], @"columnNumber",
459         (NSString *)sourceURL, @"sourceURL",
460         messageSource, @"MessageSource",
461         stringForMessageLevel(level), @"MessageLevel",
462         NULL];
463
464 #if PLATFORM(IOS_FAMILY)
465     [[[m_webView _UIKitDelegateForwarder] asyncForwarder] webView:m_webView addMessageToConsole:dictionary withSource:messageSource];
466 #else
467     if (respondsToNewSelector)
468         CallUIDelegate(m_webView, selector, dictionary, messageSource);
469     else
470         CallUIDelegate(m_webView, selector, dictionary);
471 #endif
472
473     [dictionary release];
474 }
475
476 bool WebChromeClient::canRunBeforeUnloadConfirmPanel()
477 {
478     return [[m_webView UIDelegate] respondsToSelector:@selector(webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:)];
479 }
480
481 bool WebChromeClient::runBeforeUnloadConfirmPanel(const String& message, Frame& frame)
482 {
483     return CallUIDelegateReturningBoolean(true, m_webView, @selector(webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:), message, kit(&frame));
484 }
485
486 void WebChromeClient::closeWindowSoon()
487 {
488     // We need to remove the parent WebView from WebViewSets here, before it actually
489     // closes, to make sure that JavaScript code that executes before it closes
490     // can't find it. Otherwise, window.open will select a closed WebView instead of 
491     // opening a new one <rdar://problem/3572585>.
492
493     // We also need to stop the load to prevent further parsing or JavaScript execution
494     // after the window has torn down <rdar://problem/4161660>.
495   
496     // FIXME: This code assumes that the UI delegate will respond to a webViewClose
497     // message by actually closing the WebView. Safari guarantees this behavior, but other apps might not.
498     // This approach is an inherent limitation of not making a close execute immediately
499     // after a call to window.close.
500
501     [m_webView setGroupName:nil];
502     [m_webView stopLoading:nil];
503     [m_webView performSelector:@selector(_closeWindow) withObject:nil afterDelay:0.0];
504 }
505
506 void WebChromeClient::runJavaScriptAlert(Frame& frame, const String& message)
507 {
508     id delegate = [m_webView UIDelegate];
509     SEL selector = @selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:);
510     if ([delegate respondsToSelector:selector]) {
511         CallUIDelegate(m_webView, selector, message, kit(&frame));
512         return;
513     }
514
515     // Call the old version of the delegate method if it is implemented.
516     selector = @selector(webView:runJavaScriptAlertPanelWithMessage:);
517     if ([delegate respondsToSelector:selector]) {
518         CallUIDelegate(m_webView, selector, message);
519         return;
520     }
521 }
522
523 bool WebChromeClient::runJavaScriptConfirm(Frame& frame, const String& message)
524 {
525     id delegate = [m_webView UIDelegate];
526     SEL selector = @selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:);
527     if ([delegate respondsToSelector:selector])
528         return CallUIDelegateReturningBoolean(NO, m_webView, selector, message, kit(&frame));
529
530     // Call the old version of the delegate method if it is implemented.
531     selector = @selector(webView:runJavaScriptConfirmPanelWithMessage:);
532     if ([delegate respondsToSelector:selector])
533         return CallUIDelegateReturningBoolean(NO, m_webView, selector, message);
534
535     return NO;
536 }
537
538 bool WebChromeClient::runJavaScriptPrompt(Frame& frame, const String& prompt, const String& defaultText, String& result)
539 {
540     id delegate = [m_webView UIDelegate];
541     SEL selector = @selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:);
542     NSString *defaultString = defaultText;
543     if ([delegate respondsToSelector:selector]) {
544         result = (NSString *)CallUIDelegate(m_webView, selector, prompt, defaultString, kit(&frame));
545         return !result.isNull();
546     }
547
548     // Call the old version of the delegate method if it is implemented.
549     selector = @selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:);
550     if ([delegate respondsToSelector:selector]) {
551         result = (NSString *)CallUIDelegate(m_webView, selector, prompt, defaultString);
552         return !result.isNull();
553     }
554
555     result = [[WebDefaultUIDelegate sharedUIDelegate] webView:m_webView runJavaScriptTextInputPanelWithPrompt:prompt defaultText:defaultString initiatedByFrame:kit(&frame)];
556     return !result.isNull();
557 }
558
559 void WebChromeClient::setStatusbarText(const String& status)
560 {
561     // We want the temporaries allocated here to be released even before returning to the 
562     // event loop; see <http://bugs.webkit.org/show_bug.cgi?id=9880>.
563     @autoreleasepool {
564         CallUIDelegate(m_webView, @selector(webView:setStatusText:), (NSString *)status);
565     }
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_FAMILY)
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
719 std::unique_ptr<ColorChooser> WebChromeClient::createColorChooser(ColorChooserClient& client, const Color& initialColor)
720 {
721     // FIXME: Implement <input type='color'> for WK1 (Bug 119094).
722     ASSERT_NOT_REACHED();
723     return nullptr;
724 }
725
726 #endif
727
728 #if ENABLE(DATALIST_ELEMENT)
729 std::unique_ptr<DataListSuggestionPicker> WebChromeClient::createDataListSuggestionPicker(DataListSuggestionsClient& client)
730 {
731     ASSERT_NOT_REACHED();
732     return nullptr;
733 }
734 #endif
735
736 #if ENABLE(POINTER_LOCK)
737 bool WebChromeClient::requestPointerLock()
738 {
739 #if PLATFORM(MAC)
740     if (![m_webView page])
741         return false;
742
743     CGDisplayHideCursor(CGMainDisplayID());
744     CGAssociateMouseAndMouseCursorPosition(false);
745     [m_webView page]->pointerLockController().didAcquirePointerLock();
746     
747     return true;
748 #else
749     return false;
750 #endif
751 }
752
753 void WebChromeClient::requestPointerUnlock()
754 {
755 #if PLATFORM(MAC)
756     CGAssociateMouseAndMouseCursorPosition(true);
757     CGDisplayShowCursor(CGMainDisplayID());
758     if ([m_webView page])
759         [m_webView page]->pointerLockController().didLosePointerLock();
760 #endif
761 }
762 #endif
763
764 void WebChromeClient::runOpenPanel(Frame&, FileChooser& chooser)
765 {
766     BEGIN_BLOCK_OBJC_EXCEPTIONS;
767     BOOL allowMultipleFiles = chooser.settings().allowsMultipleFiles;
768     WebOpenPanelResultListener *listener = [[WebOpenPanelResultListener alloc] initWithChooser:chooser];
769     id delegate = [m_webView UIDelegate];
770     if ([delegate respondsToSelector:@selector(webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:)])
771         CallUIDelegate(m_webView, @selector(webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:), listener, allowMultipleFiles);
772     else if ([delegate respondsToSelector:@selector(webView:runOpenPanelForFileButtonWithResultListener:)])
773         CallUIDelegate(m_webView, @selector(webView:runOpenPanelForFileButtonWithResultListener:), listener);
774     else
775         [listener cancel];
776     [listener release];
777     END_BLOCK_OBJC_EXCEPTIONS;
778 }
779
780 void WebChromeClient::showShareSheet(ShareDataWithParsedURL&, CompletionHandler<void(bool)>&&)
781 {
782 }
783
784 void WebChromeClient::loadIconForFiles(const Vector<String>& filenames, FileIconLoader& iconLoader)
785 {
786     iconLoader.iconLoaded(createIconForFiles(filenames));
787 }
788
789 RefPtr<Icon> WebChromeClient::createIconForFiles(const Vector<String>& filenames)
790 {
791     return Icon::createIconForFiles(filenames);
792 }
793
794 #if !PLATFORM(IOS_FAMILY)
795
796 void WebChromeClient::setCursor(const WebCore::Cursor& cursor)
797 {
798     // FIXME: Would be nice to share this code with WebKit2's PageClientImpl.
799
800     if ([NSApp _cursorRectCursor])
801         return;
802
803     if (!m_webView)
804         return;
805
806     NSWindow *window = [m_webView window];
807     if (!window)
808         return;
809
810     if ([window windowNumber] != [NSWindow windowNumberAtPoint:[NSEvent mouseLocation] belowWindowWithWindowNumber:0])
811         return;
812
813     NSCursor *platformCursor = cursor.platformCursor();
814     if ([NSCursor currentCursor] == platformCursor)
815         return;
816
817     [platformCursor set];
818 }
819
820 void WebChromeClient::setCursorHiddenUntilMouseMoves(bool hiddenUntilMouseMoves)
821 {
822     [NSCursor setHiddenUntilMouseMoves:hiddenUntilMouseMoves];
823 }
824
825 #endif
826
827 KeyboardUIMode WebChromeClient::keyboardUIMode()
828 {
829     BEGIN_BLOCK_OBJC_EXCEPTIONS;
830     return [m_webView _keyboardUIMode];
831     END_BLOCK_OBJC_EXCEPTIONS;
832     return KeyboardAccessDefault;
833 }
834
835 NSResponder *WebChromeClient::firstResponder()
836 {
837     BEGIN_BLOCK_OBJC_EXCEPTIONS;
838     return [[m_webView _UIDelegateForwarder] webViewFirstResponder:m_webView];
839     END_BLOCK_OBJC_EXCEPTIONS;
840     return nil;
841 }
842
843 void WebChromeClient::makeFirstResponder(NSResponder *responder)
844 {
845     BEGIN_BLOCK_OBJC_EXCEPTIONS;
846     [m_webView _pushPerformingProgrammaticFocus];
847     [[m_webView _UIDelegateForwarder] webView:m_webView makeFirstResponder:responder];
848     [m_webView _popPerformingProgrammaticFocus];
849     END_BLOCK_OBJC_EXCEPTIONS;
850 }
851
852 void WebChromeClient::enableSuddenTermination()
853 {
854 #if !PLATFORM(IOS_FAMILY)
855     [[NSProcessInfo processInfo] enableSuddenTermination];
856 #endif
857 }
858
859 void WebChromeClient::disableSuddenTermination()
860 {
861 #if !PLATFORM(IOS_FAMILY)
862     [[NSProcessInfo processInfo] disableSuddenTermination];
863 #endif
864 }
865
866 bool WebChromeClient::shouldReplaceWithGeneratedFileForUpload(const String& path, String& generatedFilename)
867 {
868     NSString* filename;
869     if (![[m_webView _UIDelegateForwarder] webView:m_webView shouldReplaceUploadFile:path usingGeneratedFilename:&filename])
870         return false;
871     generatedFilename = filename;
872     return true;
873 }
874
875 String WebChromeClient::generateReplacementFile(const String& path)
876 {
877     return [[m_webView _UIDelegateForwarder] webView:m_webView generateReplacementFile:path];
878 }
879
880 #if !PLATFORM(IOS_FAMILY)
881 void WebChromeClient::elementDidFocus(WebCore::Element& element)
882 {
883     CallUIDelegate(m_webView, @selector(webView:formDidFocusNode:), kit(&element));
884 }
885
886 void WebChromeClient::elementDidBlur(WebCore::Element& element)
887 {
888     CallUIDelegate(m_webView, @selector(webView:formDidBlurNode:), kit(&element));
889 }
890 #endif
891
892 bool WebChromeClient::selectItemWritingDirectionIsNatural()
893 {
894     return false;
895 }
896
897 bool WebChromeClient::selectItemAlignmentFollowsMenuWritingDirection()
898 {
899     return true;
900 }
901
902 RefPtr<WebCore::PopupMenu> WebChromeClient::createPopupMenu(WebCore::PopupMenuClient& client) const
903 {
904 #if !PLATFORM(IOS_FAMILY)
905     return adoptRef(*new PopupMenuMac(&client));
906 #else
907     return nullptr;
908 #endif
909 }
910
911 RefPtr<WebCore::SearchPopupMenu> WebChromeClient::createSearchPopupMenu(WebCore::PopupMenuClient& client) const
912 {
913 #if !PLATFORM(IOS_FAMILY)
914     return adoptRef(*new SearchPopupMenuMac(&client));
915 #else
916     return nullptr;
917 #endif
918 }
919
920 bool WebChromeClient::shouldPaintEntireContents() const
921 {
922 #if PLATFORM(IOS_FAMILY)
923     return false;
924 #else
925     NSView *documentView = [[[m_webView mainFrame] frameView] documentView];
926     return [documentView layer];
927 #endif
928 }
929
930 void WebChromeClient::attachRootGraphicsLayer(Frame& frame, GraphicsLayer* graphicsLayer)
931 {
932 #if !PLATFORM(MAC)
933     UNUSED_PARAM(frame);
934     UNUSED_PARAM(graphicsLayer);
935 #else
936     BEGIN_BLOCK_OBJC_EXCEPTIONS;
937
938     NSView *documentView = [[kit(&frame) frameView] documentView];
939     if (![documentView isKindOfClass:[WebHTMLView class]]) {
940         // We should never be attaching when we don't have a WebHTMLView.
941         ASSERT(!graphicsLayer);
942         return;
943     }
944
945     WebHTMLView *webHTMLView = (WebHTMLView *)documentView;
946     if (graphicsLayer)
947         [webHTMLView attachRootLayer:graphicsLayer->platformLayer()];
948     else
949         [webHTMLView detachRootLayer];
950     END_BLOCK_OBJC_EXCEPTIONS;
951 #endif
952 }
953
954 void WebChromeClient::attachViewOverlayGraphicsLayer(Frame&, GraphicsLayer*)
955 {
956     // FIXME: If we want view-relative page overlays in Legacy WebKit, this would be the place to hook them up.
957 }
958
959 void WebChromeClient::setNeedsOneShotDrawingSynchronization()
960 {
961     BEGIN_BLOCK_OBJC_EXCEPTIONS;
962     [m_webView _setNeedsOneShotDrawingSynchronization:YES];
963     END_BLOCK_OBJC_EXCEPTIONS;
964 }
965
966 void WebChromeClient::scheduleCompositingLayerFlush()
967 {
968     BEGIN_BLOCK_OBJC_EXCEPTIONS;
969     [m_webView _scheduleCompositingLayerFlush];
970     END_BLOCK_OBJC_EXCEPTIONS;
971 }
972
973 #if ENABLE(VIDEO)
974
975 bool WebChromeClient::supportsVideoFullscreen(HTMLMediaElementEnums::VideoFullscreenMode)
976 {
977 #if PLATFORM(IOS_FAMILY)
978     if (!DeprecatedGlobalSettings::avKitEnabled())
979         return false;
980 #endif
981     return true;
982 }
983
984 void WebChromeClient::enterVideoFullscreenForVideoElement(HTMLVideoElement& videoElement, HTMLMediaElementEnums::VideoFullscreenMode mode, bool standby)
985 {
986     ASSERT_UNUSED(standby, !standby);
987     ASSERT(mode != HTMLMediaElementEnums::VideoFullscreenModeNone);
988     BEGIN_BLOCK_OBJC_EXCEPTIONS;
989     [m_webView _enterVideoFullscreenForVideoElement:&videoElement mode:mode];
990     END_BLOCK_OBJC_EXCEPTIONS;
991 }
992
993 void WebChromeClient::exitVideoFullscreenForVideoElement(WebCore::HTMLVideoElement&)
994 {
995     BEGIN_BLOCK_OBJC_EXCEPTIONS;
996     [m_webView _exitVideoFullscreen];
997     END_BLOCK_OBJC_EXCEPTIONS;    
998 }
999
1000 void WebChromeClient::exitVideoFullscreenToModeWithoutAnimation(HTMLVideoElement& videoElement, HTMLMediaElementEnums::VideoFullscreenMode targetMode)
1001 {
1002     BEGIN_BLOCK_OBJC_EXCEPTIONS;
1003     [m_webView _exitVideoFullscreen];
1004     END_BLOCK_OBJC_EXCEPTIONS;
1005 }
1006
1007 #endif // ENABLE(VIDEO)
1008
1009 #if ENABLE(VIDEO) && PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE)
1010
1011 void WebChromeClient::setUpPlaybackControlsManager(HTMLMediaElement& element)
1012 {
1013     [m_webView _setUpPlaybackControlsManagerForMediaElement:element];
1014 }
1015
1016 void WebChromeClient::clearPlaybackControlsManager()
1017 {
1018     [m_webView _clearPlaybackControlsManager];
1019 }
1020
1021 #endif
1022
1023 #if ENABLE(FULLSCREEN_API)
1024
1025 bool WebChromeClient::supportsFullScreenForElement(const Element& element, bool withKeyboard)
1026 {
1027     SEL selector = @selector(webView:supportsFullScreenForElement:withKeyboard:);
1028     if ([[m_webView UIDelegate] respondsToSelector:selector])
1029         return CallUIDelegateReturningBoolean(false, m_webView, selector, kit(const_cast<WebCore::Element*>(&element)), withKeyboard);
1030 #if !PLATFORM(IOS_FAMILY)
1031     return [m_webView _supportsFullScreenForElement:const_cast<WebCore::Element*>(&element) withKeyboard:withKeyboard];
1032 #else
1033     return NO;
1034 #endif
1035 }
1036
1037 void WebChromeClient::enterFullScreenForElement(Element& element)
1038 {
1039     SEL selector = @selector(webView:enterFullScreenForElement:listener:);
1040     if ([[m_webView UIDelegate] respondsToSelector:selector]) {
1041         WebKitFullScreenListener* listener = [[WebKitFullScreenListener alloc] initWithElement:&element];
1042         CallUIDelegate(m_webView, selector, kit(&element), listener);
1043         [listener release];
1044     }
1045 #if !PLATFORM(IOS_FAMILY)
1046     else
1047         [m_webView _enterFullScreenForElement:&element];
1048 #endif
1049 }
1050
1051 void WebChromeClient::exitFullScreenForElement(Element* element)
1052 {
1053     SEL selector = @selector(webView:exitFullScreenForElement:listener:);
1054     if ([[m_webView UIDelegate] respondsToSelector:selector]) {
1055         WebKitFullScreenListener* listener = [[WebKitFullScreenListener alloc] initWithElement:element];
1056         CallUIDelegate(m_webView, selector, kit(element), listener);
1057         [listener release];
1058     }
1059 #if !PLATFORM(IOS_FAMILY)
1060     else
1061         [m_webView _exitFullScreenForElement:element];
1062 #endif
1063 }
1064
1065 #endif // ENABLE(FULLSCREEN_API)
1066
1067 #if ENABLE(WEB_CRYPTO)
1068
1069 bool WebChromeClient::wrapCryptoKey(const Vector<uint8_t>& key, Vector<uint8_t>& wrappedKey) const
1070 {
1071     Vector<uint8_t> masterKey;
1072     SEL selector = @selector(webCryptoMasterKeyForWebView:);
1073     if ([[m_webView UIDelegate] respondsToSelector:selector]) {
1074         NSData *keyData = CallUIDelegate(m_webView, selector);
1075         masterKey.append(static_cast<uint8_t*>(const_cast<void*>([keyData bytes])), [keyData length]);
1076     } else if (!getDefaultWebCryptoMasterKey(masterKey))
1077         return false;
1078
1079     return wrapSerializedCryptoKey(masterKey, key, wrappedKey);
1080 }
1081
1082 bool WebChromeClient::unwrapCryptoKey(const Vector<uint8_t>& wrappedKey, Vector<uint8_t>& key) const
1083 {
1084     Vector<uint8_t> masterKey;
1085     SEL selector = @selector(webCryptoMasterKeyForWebView:);
1086     if ([[m_webView UIDelegate] respondsToSelector:selector]) {
1087         NSData *keyData = CallUIDelegate(m_webView, selector);
1088         masterKey.append(static_cast<uint8_t*>(const_cast<void*>([keyData bytes])), [keyData length]);
1089     } else if (!getDefaultWebCryptoMasterKey(masterKey))
1090         return false;
1091
1092     return unwrapSerializedCryptoKey(masterKey, wrappedKey, key);
1093 }
1094
1095 #endif
1096
1097 #if ENABLE(SERVICE_CONTROLS)
1098
1099 void WebChromeClient::handleSelectionServiceClick(WebCore::FrameSelection& selection, const Vector<String>& telephoneNumbers, const WebCore::IntPoint& point)
1100 {
1101     [m_webView _selectionServiceController].handleSelectionServiceClick(selection, telephoneNumbers, point);
1102 }
1103
1104 bool WebChromeClient::hasRelevantSelectionServices(bool isTextOnly) const
1105 {
1106     return [m_webView _selectionServiceController].hasRelevantSelectionServices(isTextOnly);
1107 }
1108
1109 #endif
1110
1111 #if ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS_FAMILY)
1112
1113 void WebChromeClient::addPlaybackTargetPickerClient(uint64_t contextId)
1114 {
1115     [m_webView _addPlaybackTargetPickerClient:contextId];
1116 }
1117
1118 void WebChromeClient::removePlaybackTargetPickerClient(uint64_t contextId)
1119 {
1120     [m_webView _removePlaybackTargetPickerClient:contextId];
1121 }
1122
1123 void WebChromeClient::showPlaybackTargetPicker(uint64_t contextId, const WebCore::IntPoint& location, bool hasVideo)
1124 {
1125     [m_webView _showPlaybackTargetPicker:contextId location:location hasVideo:hasVideo];
1126 }
1127
1128 void WebChromeClient::playbackTargetPickerClientStateDidChange(uint64_t contextId, MediaProducer::MediaStateFlags state)
1129 {
1130     [m_webView _playbackTargetPickerClientStateDidChange:contextId state:state];
1131 }
1132
1133 void WebChromeClient::setMockMediaPlaybackTargetPickerEnabled(bool enabled)
1134 {
1135     [m_webView _setMockMediaPlaybackTargetPickerEnabled:enabled];
1136 }
1137
1138 void WebChromeClient::setMockMediaPlaybackTargetPickerState(const String& name, MediaPlaybackTargetContext::State state)
1139 {
1140     [m_webView _setMockMediaPlaybackTargetPickerName:name state:state];
1141 }
1142
1143 #endif
1144
1145 String WebChromeClient::signedPublicKeyAndChallengeString(unsigned keySizeIndex, const String& challengeString, const URL& url) const
1146 {
1147     SEL selector = @selector(signedPublicKeyAndChallengeStringForWebView:);
1148     if ([[m_webView UIDelegate] respondsToSelector:selector])
1149         return CallUIDelegate(m_webView, selector);
1150     return WebCore::signedPublicKeyAndChallengeString(keySizeIndex, challengeString, url);
1151 }