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