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