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