Unreviewed, rolling out r167700.
[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 "WebUIDelegatePrivate.h"
53 #import "WebView.h"
54 #import "WebViewInternal.h"
55 #import <Foundation/Foundation.h>
56 #import <WebCore/BlockExceptions.h>
57 #import <WebCore/ColorChooser.h>
58 #import <WebCore/ContextMenu.h>
59 #import <WebCore/ContextMenuController.h>
60 #import <WebCore/Cursor.h>
61 #import <WebCore/Element.h>
62 #import <WebCore/FileChooser.h>
63 #import <WebCore/FileIconLoader.h>
64 #import <WebCore/FloatRect.h>
65 #import <WebCore/Frame.h>
66 #import <WebCore/FrameLoadRequest.h>
67 #import <WebCore/FrameView.h>
68 #import <WebCore/GraphicsLayer.h>
69 #import <WebCore/HTMLInputElement.h>
70 #import <WebCore/HTMLNames.h>
71 #import <WebCore/HTMLPlugInImageElement.h>
72 #import <WebCore/HitTestResult.h>
73 #import <WebCore/Icon.h>
74 #import <WebCore/IntPoint.h>
75 #import <WebCore/IntRect.h>
76 #import <WebCore/NavigationAction.h>
77 #import <WebCore/NotImplemented.h>
78 #import <WebCore/Page.h>
79 #import <WebCore/PlatformScreen.h>
80 #import <WebCore/ResourceRequest.h>
81 #import <WebCore/SerializedCryptoKeyWrap.h>
82 #import <WebCore/Widget.h>
83 #import <WebCore/WindowFeatures.h>
84 #import <wtf/PassRefPtr.h>
85 #import <wtf/Vector.h>
86 #import <wtf/text/WTFString.h>
87
88 #if USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API)
89 #import "NetscapePluginHostManager.h"
90 #endif
91
92 #if PLATFORM(IOS) && ENABLE(GEOLOCATION)
93 #import <WebCore/Geolocation.h>
94 #endif
95
96 #if PLATFORM(IOS)
97 #import <WebCore/WAKClipView.h>
98 #import <WebCore/WAKWindow.h>
99 #import <WebCore/WebCoreThreadMessage.h>
100 #endif
101
102 NSString *WebConsoleMessageXMLMessageSource = @"XMLMessageSource";
103 NSString *WebConsoleMessageJSMessageSource = @"JSMessageSource";
104 NSString *WebConsoleMessageNetworkMessageSource = @"NetworkMessageSource";
105 NSString *WebConsoleMessageConsoleAPIMessageSource = @"ConsoleAPIMessageSource";
106 NSString *WebConsoleMessageStorageMessageSource = @"StorageMessageSource";
107 NSString *WebConsoleMessageAppCacheMessageSource = @"AppCacheMessageSource";
108 NSString *WebConsoleMessageRenderingMessageSource = @"RenderingMessageSource";
109 NSString *WebConsoleMessageCSSMessageSource = @"CSSMessageSource";
110 NSString *WebConsoleMessageSecurityMessageSource = @"SecurityMessageSource";
111 NSString *WebConsoleMessageOtherMessageSource = @"OtherMessageSource";
112
113 NSString *WebConsoleMessageDebugMessageLevel = @"DebugMessageLevel";
114 NSString *WebConsoleMessageLogMessageLevel = @"LogMessageLevel";
115 NSString *WebConsoleMessageWarningMessageLevel = @"WarningMessageLevel";
116 NSString *WebConsoleMessageErrorMessageLevel = @"ErrorMessageLevel";
117
118
119 #if !PLATFORM(IOS)
120 @interface NSApplication (WebNSApplicationDetails)
121 - (NSCursor *)_cursorRectCursor;
122 @end
123 #endif
124
125 @interface NSView (WebNSViewDetails)
126 - (NSView *)_findLastViewInKeyViewLoop;
127 @end
128
129 // For compatibility with old SPI.
130 @interface NSView (WebOldWebKitPlugInDetails)
131 - (void)setIsSelected:(BOOL)isSelected;
132 @end
133
134 #if !PLATFORM(IOS)
135 @interface NSWindow (AppKitSecretsIKnowAbout)
136 - (NSRect)_growBoxRect;
137 @end
138 #endif
139
140 using namespace WebCore;
141 using namespace HTMLNames;
142
143 WebChromeClient::WebChromeClient(WebView *webView) 
144     : m_webView(webView)
145 {
146 }
147
148 void WebChromeClient::chromeDestroyed()
149 {
150     delete this;
151 }
152
153 // These functions scale between window and WebView coordinates because JavaScript/DOM operations 
154 // assume that the WebView and the window share the same coordinate system.
155
156 void WebChromeClient::setWindowRect(const FloatRect& rect)
157 {
158 #if !PLATFORM(IOS)
159     NSRect windowRect = toDeviceSpace(rect, [m_webView window]);
160     [[m_webView _UIDelegateForwarder] webView:m_webView setFrame:windowRect];
161 #endif
162 }
163
164 FloatRect WebChromeClient::windowRect()
165 {
166 #if !PLATFORM(IOS)
167     NSRect windowRect = [[m_webView _UIDelegateForwarder] webViewFrame:m_webView];
168     return toUserSpace(windowRect, [m_webView window]);
169 #else
170     return FloatRect();
171 #endif
172 }
173
174 // FIXME: We need to add API for setting and getting this.
175 FloatRect WebChromeClient::pageRect()
176 {
177     return [m_webView frame];
178 }
179
180 void WebChromeClient::focus()
181 {
182     [[m_webView _UIDelegateForwarder] webViewFocus:m_webView];
183 }
184
185 void WebChromeClient::unfocus()
186 {
187     [[m_webView _UIDelegateForwarder] webViewUnfocus:m_webView];
188 }
189
190 bool WebChromeClient::canTakeFocus(FocusDirection)
191 {
192     // There's unfortunately no way to determine if we will become first responder again
193     // once we give it up, so we just have to guess that we won't.
194     return true;
195 }
196
197 void WebChromeClient::takeFocus(FocusDirection direction)
198 {
199 #if !PLATFORM(IOS)
200     if (direction == FocusDirectionForward) {
201         // Since we're trying to move focus out of m_webView, and because
202         // m_webView may contain subviews within it, we ask it for the next key
203         // view of the last view in its key view loop. This makes m_webView
204         // behave as if it had no subviews, which is the behavior we want.
205         NSView *lastView = [m_webView _findLastViewInKeyViewLoop];
206         // avoid triggering assertions if the WebView is the only thing in the key loop
207         if ([m_webView _becomingFirstResponderFromOutside] && m_webView == [lastView nextValidKeyView])
208             return;
209         [[m_webView window] selectKeyViewFollowingView:lastView];
210     } else {
211         // avoid triggering assertions if the WebView is the only thing in the key loop
212         if ([m_webView _becomingFirstResponderFromOutside] && m_webView == [m_webView previousValidKeyView])
213             return;
214         [[m_webView window] selectKeyViewPrecedingView:m_webView];
215     }
216 #endif
217 }
218
219 void WebChromeClient::focusedElementChanged(Element* element)
220 {
221     if (!element)
222         return;
223     if (!isHTMLInputElement(element))
224         return;
225
226     HTMLInputElement* inputElement = toHTMLInputElement(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::shared().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::Warning:
405         return WebConsoleMessageWarningMessageLevel;
406     case MessageLevel::Error:
407         return WebConsoleMessageErrorMessageLevel;
408     }
409     ASSERT_NOT_REACHED();
410     return @"";
411 }
412
413 void WebChromeClient::addMessageToConsole(MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, unsigned columnNumber, const String& sourceURL)
414 {
415 #if !PLATFORM(IOS)
416     id delegate = [m_webView UIDelegate];
417 #else
418     if (![m_webView _allowsMessaging])
419         return;
420
421     id delegate = [m_webView _UIKitDelegate];
422     // No delegate means nothing to send this data to so bail.
423     if (!delegate)
424         return;
425 #endif
426
427     BOOL respondsToNewSelector = NO;
428
429     SEL selector = @selector(webView:addMessageToConsole:withSource:);
430     if ([delegate respondsToSelector:selector])
431         respondsToNewSelector = YES;
432     else {
433         // The old selector only takes JSMessageSource messages.
434         if (source != MessageSource::JS)
435             return;
436         selector = @selector(webView:addMessageToConsole:);
437         if (![delegate respondsToSelector:selector])
438             return;
439     }
440
441     NSString *messageSource = stringForMessageSource(source);
442     NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:
443         (NSString *)message, @"message",
444         [NSNumber numberWithUnsignedInt:lineNumber], @"lineNumber",
445         [NSNumber numberWithUnsignedInt:columnNumber], @"columnNumber",
446         (NSString *)sourceURL, @"sourceURL",
447         messageSource, @"MessageSource",
448         stringForMessageLevel(level), @"MessageLevel",
449         NULL];
450
451 #if PLATFORM(IOS)
452     [[[m_webView _UIKitDelegateForwarder] asyncForwarder] webView:m_webView addMessageToConsole:dictionary withSource:messageSource];
453 #else
454     if (respondsToNewSelector)
455         CallUIDelegate(m_webView, selector, dictionary, messageSource);
456     else
457         CallUIDelegate(m_webView, selector, dictionary);
458 #endif
459
460     [dictionary release];
461 }
462
463 bool WebChromeClient::canRunBeforeUnloadConfirmPanel()
464 {
465     return [[m_webView UIDelegate] respondsToSelector:@selector(webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:)];
466 }
467
468 bool WebChromeClient::runBeforeUnloadConfirmPanel(const String& message, Frame* frame)
469 {
470     return CallUIDelegateReturningBoolean(true, m_webView, @selector(webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:), message, kit(frame));
471 }
472
473 void WebChromeClient::closeWindowSoon()
474 {
475     // We need to remove the parent WebView from WebViewSets here, before it actually
476     // closes, to make sure that JavaScript code that executes before it closes
477     // can't find it. Otherwise, window.open will select a closed WebView instead of 
478     // opening a new one <rdar://problem/3572585>.
479
480     // We also need to stop the load to prevent further parsing or JavaScript execution
481     // after the window has torn down <rdar://problem/4161660>.
482   
483     // FIXME: This code assumes that the UI delegate will respond to a webViewClose
484     // message by actually closing the WebView. Safari guarantees this behavior, but other apps might not.
485     // This approach is an inherent limitation of not making a close execute immediately
486     // after a call to window.close.
487
488     [m_webView setGroupName:nil];
489     [m_webView stopLoading:nil];
490     [m_webView performSelector:@selector(_closeWindow) withObject:nil afterDelay:0.0];
491 }
492
493 void WebChromeClient::runJavaScriptAlert(Frame* frame, const String& message)
494 {
495     id delegate = [m_webView UIDelegate];
496     SEL selector = @selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:);
497     if ([delegate respondsToSelector:selector]) {
498         CallUIDelegate(m_webView, selector, message, kit(frame));
499         return;
500     }
501
502     // Call the old version of the delegate method if it is implemented.
503     selector = @selector(webView:runJavaScriptAlertPanelWithMessage:);
504     if ([delegate respondsToSelector:selector]) {
505         CallUIDelegate(m_webView, selector, message);
506         return;
507     }
508 }
509
510 bool WebChromeClient::runJavaScriptConfirm(Frame* frame, const String& message)
511 {
512     id delegate = [m_webView UIDelegate];
513     SEL selector = @selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:);
514     if ([delegate respondsToSelector:selector])
515         return CallUIDelegateReturningBoolean(NO, m_webView, selector, message, kit(frame));
516
517     // Call the old version of the delegate method if it is implemented.
518     selector = @selector(webView:runJavaScriptConfirmPanelWithMessage:);
519     if ([delegate respondsToSelector:selector])
520         return CallUIDelegateReturningBoolean(NO, m_webView, selector, message);
521
522     return NO;
523 }
524
525 bool WebChromeClient::runJavaScriptPrompt(Frame* frame, const String& prompt, const String& defaultText, String& result)
526 {
527     id delegate = [m_webView UIDelegate];
528     SEL selector = @selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:);
529     NSString *defaultString = defaultText;
530     if ([delegate respondsToSelector:selector]) {
531         result = (NSString *)CallUIDelegate(m_webView, selector, prompt, defaultString, kit(frame));
532         return !result.isNull();
533     }
534
535     // Call the old version of the delegate method if it is implemented.
536     selector = @selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:);
537     if ([delegate respondsToSelector:selector]) {
538         result = (NSString *)CallUIDelegate(m_webView, selector, prompt, defaultString);
539         return !result.isNull();
540     }
541
542     result = [[WebDefaultUIDelegate sharedUIDelegate] webView:m_webView runJavaScriptTextInputPanelWithPrompt:prompt defaultText:defaultString initiatedByFrame:kit(frame)];
543     return !result.isNull();
544 }
545
546 bool WebChromeClient::shouldInterruptJavaScript()
547 {
548     return CallUIDelegateReturningBoolean(NO, m_webView, @selector(webViewShouldInterruptJavaScript:));
549 }
550
551 void WebChromeClient::setStatusbarText(const String& status)
552 {
553     // We want the temporaries allocated here to be released even before returning to the 
554     // event loop; see <http://bugs.webkit.org/show_bug.cgi?id=9880>.
555     NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init];
556     CallUIDelegate(m_webView, @selector(webView:setStatusText:), (NSString *)status);
557     [localPool drain];
558 }
559
560 IntRect WebChromeClient::windowResizerRect() const
561 {
562 #if !PLATFORM(IOS)
563     return enclosingIntRect([[m_webView window] _growBoxRect]);
564 #else
565     return IntRect();
566 #endif
567 }
568
569 bool WebChromeClient::supportsImmediateInvalidation()
570 {
571     return true;
572 }
573
574 void WebChromeClient::invalidateRootView(const IntRect&)
575 {
576 }
577
578 void WebChromeClient::invalidateContentsAndRootView(const IntRect& rect)
579 {
580 }
581
582 void WebChromeClient::invalidateContentsForSlowScroll(const IntRect& rect)
583 {
584     invalidateContentsAndRootView(rect);
585 }
586
587 void WebChromeClient::scroll(const IntSize&, const IntRect&, const IntRect&)
588 {
589 }
590
591 IntPoint WebChromeClient::screenToRootView(const IntPoint& p) const
592 {
593     // FIXME: Implement this.
594     return p;
595 }
596
597 IntRect WebChromeClient::rootViewToScreen(const IntRect& r) const
598 {
599     // FIXME: Implement this.
600     return r;
601 }
602
603 PlatformPageClient WebChromeClient::platformPageClient() const
604 {
605     return 0;
606 }
607
608 void WebChromeClient::contentsSizeChanged(Frame*, const IntSize&) const
609 {
610 }
611
612 void WebChromeClient::scrollRectIntoView(const IntRect& r) const
613 {
614     // FIXME: This scrolling behavior should be under the control of the embedding client,
615     // perhaps in a delegate method, rather than something WebKit does unconditionally.
616     NSView *coordinateView = [[[m_webView mainFrame] frameView] documentView];
617     NSRect rect = r;
618     for (NSView *view = m_webView; view; view = [view superview]) {
619         if ([view isKindOfClass:[NSClipView class]]) {
620             NSClipView *clipView = (NSClipView *)view;
621             NSView *documentView = [clipView documentView];
622             [documentView scrollRectToVisible:[documentView convertRect:rect fromView:coordinateView]];
623         }
624     }
625 }
626
627 // End host window methods.
628
629 bool WebChromeClient::shouldUnavailablePluginMessageBeButton(RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason) const
630 {
631     if (pluginUnavailabilityReason == RenderEmbeddedObject::PluginMissing)
632         return [[m_webView UIDelegate] respondsToSelector:@selector(webView:didPressMissingPluginButton:)];
633
634     return false;
635 }
636
637 void WebChromeClient::unavailablePluginButtonClicked(Element* element, RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason) const
638 {
639     ASSERT(element->hasTagName(objectTag) || element->hasTagName(embedTag) || element->hasTagName(appletTag));
640
641     ASSERT(pluginUnavailabilityReason == RenderEmbeddedObject::PluginMissing);
642     CallUIDelegate(m_webView, @selector(webView:didPressMissingPluginButton:), kit(element));
643 }
644
645 void WebChromeClient::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags)
646 {
647     WebElementDictionary *element = [[WebElementDictionary alloc] initWithHitTestResult:result];
648     [m_webView _mouseDidMoveOverElement:element modifierFlags:modifierFlags];
649     [element release];
650 }
651
652 void WebChromeClient::setToolTip(const String& toolTip, TextDirection)
653 {
654     NSView<WebDocumentView> *documentView = [[[m_webView _selectedOrMainFrame] frameView] documentView];
655     if ([documentView isKindOfClass:[WebHTMLView class]])
656         [(WebHTMLView *)documentView _setToolTip:toolTip];
657 }
658
659 void WebChromeClient::print(Frame* frame)
660 {
661     WebFrame *webFrame = kit(frame);
662     if ([[m_webView UIDelegate] respondsToSelector:@selector(webView:printFrame:)])
663         CallUIDelegate(m_webView, @selector(webView:printFrame:), webFrame);
664     else
665         CallUIDelegate(m_webView, @selector(webView:printFrameView:), [webFrame frameView]);
666 }
667
668 #if ENABLE(SQL_DATABASE)
669
670 void WebChromeClient::exceededDatabaseQuota(Frame* frame, const String& databaseName, DatabaseDetails)
671 {
672     BEGIN_BLOCK_OBJC_EXCEPTIONS;
673
674     WebSecurityOrigin *webOrigin = [[WebSecurityOrigin alloc] _initWithWebCoreSecurityOrigin:frame->document()->securityOrigin()];
675 #if !PLATFORM(IOS)
676     // FIXME: remove this workaround once shipping Safari has the necessary delegate implemented.
677     if (WKAppVersionCheckLessThan(@"com.apple.Safari", -1, 3.1)) {
678         const unsigned long long defaultQuota = 5 * 1024 * 1024; // 5 megabytes should hopefully be enough to test storage support.
679         [[webOrigin databaseQuotaManager] setQuota:defaultQuota];
680     } else
681 #endif
682         CallUIDelegate(m_webView, @selector(webView:frame:exceededDatabaseQuotaForSecurityOrigin:database:), kit(frame), webOrigin, (NSString *)databaseName);
683     [webOrigin release];
684
685     END_BLOCK_OBJC_EXCEPTIONS;
686 }
687
688 #endif
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 void WebChromeClient::populateVisitedLinks()
707 {
708     if ([m_webView historyDelegate]) {
709         WebHistoryDelegateImplementationCache* implementations = WebViewGetHistoryDelegateImplementations(m_webView);
710         
711         if (implementations->populateVisitedLinksFunc)
712             CallHistoryDelegate(implementations->populateVisitedLinksFunc, m_webView, @selector(populateVisitedLinksForWebView:));
713
714         return;
715     }
716
717     BEGIN_BLOCK_OBJC_EXCEPTIONS;
718     [[WebHistory optionalSharedHistory] _addVisitedLinksToPageGroup:[m_webView page]->group()];
719     END_BLOCK_OBJC_EXCEPTIONS;
720 }
721
722 #if ENABLE(DASHBOARD_SUPPORT)
723
724 void WebChromeClient::annotatedRegionsChanged()
725 {
726     BEGIN_BLOCK_OBJC_EXCEPTIONS;
727     CallUIDelegate(m_webView, @selector(webView:dashboardRegionsChanged:), [m_webView _dashboardRegions]);
728     END_BLOCK_OBJC_EXCEPTIONS;
729 }
730
731 #endif
732
733 #if ENABLE(INPUT_TYPE_COLOR)
734 PassOwnPtr<ColorChooser> WebChromeClient::createColorChooser(ColorChooserClient* client, const Color& initialColor)
735 {
736     // FIXME: Implement <input type='color'> for WK1 (Bug 119094).
737     ASSERT_NOT_REACHED();
738     return nullptr;
739 }
740 #endif
741
742 void WebChromeClient::runOpenPanel(Frame*, PassRefPtr<FileChooser> chooser)
743 {
744     BEGIN_BLOCK_OBJC_EXCEPTIONS;
745     BOOL allowMultipleFiles = chooser->settings().allowsMultipleFiles;
746     WebOpenPanelResultListener *listener = [[WebOpenPanelResultListener alloc] initWithChooser:chooser];
747     id delegate = [m_webView UIDelegate];
748     if ([delegate respondsToSelector:@selector(webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:)])
749         CallUIDelegate(m_webView, @selector(webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:), listener, allowMultipleFiles);
750     else if ([delegate respondsToSelector:@selector(webView:runOpenPanelForFileButtonWithResultListener:)])
751         CallUIDelegate(m_webView, @selector(webView:runOpenPanelForFileButtonWithResultListener:), listener);
752     else
753         [listener cancel];
754     [listener release];
755     END_BLOCK_OBJC_EXCEPTIONS;
756 }
757
758 void WebChromeClient::loadIconForFiles(const Vector<String>& filenames, FileIconLoader* iconLoader)
759 {
760     iconLoader->notifyFinished(Icon::createIconForFiles(filenames));
761 }
762
763 #if !PLATFORM(IOS)
764
765 void WebChromeClient::setCursor(const WebCore::Cursor& cursor)
766 {
767     // FIXME: Would be nice to share this code with WebKit2's PageClientImpl.
768
769     if ([NSApp _cursorRectCursor])
770         return;
771
772     if (!m_webView)
773         return;
774
775     NSWindow *window = [m_webView window];
776     if (!window)
777         return;
778
779     if ([window windowNumber] != [NSWindow windowNumberAtPoint:[NSEvent mouseLocation] belowWindowWithWindowNumber:0])
780         return;
781
782     NSCursor *platformCursor = cursor.platformCursor();
783     if ([NSCursor currentCursor] == platformCursor)
784         return;
785
786     [platformCursor set];
787 }
788
789 void WebChromeClient::setCursorHiddenUntilMouseMoves(bool hiddenUntilMouseMoves)
790 {
791     [NSCursor setHiddenUntilMouseMoves:hiddenUntilMouseMoves];
792 }
793
794 #endif
795
796 KeyboardUIMode WebChromeClient::keyboardUIMode()
797 {
798     BEGIN_BLOCK_OBJC_EXCEPTIONS;
799     return [m_webView _keyboardUIMode];
800     END_BLOCK_OBJC_EXCEPTIONS;
801     return KeyboardAccessDefault;
802 }
803
804 NSResponder *WebChromeClient::firstResponder()
805 {
806     BEGIN_BLOCK_OBJC_EXCEPTIONS;
807     return [[m_webView _UIDelegateForwarder] webViewFirstResponder:m_webView];
808     END_BLOCK_OBJC_EXCEPTIONS;
809     return nil;
810 }
811
812 void WebChromeClient::makeFirstResponder(NSResponder *responder)
813 {
814     BEGIN_BLOCK_OBJC_EXCEPTIONS;
815     [m_webView _pushPerformingProgrammaticFocus];
816     [[m_webView _UIDelegateForwarder] webView:m_webView makeFirstResponder:responder];
817     [m_webView _popPerformingProgrammaticFocus];
818     END_BLOCK_OBJC_EXCEPTIONS;
819 }
820
821 void WebChromeClient::enableSuddenTermination()
822 {
823 #if !PLATFORM(IOS)
824     [[NSProcessInfo processInfo] enableSuddenTermination];
825 #endif
826 }
827
828 void WebChromeClient::disableSuddenTermination()
829 {
830 #if !PLATFORM(IOS)
831     [[NSProcessInfo processInfo] disableSuddenTermination];
832 #endif
833 }
834
835 bool WebChromeClient::shouldReplaceWithGeneratedFileForUpload(const String& path, String& generatedFilename)
836 {
837     NSString* filename;
838     if (![[m_webView _UIDelegateForwarder] webView:m_webView shouldReplaceUploadFile:path usingGeneratedFilename:&filename])
839         return false;
840     generatedFilename = filename;
841     return true;
842 }
843
844 String WebChromeClient::generateReplacementFile(const String& path)
845 {
846     return [[m_webView _UIDelegateForwarder] webView:m_webView generateReplacementFile:path];
847 }
848
849 void WebChromeClient::elementDidFocus(const WebCore::Node* node)
850 {
851     CallUIDelegate(m_webView, @selector(webView:formDidFocusNode:), kit(const_cast<WebCore::Node*>(node)));
852 }
853
854 void WebChromeClient::elementDidBlur(const WebCore::Node* node)
855 {
856     CallUIDelegate(m_webView, @selector(webView:formDidBlurNode:), kit(const_cast<WebCore::Node*>(node)));
857 }
858
859 bool WebChromeClient::selectItemWritingDirectionIsNatural()
860 {
861     return false;
862 }
863
864 bool WebChromeClient::selectItemAlignmentFollowsMenuWritingDirection()
865 {
866     return true;
867 }
868
869 bool WebChromeClient::hasOpenedPopup() const
870 {
871     notImplemented();
872     return false;
873 }
874
875 PassRefPtr<WebCore::PopupMenu> WebChromeClient::createPopupMenu(WebCore::PopupMenuClient* client) const
876 {
877 #if !PLATFORM(IOS)
878     return adoptRef(new PopupMenuMac(client));
879 #else
880     return nullptr;
881 #endif
882 }
883
884 PassRefPtr<WebCore::SearchPopupMenu> WebChromeClient::createSearchPopupMenu(WebCore::PopupMenuClient* client) const
885 {
886 #if !PLATFORM(IOS)
887     return adoptRef(new SearchPopupMenuMac(client));
888 #else
889     return nullptr;
890 #endif
891 }
892
893 bool WebChromeClient::shouldPaintEntireContents() const
894 {
895 #if PLATFORM(IOS)
896     return false;
897 #else
898     NSView *documentView = [[[m_webView mainFrame] frameView] documentView];
899     return [documentView layer];
900 #endif
901 }
902
903 void WebChromeClient::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* graphicsLayer)
904 {
905     BEGIN_BLOCK_OBJC_EXCEPTIONS;
906
907     NSView *documentView = [[kit(frame) frameView] documentView];
908     if (![documentView isKindOfClass:[WebHTMLView class]]) {
909         // We should never be attaching when we don't have a WebHTMLView.
910         ASSERT(!graphicsLayer);
911         return;
912     }
913
914     WebHTMLView *webHTMLView = (WebHTMLView *)documentView;
915     if (graphicsLayer)
916         [webHTMLView attachRootLayer:graphicsLayer->platformLayer()];
917     else
918         [webHTMLView detachRootLayer];
919     END_BLOCK_OBJC_EXCEPTIONS;
920 }
921
922 void WebChromeClient::setNeedsOneShotDrawingSynchronization()
923 {
924     BEGIN_BLOCK_OBJC_EXCEPTIONS;
925     [m_webView _setNeedsOneShotDrawingSynchronization:YES];
926     END_BLOCK_OBJC_EXCEPTIONS;
927 }
928
929 void WebChromeClient::scheduleCompositingLayerFlush()
930 {
931     BEGIN_BLOCK_OBJC_EXCEPTIONS;
932     [m_webView _scheduleCompositingLayerFlush];
933     END_BLOCK_OBJC_EXCEPTIONS;
934 }
935
936 #if ENABLE(VIDEO)
937
938 bool WebChromeClient::supportsFullscreenForNode(const Node* node)
939 {
940 #if PLATFORM(IOS)
941     if (!Settings::avKitEnabled())
942         return false;
943 #endif
944     return isHTMLVideoElement(node);
945 }
946
947 void WebChromeClient::enterFullscreenForNode(Node* node)
948 {
949     BEGIN_BLOCK_OBJC_EXCEPTIONS;
950     [m_webView _enterFullscreenForNode:node];
951     END_BLOCK_OBJC_EXCEPTIONS;
952 }
953
954 void WebChromeClient::exitFullscreenForNode(Node*)
955 {
956     BEGIN_BLOCK_OBJC_EXCEPTIONS;
957     [m_webView _exitFullscreen];
958     END_BLOCK_OBJC_EXCEPTIONS;    
959 }
960
961 #endif
962
963 #if ENABLE(FULLSCREEN_API)
964
965 bool WebChromeClient::supportsFullScreenForElement(const Element* element, bool withKeyboard)
966 {
967     SEL selector = @selector(webView:supportsFullScreenForElement:withKeyboard:);
968     if ([[m_webView UIDelegate] respondsToSelector:selector])
969         return CallUIDelegateReturningBoolean(false, m_webView, selector, kit(const_cast<WebCore::Element*>(element)), withKeyboard);
970 #if !PLATFORM(IOS)
971     return [m_webView _supportsFullScreenForElement:const_cast<WebCore::Element*>(element) withKeyboard:withKeyboard];
972 #else
973     return NO;
974 #endif
975 }
976
977 void WebChromeClient::enterFullScreenForElement(Element* element)
978 {
979     SEL selector = @selector(webView:enterFullScreenForElement:listener:);
980     if ([[m_webView UIDelegate] respondsToSelector:selector]) {
981         WebKitFullScreenListener* listener = [[WebKitFullScreenListener alloc] initWithElement:element];
982         CallUIDelegate(m_webView, selector, kit(element), listener);
983         [listener release];
984     }
985 #if !PLATFORM(IOS)
986     else
987         [m_webView _enterFullScreenForElement:element];
988 #endif
989 }
990
991 void WebChromeClient::exitFullScreenForElement(Element* element)
992 {
993     SEL selector = @selector(webView:exitFullScreenForElement:listener:);
994     if ([[m_webView UIDelegate] respondsToSelector:selector]) {
995         WebKitFullScreenListener* listener = [[WebKitFullScreenListener alloc] initWithElement:element];
996         CallUIDelegate(m_webView, selector, kit(element), listener);
997         [listener release];
998     }
999 #if !PLATFORM(IOS)
1000     else
1001         [m_webView _exitFullScreenForElement:element];
1002 #endif
1003 }
1004
1005 #endif // ENABLE(FULLSCREEN_API)
1006
1007 #if ENABLE(SUBTLE_CRYPTO)
1008 bool WebChromeClient::wrapCryptoKey(const Vector<uint8_t>& key, Vector<uint8_t>& wrappedKey) const
1009 {
1010     Vector<uint8_t> masterKey;
1011     SEL selector = @selector(webCryptoMasterKeyForWebView:);
1012     if ([[m_webView UIDelegate] respondsToSelector:selector]) {
1013         NSData *keyData = CallUIDelegate(m_webView, selector);
1014         masterKey.append((uint8_t*)[keyData bytes], [keyData length]);
1015     } else if (!getDefaultWebCryptoMasterKey(masterKey))
1016         return false;
1017
1018     return wrapSerializedCryptoKey(masterKey, key, wrappedKey);
1019 }
1020
1021 bool WebChromeClient::unwrapCryptoKey(const Vector<uint8_t>& wrappedKey, Vector<uint8_t>& key) const
1022 {
1023     Vector<uint8_t> masterKey;
1024     SEL selector = @selector(webCryptoMasterKeyForWebView:);
1025     if ([[m_webView UIDelegate] respondsToSelector:selector]) {
1026         NSData *keyData = CallUIDelegate(m_webView, selector);
1027         masterKey.append((uint8_t*)[keyData bytes], [keyData length]);
1028     } else if (!getDefaultWebCryptoMasterKey(masterKey))
1029         return false;
1030
1031     return unwrapSerializedCryptoKey(masterKey, wrappedKey, key);
1032 }
1033 #endif