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