• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 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 "DOMNodeInternal.h"
33#import "WebDefaultUIDelegate.h"
34#import "WebDelegateImplementationCaching.h"
35#import "WebElementDictionary.h"
36#import "WebFrameInternal.h"
37#import "WebFrameView.h"
38#import "WebHTMLViewInternal.h"
39#import "WebHistoryInternal.h"
40#import "WebKitPrefix.h"
41#import "WebKitSystemInterface.h"
42#import "WebNSURLRequestExtras.h"
43#import "WebPlugin.h"
44#import "WebSecurityOriginInternal.h"
45#import "WebUIDelegatePrivate.h"
46#import "WebView.h"
47#import "WebViewInternal.h"
48#import <Foundation/Foundation.h>
49#import <WebCore/BlockExceptions.h>
50#import <WebCore/Console.h>
51#import <WebCore/Element.h>
52#import <WebCore/FileChooser.h>
53#import <WebCore/FloatRect.h>
54#import <WebCore/Frame.h>
55#import <WebCore/FrameLoadRequest.h>
56#import <WebCore/Geolocation.h>
57#import <WebCore/HitTestResult.h>
58#import <WebCore/HTMLNames.h>
59#import <WebCore/IntRect.h>
60#import <WebCore/Page.h>
61#import <WebCore/PlatformScreen.h>
62#import <WebCore/PlatformString.h>
63#import <WebCore/ResourceRequest.h>
64#import <WebCore/ScrollView.h>
65#import <WebCore/Widget.h>
66#import <WebCore/WindowFeatures.h>
67#import <wtf/PassRefPtr.h>
68#import <wtf/Vector.h>
69
70#if USE(ACCELERATED_COMPOSITING)
71#import <WebCore/GraphicsLayer.h>
72#endif
73
74#if USE(PLUGIN_HOST_PROCESS)
75#import "NetscapePluginHostManager.h"
76#endif
77
78@interface NSView (WebNSViewDetails)
79- (NSView *)_findLastViewInKeyViewLoop;
80@end
81
82// For compatibility with old SPI.
83@interface NSView (WebOldWebKitPlugInDetails)
84- (void)setIsSelected:(BOOL)isSelected;
85@end
86
87@interface NSWindow (AppKitSecretsIKnowAbout)
88- (NSRect)_growBoxRect;
89@end
90
91using namespace WebCore;
92
93@interface WebOpenPanelResultListener : NSObject <WebOpenPanelResultListener>
94{
95    FileChooser* _chooser;
96}
97- (id)initWithChooser:(PassRefPtr<FileChooser>)chooser;
98@end
99
100@interface WebGeolocationPolicyListener : NSObject <WebGeolocationPolicyListener>
101{
102    RefPtr<Geolocation> _geolocation;
103}
104- (id)initWithGeolocation:(Geolocation*)geolocation;
105@end
106
107WebChromeClient::WebChromeClient(WebView *webView)
108    : m_webView(webView)
109{
110}
111
112void WebChromeClient::chromeDestroyed()
113{
114    delete this;
115}
116
117// These functions scale between window and WebView coordinates because JavaScript/DOM operations
118// assume that the WebView and the window share the same coordinate system.
119
120void WebChromeClient::setWindowRect(const FloatRect& rect)
121{
122    NSRect windowRect = toDeviceSpace(rect, [m_webView window]);
123    [[m_webView _UIDelegateForwarder] webView:m_webView setFrame:windowRect];
124}
125
126FloatRect WebChromeClient::windowRect()
127{
128    NSRect windowRect = [[m_webView _UIDelegateForwarder] webViewFrame:m_webView];
129    return toUserSpace(windowRect, [m_webView window]);
130}
131
132// FIXME: We need to add API for setting and getting this.
133FloatRect WebChromeClient::pageRect()
134{
135    return [m_webView frame];
136}
137
138float WebChromeClient::scaleFactor()
139{
140    if (NSWindow *window = [m_webView window])
141        return [window  userSpaceScaleFactor];
142    return [[NSScreen mainScreen] userSpaceScaleFactor];
143}
144
145void WebChromeClient::focus()
146{
147    [[m_webView _UIDelegateForwarder] webViewFocus:m_webView];
148}
149
150void WebChromeClient::unfocus()
151{
152    [[m_webView _UIDelegateForwarder] webViewUnfocus:m_webView];
153}
154
155bool WebChromeClient::canTakeFocus(FocusDirection)
156{
157    // There's unfortunately no way to determine if we will become first responder again
158    // once we give it up, so we just have to guess that we won't.
159    return true;
160}
161
162void WebChromeClient::takeFocus(FocusDirection direction)
163{
164    if (direction == FocusDirectionForward) {
165        // Since we're trying to move focus out of m_webView, and because
166        // m_webView may contain subviews within it, we ask it for the next key
167        // view of the last view in its key view loop. This makes m_webView
168        // behave as if it had no subviews, which is the behavior we want.
169        NSView *lastView = [m_webView _findLastViewInKeyViewLoop];
170        // avoid triggering assertions if the WebView is the only thing in the key loop
171        if ([m_webView _becomingFirstResponderFromOutside] && m_webView == [lastView nextValidKeyView])
172            return;
173        [[m_webView window] selectKeyViewFollowingView:lastView];
174    } else {
175        // avoid triggering assertions if the WebView is the only thing in the key loop
176        if ([m_webView _becomingFirstResponderFromOutside] && m_webView == [m_webView previousValidKeyView])
177            return;
178        [[m_webView window] selectKeyViewPrecedingView:m_webView];
179    }
180}
181
182void WebChromeClient::focusedNodeChanged(Node*)
183{
184}
185
186Page* WebChromeClient::createWindow(Frame* frame, const FrameLoadRequest& request, const WindowFeatures& features)
187{
188    NSURLRequest *URLRequest = nil;
189    if (!request.isEmpty())
190        URLRequest = request.resourceRequest().nsURLRequest();
191
192    id delegate = [m_webView UIDelegate];
193    WebView *newWebView;
194
195    if ([delegate respondsToSelector:@selector(webView:createWebViewWithRequest:windowFeatures:)]) {
196        NSNumber *x = features.xSet ? [[NSNumber alloc] initWithFloat:features.x] : nil;
197        NSNumber *y = features.ySet ? [[NSNumber alloc] initWithFloat:features.y] : nil;
198        NSNumber *width = features.widthSet ? [[NSNumber alloc] initWithFloat:features.width] : nil;
199        NSNumber *height = features.heightSet ? [[NSNumber alloc] initWithFloat:features.height] : nil;
200        NSNumber *menuBarVisible = [[NSNumber alloc] initWithBool:features.menuBarVisible];
201        NSNumber *statusBarVisible = [[NSNumber alloc] initWithBool:features.statusBarVisible];
202        NSNumber *toolBarVisible = [[NSNumber alloc] initWithBool:features.toolBarVisible];
203        NSNumber *scrollbarsVisible = [[NSNumber alloc] initWithBool:features.scrollbarsVisible];
204        NSNumber *resizable = [[NSNumber alloc] initWithBool:features.resizable];
205        NSNumber *fullscreen = [[NSNumber alloc] initWithBool:features.fullscreen];
206        NSNumber *dialog = [[NSNumber alloc] initWithBool:features.dialog];
207
208        NSMutableDictionary *dictFeatures = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
209                                             menuBarVisible, @"menuBarVisible",
210                                             statusBarVisible, @"statusBarVisible",
211                                             toolBarVisible, @"toolBarVisible",
212                                             scrollbarsVisible, @"scrollbarsVisible",
213                                             resizable, @"resizable",
214                                             fullscreen, @"fullscreen",
215                                             dialog, @"dialog",
216                                             nil];
217
218        if (x)
219            [dictFeatures setObject:x forKey:@"x"];
220        if (y)
221            [dictFeatures setObject:y forKey:@"y"];
222        if (width)
223            [dictFeatures setObject:width forKey:@"width"];
224        if (height)
225            [dictFeatures setObject:height forKey:@"height"];
226
227        newWebView = CallUIDelegate(m_webView, @selector(webView:createWebViewWithRequest:windowFeatures:), URLRequest, dictFeatures);
228
229        [dictFeatures release];
230        [x release];
231        [y release];
232        [width release];
233        [height release];
234        [menuBarVisible release];
235        [statusBarVisible release];
236        [toolBarVisible release];
237        [scrollbarsVisible release];
238        [resizable release];
239        [fullscreen release];
240        [dialog release];
241    } else if (features.dialog && [delegate respondsToSelector:@selector(webView:createWebViewModalDialogWithRequest:)]) {
242        newWebView = CallUIDelegate(m_webView, @selector(webView:createWebViewModalDialogWithRequest:), URLRequest);
243    } else {
244        newWebView = CallUIDelegate(m_webView, @selector(webView:createWebViewWithRequest:), URLRequest);
245    }
246
247#if USE(PLUGIN_HOST_PROCESS)
248    if (newWebView)
249        WebKit::NetscapePluginHostManager::shared().didCreateWindow();
250#endif
251
252    return core(newWebView);
253}
254
255void WebChromeClient::show()
256{
257    [[m_webView _UIDelegateForwarder] webViewShow:m_webView];
258}
259
260bool WebChromeClient::canRunModal()
261{
262    return [[m_webView UIDelegate] respondsToSelector:@selector(webViewRunModal:)];
263}
264
265void WebChromeClient::runModal()
266{
267    CallUIDelegate(m_webView, @selector(webViewRunModal:));
268}
269
270void WebChromeClient::setToolbarsVisible(bool b)
271{
272    [[m_webView _UIDelegateForwarder] webView:m_webView setToolbarsVisible:b];
273}
274
275bool WebChromeClient::toolbarsVisible()
276{
277    return CallUIDelegateReturningBoolean(NO, m_webView, @selector(webViewAreToolbarsVisible:));
278}
279
280void WebChromeClient::setStatusbarVisible(bool b)
281{
282    [[m_webView _UIDelegateForwarder] webView:m_webView setStatusBarVisible:b];
283}
284
285bool WebChromeClient::statusbarVisible()
286{
287    return CallUIDelegateReturningBoolean(NO, m_webView, @selector(webViewIsStatusBarVisible:));
288}
289
290void WebChromeClient::setScrollbarsVisible(bool b)
291{
292    [[[m_webView mainFrame] frameView] setAllowsScrolling:b];
293}
294
295bool WebChromeClient::scrollbarsVisible()
296{
297    return [[[m_webView mainFrame] frameView] allowsScrolling];
298}
299
300void WebChromeClient::setMenubarVisible(bool)
301{
302    // The menubar is always visible in Mac OS X.
303    return;
304}
305
306bool WebChromeClient::menubarVisible()
307{
308    // The menubar is always visible in Mac OS X.
309    return true;
310}
311
312void WebChromeClient::setResizable(bool b)
313{
314    [[m_webView _UIDelegateForwarder] webView:m_webView setResizable:b];
315}
316
317void WebChromeClient::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned int lineNumber, const String& sourceURL)
318{
319    id delegate = [m_webView UIDelegate];
320    SEL selector = @selector(webView:addMessageToConsole:);
321    if (![delegate respondsToSelector:selector])
322        return;
323
324    NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:
325        (NSString *)message, @"message", [NSNumber numberWithUnsignedInt:lineNumber], @"lineNumber",
326        (NSString *)sourceURL, @"sourceURL", NULL];
327
328    CallUIDelegate(m_webView, selector, dictionary);
329
330    [dictionary release];
331}
332
333bool WebChromeClient::canRunBeforeUnloadConfirmPanel()
334{
335    return [[m_webView UIDelegate] respondsToSelector:@selector(webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:)];
336}
337
338bool WebChromeClient::runBeforeUnloadConfirmPanel(const String& message, Frame* frame)
339{
340    return CallUIDelegateReturningBoolean(true, m_webView, @selector(webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:), message, kit(frame));
341}
342
343void WebChromeClient::closeWindowSoon()
344{
345    // We need to remove the parent WebView from WebViewSets here, before it actually
346    // closes, to make sure that JavaScript code that executes before it closes
347    // can't find it. Otherwise, window.open will select a closed WebView instead of
348    // opening a new one <rdar://problem/3572585>.
349
350    // We also need to stop the load to prevent further parsing or JavaScript execution
351    // after the window has torn down <rdar://problem/4161660>.
352
353    // FIXME: This code assumes that the UI delegate will respond to a webViewClose
354    // message by actually closing the WebView. Safari guarantees this behavior, but other apps might not.
355    // This approach is an inherent limitation of not making a close execute immediately
356    // after a call to window.close.
357
358    [m_webView setGroupName:nil];
359    [m_webView stopLoading:nil];
360    [m_webView performSelector:@selector(_closeWindow) withObject:nil afterDelay:0.0];
361}
362
363void WebChromeClient::runJavaScriptAlert(Frame* frame, const String& message)
364{
365    id delegate = [m_webView UIDelegate];
366    SEL selector = @selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:);
367    if ([delegate respondsToSelector:selector]) {
368        CallUIDelegate(m_webView, selector, message, kit(frame));
369        return;
370    }
371
372    // Call the old version of the delegate method if it is implemented.
373    selector = @selector(webView:runJavaScriptAlertPanelWithMessage:);
374    if ([delegate respondsToSelector:selector]) {
375        CallUIDelegate(m_webView, selector, message);
376        return;
377    }
378}
379
380bool WebChromeClient::runJavaScriptConfirm(Frame* frame, const String& message)
381{
382    id delegate = [m_webView UIDelegate];
383    SEL selector = @selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:);
384    if ([delegate respondsToSelector:selector])
385        return CallUIDelegateReturningBoolean(NO, m_webView, selector, message, kit(frame));
386
387    // Call the old version of the delegate method if it is implemented.
388    selector = @selector(webView:runJavaScriptConfirmPanelWithMessage:);
389    if ([delegate respondsToSelector:selector])
390        return CallUIDelegateReturningBoolean(NO, m_webView, selector, message);
391
392    return NO;
393}
394
395bool WebChromeClient::runJavaScriptPrompt(Frame* frame, const String& prompt, const String& defaultText, String& result)
396{
397    id delegate = [m_webView UIDelegate];
398    SEL selector = @selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:);
399    if ([delegate respondsToSelector:selector]) {
400        result = (NSString *)CallUIDelegate(m_webView, selector, prompt, defaultText, kit(frame));
401        return !result.isNull();
402    }
403
404    // Call the old version of the delegate method if it is implemented.
405    selector = @selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:);
406    if ([delegate respondsToSelector:selector]) {
407        result = (NSString *)CallUIDelegate(m_webView, selector, prompt, defaultText);
408        return !result.isNull();
409    }
410
411    result = [[WebDefaultUIDelegate sharedUIDelegate] webView:m_webView runJavaScriptTextInputPanelWithPrompt:prompt defaultText:defaultText initiatedByFrame:kit(frame)];
412    return !result.isNull();
413}
414
415bool WebChromeClient::shouldInterruptJavaScript()
416{
417    return CallUIDelegate(m_webView, @selector(webViewShouldInterruptJavaScript:));
418}
419
420void WebChromeClient::setStatusbarText(const String& status)
421{
422    // We want the temporaries allocated here to be released even before returning to the
423    // event loop; see <http://bugs.webkit.org/show_bug.cgi?id=9880>.
424    NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init];
425    CallUIDelegate(m_webView, @selector(webView:setStatusText:), (NSString *)status);
426    [localPool drain];
427}
428
429bool WebChromeClient::tabsToLinks() const
430{
431    return [[m_webView preferences] tabsToLinks];
432}
433
434IntRect WebChromeClient::windowResizerRect() const
435{
436    NSRect rect = [[m_webView window] _growBoxRect];
437    if ([m_webView _usesDocumentViews])
438        return enclosingIntRect(rect);
439    return enclosingIntRect([m_webView convertRect:rect fromView:nil]);
440}
441
442void WebChromeClient::repaint(const IntRect& rect, bool contentChanged, bool immediate, bool repaintContentOnly)
443{
444    if ([m_webView _usesDocumentViews])
445        return;
446
447    if (contentChanged)
448        [m_webView setNeedsDisplayInRect:rect];
449
450    if (immediate) {
451        [[m_webView window] displayIfNeeded];
452        [[m_webView window] flushWindowIfNeeded];
453    }
454}
455
456void WebChromeClient::scroll(const IntSize&, const IntRect&, const IntRect&)
457{
458}
459
460IntPoint WebChromeClient::screenToWindow(const IntPoint& p) const
461{
462    if ([m_webView _usesDocumentViews])
463        return p;
464    NSPoint windowCoord = [[m_webView window] convertScreenToBase:p];
465    return IntPoint([m_webView convertPoint:windowCoord fromView:nil]);
466}
467
468IntRect WebChromeClient::windowToScreen(const IntRect& r) const
469{
470    if ([m_webView _usesDocumentViews])
471        return r;
472    NSRect tempRect = r;
473    tempRect = [m_webView convertRect:tempRect toView:nil];
474    tempRect.origin = [[m_webView window] convertBaseToScreen:tempRect.origin];
475    return enclosingIntRect(tempRect);
476}
477
478PlatformPageClient WebChromeClient::platformPageClient() const
479{
480    if ([m_webView _usesDocumentViews])
481        return 0;
482    return m_webView;
483}
484
485void WebChromeClient::contentsSizeChanged(Frame*, const IntSize&) const
486{
487}
488
489void WebChromeClient::scrollRectIntoView(const IntRect& r, const ScrollView* scrollView) const
490{
491    // FIXME: This scrolling behavior should be under the control of the embedding client (rather than something
492    // we just do ourselves).
493
494    NSRect rect = r;
495    for (NSView *view = m_webView; view; view = [view superview]) {
496        if ([view isKindOfClass:[NSClipView class]]) {
497            NSClipView *clipView = (NSClipView *)view;
498            NSView *documentView = [clipView documentView];
499            [documentView scrollRectToVisible:[documentView convertRect:rect fromView:m_webView]];
500        }
501    }
502}
503
504// End host window methods.
505
506void WebChromeClient::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags)
507{
508    WebElementDictionary *element = [[WebElementDictionary alloc] initWithHitTestResult:result];
509    [m_webView _mouseDidMoveOverElement:element modifierFlags:modifierFlags];
510    [element release];
511}
512
513void WebChromeClient::setToolTip(const String& toolTip, TextDirection)
514{
515    [m_webView _setToolTip:toolTip];
516}
517
518void WebChromeClient::print(Frame* frame)
519{
520    WebFrame *webFrame = kit(frame);
521    if ([[m_webView UIDelegate] respondsToSelector:@selector(webView:printFrame:)])
522        CallUIDelegate(m_webView, @selector(webView:printFrame:), webFrame);
523    else if ([m_webView _usesDocumentViews])
524        CallUIDelegate(m_webView, @selector(webView:printFrameView:), [webFrame frameView]);
525}
526
527#if ENABLE(DATABASE)
528void WebChromeClient::exceededDatabaseQuota(Frame* frame, const String& databaseName)
529{
530    BEGIN_BLOCK_OBJC_EXCEPTIONS;
531
532    WebSecurityOrigin *webOrigin = [[WebSecurityOrigin alloc] _initWithWebCoreSecurityOrigin:frame->document()->securityOrigin()];
533    // FIXME: remove this workaround once shipping Safari has the necessary delegate implemented.
534    if (WKAppVersionCheckLessThan(@"com.apple.Safari", -1, 3.1)) {
535        const unsigned long long defaultQuota = 5 * 1024 * 1024; // 5 megabytes should hopefully be enough to test storage support.
536        [webOrigin setQuota:defaultQuota];
537    } else
538        CallUIDelegate(m_webView, @selector(webView:frame:exceededDatabaseQuotaForSecurityOrigin:database:), kit(frame), webOrigin, (NSString *)databaseName);
539    [webOrigin release];
540
541    END_BLOCK_OBJC_EXCEPTIONS;
542}
543#endif
544
545#if ENABLE(OFFLINE_WEB_APPLICATIONS)
546void WebChromeClient::reachedMaxAppCacheSize(int64_t spaceNeeded)
547{
548    // FIXME: Free some space.
549}
550#endif
551
552void WebChromeClient::populateVisitedLinks()
553{
554    if ([m_webView historyDelegate]) {
555        WebHistoryDelegateImplementationCache* implementations = WebViewGetHistoryDelegateImplementations(m_webView);
556
557        if (implementations->populateVisitedLinksFunc)
558            CallHistoryDelegate(implementations->populateVisitedLinksFunc, m_webView, @selector(populateVisitedLinksForWebView:));
559
560        return;
561    }
562
563    BEGIN_BLOCK_OBJC_EXCEPTIONS;
564    [[WebHistory optionalSharedHistory] _addVisitedLinksToPageGroup:[m_webView page]->group()];
565    END_BLOCK_OBJC_EXCEPTIONS;
566}
567
568#if ENABLE(DASHBOARD_SUPPORT)
569void WebChromeClient::dashboardRegionsChanged()
570{
571    BEGIN_BLOCK_OBJC_EXCEPTIONS;
572
573    NSMutableDictionary *regions = core([m_webView mainFrame])->dashboardRegionsDictionary();
574    [m_webView _addScrollerDashboardRegions:regions];
575
576    CallUIDelegate(m_webView, @selector(webView:dashboardRegionsChanged:), regions);
577
578    END_BLOCK_OBJC_EXCEPTIONS;
579}
580#endif
581
582FloatRect WebChromeClient::customHighlightRect(Node* node, const AtomicString& type, const FloatRect& lineRect)
583{
584    BEGIN_BLOCK_OBJC_EXCEPTIONS;
585
586    NSView *documentView = [[kit(node->document()->frame()) frameView] documentView];
587    if (![documentView isKindOfClass:[WebHTMLView class]])
588        return NSZeroRect;
589
590    WebHTMLView *webHTMLView = (WebHTMLView *)documentView;
591    id<WebHTMLHighlighter> highlighter = [webHTMLView _highlighterForType:type];
592    if ([(NSObject *)highlighter respondsToSelector:@selector(highlightRectForLine:representedNode:)])
593        return [highlighter highlightRectForLine:lineRect representedNode:kit(node)];
594    return [highlighter highlightRectForLine:lineRect];
595
596    END_BLOCK_OBJC_EXCEPTIONS;
597
598    return NSZeroRect;
599}
600
601void WebChromeClient::paintCustomHighlight(Node* node, const AtomicString& type, const FloatRect& boxRect, const FloatRect& lineRect,
602    bool behindText, bool entireLine)
603{
604    BEGIN_BLOCK_OBJC_EXCEPTIONS;
605
606    NSView *documentView = [[kit(node->document()->frame()) frameView] documentView];
607    if (![documentView isKindOfClass:[WebHTMLView class]])
608        return;
609
610    WebHTMLView *webHTMLView = (WebHTMLView *)documentView;
611    id<WebHTMLHighlighter> highlighter = [webHTMLView _highlighterForType:type];
612    if ([(NSObject *)highlighter respondsToSelector:@selector(paintHighlightForBox:onLine:behindText:entireLine:representedNode:)])
613        [highlighter paintHighlightForBox:boxRect onLine:lineRect behindText:behindText entireLine:entireLine representedNode:kit(node)];
614    else
615        [highlighter paintHighlightForBox:boxRect onLine:lineRect behindText:behindText entireLine:entireLine];
616
617    END_BLOCK_OBJC_EXCEPTIONS;
618}
619
620void WebChromeClient::runOpenPanel(Frame*, PassRefPtr<FileChooser> chooser)
621{
622    BEGIN_BLOCK_OBJC_EXCEPTIONS;
623    BOOL allowMultipleFiles = chooser->allowsMultipleFiles();
624    WebOpenPanelResultListener *listener = [[WebOpenPanelResultListener alloc] initWithChooser:chooser];
625    id delegate = [m_webView UIDelegate];
626    if ([delegate respondsToSelector:@selector(webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:)])
627        CallUIDelegate(m_webView, @selector(webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:), listener, allowMultipleFiles);
628    else
629        CallUIDelegate(m_webView, @selector(webView:runOpenPanelForFileButtonWithResultListener:), listener);
630    [listener release];
631    END_BLOCK_OBJC_EXCEPTIONS;
632}
633
634KeyboardUIMode WebChromeClient::keyboardUIMode()
635{
636    BEGIN_BLOCK_OBJC_EXCEPTIONS;
637    return [m_webView _keyboardUIMode];
638    END_BLOCK_OBJC_EXCEPTIONS;
639    return KeyboardAccessDefault;
640}
641
642NSResponder *WebChromeClient::firstResponder()
643{
644    BEGIN_BLOCK_OBJC_EXCEPTIONS;
645    return [[m_webView _UIDelegateForwarder] webViewFirstResponder:m_webView];
646    END_BLOCK_OBJC_EXCEPTIONS;
647    return nil;
648}
649
650void WebChromeClient::makeFirstResponder(NSResponder *responder)
651{
652    BEGIN_BLOCK_OBJC_EXCEPTIONS;
653    [m_webView _pushPerformingProgrammaticFocus];
654    [[m_webView _UIDelegateForwarder] webView:m_webView makeFirstResponder:responder];
655    [m_webView _popPerformingProgrammaticFocus];
656    END_BLOCK_OBJC_EXCEPTIONS;
657}
658
659void WebChromeClient::willPopUpMenu(NSMenu *menu)
660{
661    BEGIN_BLOCK_OBJC_EXCEPTIONS;
662    CallUIDelegate(m_webView, @selector(webView:willPopupMenu:), menu);
663    END_BLOCK_OBJC_EXCEPTIONS;
664}
665
666bool WebChromeClient::shouldReplaceWithGeneratedFileForUpload(const String& path, String& generatedFilename)
667{
668    NSString* filename;
669    if (![[m_webView _UIDelegateForwarder] webView:m_webView shouldReplaceUploadFile:path usingGeneratedFilename:&filename])
670        return false;
671    generatedFilename = filename;
672    return true;
673}
674
675String WebChromeClient::generateReplacementFile(const String& path)
676{
677    return [[m_webView _UIDelegateForwarder] webView:m_webView generateReplacementFile:path];
678}
679
680void WebChromeClient::formStateDidChange(const WebCore::Node* node)
681{
682    CallUIDelegate(m_webView, @selector(webView:formStateDidChangeForNode:), kit(const_cast<WebCore::Node*>(node)));
683}
684
685void WebChromeClient::formDidFocus(const WebCore::Node* node)
686{
687    CallUIDelegate(m_webView, @selector(webView:formDidFocusNode:), kit(const_cast<WebCore::Node*>(node)));
688}
689
690void WebChromeClient::formDidBlur(const WebCore::Node* node)
691{
692    CallUIDelegate(m_webView, @selector(webView:formDidBlurNode:), kit(const_cast<WebCore::Node*>(node)));
693}
694
695#if USE(ACCELERATED_COMPOSITING)
696
697void WebChromeClient::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* graphicsLayer)
698{
699    BEGIN_BLOCK_OBJC_EXCEPTIONS;
700
701    NSView *documentView = [[kit(frame) frameView] documentView];
702    if (![documentView isKindOfClass:[WebHTMLView class]]) {
703        // We should never be attaching when we don't have a WebHTMLView.
704        ASSERT(!graphicsLayer);
705        return;
706    }
707
708    WebHTMLView *webHTMLView = (WebHTMLView *)documentView;
709    if (graphicsLayer)
710        [webHTMLView attachRootLayer:graphicsLayer->nativeLayer()];
711    else
712        [webHTMLView detachRootLayer];
713    END_BLOCK_OBJC_EXCEPTIONS;
714}
715
716void WebChromeClient::setNeedsOneShotDrawingSynchronization()
717{
718    BEGIN_BLOCK_OBJC_EXCEPTIONS;
719    [m_webView _setNeedsOneShotDrawingSynchronization:YES];
720    END_BLOCK_OBJC_EXCEPTIONS;
721}
722
723void WebChromeClient::scheduleCompositingLayerSync()
724{
725    BEGIN_BLOCK_OBJC_EXCEPTIONS;
726    [m_webView _scheduleCompositingLayerSync];
727    END_BLOCK_OBJC_EXCEPTIONS;
728}
729
730#endif
731
732#if ENABLE(VIDEO)
733
734bool WebChromeClient::supportsFullscreenForNode(const Node* node)
735{
736    return node->hasTagName(WebCore::HTMLNames::videoTag);
737}
738
739void WebChromeClient::enterFullscreenForNode(Node* node)
740{
741    BEGIN_BLOCK_OBJC_EXCEPTIONS;
742    [m_webView _enterFullscreenForNode:node];
743    END_BLOCK_OBJC_EXCEPTIONS;
744}
745
746void WebChromeClient::exitFullscreenForNode(Node*)
747{
748    BEGIN_BLOCK_OBJC_EXCEPTIONS;
749    [m_webView _exitFullscreen];
750    END_BLOCK_OBJC_EXCEPTIONS;
751}
752
753#endif
754
755void WebChromeClient::requestGeolocationPermissionForFrame(Frame* frame, Geolocation* geolocation)
756{
757    BEGIN_BLOCK_OBJC_EXCEPTIONS;
758
759    SEL selector = @selector(webView:decidePolicyForGeolocationRequestFromOrigin:frame:listener:);
760    if (![[m_webView UIDelegate] respondsToSelector:selector]) {
761        geolocation->setIsAllowed(false);
762        return;
763    }
764
765    WebSecurityOrigin *webOrigin = [[WebSecurityOrigin alloc] _initWithWebCoreSecurityOrigin:frame->document()->securityOrigin()];
766    WebGeolocationPolicyListener* listener = [[WebGeolocationPolicyListener alloc] initWithGeolocation:geolocation];
767
768    CallUIDelegate(m_webView, selector, webOrigin, kit(frame), listener);
769
770    [webOrigin release];
771    [listener release];
772
773    END_BLOCK_OBJC_EXCEPTIONS;
774}
775
776@implementation WebOpenPanelResultListener
777
778- (id)initWithChooser:(PassRefPtr<FileChooser>)chooser
779{
780    self = [super init];
781    if (!self)
782        return nil;
783    _chooser = chooser.releaseRef();
784    return self;
785}
786
787#ifndef NDEBUG
788
789- (void)dealloc
790{
791    ASSERT(!_chooser);
792    [super dealloc];
793}
794
795- (void)finalize
796{
797    ASSERT(!_chooser);
798    [super finalize];
799}
800
801#endif
802
803- (void)cancel
804{
805    ASSERT(_chooser);
806    if (!_chooser)
807        return;
808    _chooser->deref();
809    _chooser = 0;
810}
811
812- (void)chooseFilename:(NSString *)filename
813{
814    ASSERT(_chooser);
815    if (!_chooser)
816        return;
817    _chooser->chooseFile(filename);
818    _chooser->deref();
819    _chooser = 0;
820}
821
822- (void)chooseFilenames:(NSArray *)filenames
823{
824    ASSERT(_chooser);
825    if (!_chooser)
826        return;
827    int count = [filenames count];
828    Vector<String> names(count);
829    for (int i = 0; i < count; i++)
830        names[i] = [filenames objectAtIndex:i];
831    _chooser->chooseFiles(names);
832    _chooser->deref();
833    _chooser = 0;
834}
835
836@end
837
838@implementation WebGeolocationPolicyListener
839
840- (id)initWithGeolocation:(Geolocation*)geolocation
841{
842    if (!(self = [super init]))
843        return nil;
844    _geolocation = geolocation;
845    return self;
846}
847
848- (void)allow
849{
850    _geolocation->setIsAllowed(true);
851}
852
853- (void)deny
854{
855    _geolocation->setIsAllowed(false);
856}
857
858@end
859