bfa6ed6d29ce6d42da3cbc743e7275dbf3e6d247
[WebKit-https.git] / WebKit / WebCoreSupport / WebChromeClient.mm
1 /*
2  * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
3  * Copyright (C) 2007 Trolltech ASA
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 "WebDefaultUIDelegate.h"
33 #import "WebFrameInternal.h"
34 #import "WebFrameView.h"
35 #import "WebHTMLView.h"
36 #import "WebNSURLRequestExtras.h"
37 #import "WebUIDelegate.h"
38 #import "WebUIDelegatePrivate.h"
39 #import "WebView.h"
40 #import "WebViewInternal.h"
41 #import <WebCore/BlockExceptions.h>
42 #import <WebCore/FloatRect.h>
43 #import <WebCore/FrameLoadRequest.h>
44 #import <WebCore/IntRect.h>
45 #import <WebCore/PlatformString.h>
46 #import <WebCore/ResourceRequest.h>
47 #import <WebCore/Screen.h>
48 #import <wtf/PassRefPtr.h>
49
50 @interface NSView (AppKitSecretsWebBridgeKnowsAbout)
51 - (NSView *)_findLastViewInKeyViewLoop;
52 @end
53
54 using namespace WebCore;
55
56 WebChromeClient::WebChromeClient(WebView *webView) 
57     : m_webView(webView)
58 {
59 }
60
61 void WebChromeClient::chromeDestroyed()
62 {
63     delete this;
64 }
65
66 // These functions scale between window and WebView coordinates because JavaScript/DOM operations 
67 // assume that the WebView and the window share the same coordinate system.
68
69 void WebChromeClient::setWindowRect(const FloatRect& rect)
70 {
71     NSRect windowRect = toDeviceSpace(rect, [m_webView window]);
72     [[m_webView _UIDelegateForwarder] webView:m_webView setFrame:windowRect];
73 }
74
75 FloatRect WebChromeClient::windowRect()
76 {
77     NSRect windowRect = [[m_webView _UIDelegateForwarder] webViewFrame:m_webView];
78     return toUserSpace(windowRect, [m_webView window]);
79 }
80
81 // FIXME: We need to add API for setting and getting this.
82 FloatRect WebChromeClient::pageRect()
83 {
84     return [m_webView frame];
85 }
86
87 float WebChromeClient::scaleFactor()
88 {
89     return [[m_webView window] userSpaceScaleFactor];
90 }
91
92 void WebChromeClient::focus()
93 {
94     [[m_webView _UIDelegateForwarder] webViewFocus:m_webView];
95 }
96
97 void WebChromeClient::unfocus()
98 {
99     [[m_webView _UIDelegateForwarder] webViewUnfocus:m_webView];
100 }
101
102 bool WebChromeClient::canTakeFocus(FocusDirection)
103 {
104     // There's unfortunately no way to determine if we will become first responder again
105     // once we give it up, so we just have to guess that we won't.
106     return true;
107 }
108
109 void WebChromeClient::takeFocus(FocusDirection direction)
110 {
111     if (direction == FocusDirectionForward) {
112         // Since we're trying to move focus out of m_webView, and because
113         // m_webView may contain subviews within it, we ask it for the next key
114         // view of the last view in its key view loop. This makes m_webView
115         // behave as if it had no subviews, which is the behavior we want.
116         NSView *lastView = [m_webView _findLastViewInKeyViewLoop];
117         [[m_webView window] selectKeyViewFollowingView:lastView];
118     } else
119         [[m_webView window] selectKeyViewPrecedingView:m_webView];
120 }
121
122 Page* WebChromeClient::createWindow(const FrameLoadRequest& request)
123 {
124     NSURLRequest *URLRequest = nil;
125     if (!request.isEmpty())
126         URLRequest = request.resourceRequest().nsURLRequest();
127
128     WebView *newWebView;
129     id delegate = [m_webView UIDelegate];
130     if ([delegate respondsToSelector:@selector(webView:createWebViewWithRequest:)])
131         newWebView = [delegate webView:m_webView createWebViewWithRequest:URLRequest];
132     else
133         newWebView = [[WebDefaultUIDelegate sharedUIDelegate] webView:m_webView createWebViewWithRequest:URLRequest];
134
135     return core(newWebView);
136 }
137
138 Page* WebChromeClient::createModalDialog(const FrameLoadRequest& request)
139 {
140     NSURLRequest *URLRequest = nil;
141     if (!request.isEmpty())
142         URLRequest = request.resourceRequest().nsURLRequest();
143
144     WebView *newWebView = nil;
145     id delegate = [m_webView UIDelegate];
146     if ([delegate respondsToSelector:@selector(webView:createWebViewModalDialogWithRequest:)])
147         newWebView = [delegate webView:m_webView createWebViewModalDialogWithRequest:URLRequest];
148     else if ([delegate respondsToSelector:@selector(webView:createWebViewWithRequest:)])
149         newWebView = [delegate webView:m_webView createWebViewWithRequest:URLRequest];
150     else
151         newWebView = [[WebDefaultUIDelegate sharedUIDelegate] webView:m_webView createWebViewWithRequest:URLRequest];
152
153     return core(newWebView);
154 }
155
156 void WebChromeClient::show()
157 {
158     [[m_webView _UIDelegateForwarder] webViewShow:m_webView];
159 }
160
161 bool WebChromeClient::canRunModal()
162 {
163     return [[m_webView UIDelegate] respondsToSelector:@selector(webViewRunModal:)];
164 }
165
166 void WebChromeClient::runModal()
167 {
168     [[m_webView UIDelegate] webViewRunModal:m_webView];
169 }
170
171 void WebChromeClient::setToolbarsVisible(bool b)
172 {
173     [[m_webView _UIDelegateForwarder] webView:m_webView setToolbarsVisible:b];
174 }
175
176 bool WebChromeClient::toolbarsVisible()
177 {
178     id delegate = [m_webView UIDelegate];
179     if ([delegate respondsToSelector:@selector(webViewAreToolbarsVisible:)])
180         return [delegate webViewAreToolbarsVisible:m_webView];
181     return [[WebDefaultUIDelegate sharedUIDelegate] webViewAreToolbarsVisible:m_webView];
182 }
183
184 void WebChromeClient::setStatusbarVisible(bool b)
185 {
186     [[m_webView _UIDelegateForwarder] webView:m_webView setStatusBarVisible:b];
187 }
188
189 bool WebChromeClient::statusbarVisible()
190 {
191     id delegate = [m_webView UIDelegate];
192     if ([delegate respondsToSelector:@selector(webViewIsStatusBarVisible:)])
193         return [delegate webViewIsStatusBarVisible:m_webView];
194     return [[WebDefaultUIDelegate sharedUIDelegate] webViewIsStatusBarVisible:m_webView];
195 }
196
197
198 void WebChromeClient::setScrollbarsVisible(bool b)
199 {
200     [[[m_webView mainFrame] frameView] setAllowsScrolling:b];
201 }
202
203 bool WebChromeClient::scrollbarsVisible()
204 {
205     return [[[m_webView mainFrame] frameView] allowsScrolling];
206 }
207
208 void WebChromeClient::setMenubarVisible(bool)
209 {
210     // The menubar is always visible in Mac OS X.
211     return;
212 }
213
214 bool WebChromeClient::menubarVisible()
215 {
216     // The menubar is always visible in Mac OS X.
217     return true;
218 }
219
220 void WebChromeClient::setResizable(bool b)
221 {
222     [[m_webView _UIDelegateForwarder] webView:m_webView setResizable:b];
223 }
224
225 void WebChromeClient::addMessageToConsole(const String& message, unsigned int lineNumber, const String& sourceURL)
226 {
227     id wd = [m_webView UIDelegate];
228     if ([wd respondsToSelector:@selector(webView:addMessageToConsole:)]) {
229         NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
230             (NSString *)message, @"message",
231             [NSNumber numberWithInt: lineNumber], @"lineNumber",
232             (NSString *)sourceURL, @"sourceURL",
233             NULL];
234         
235         [wd webView:m_webView addMessageToConsole:dictionary];
236     }    
237 }
238
239 bool WebChromeClient::canRunBeforeUnloadConfirmPanel()
240 {
241     id wd = [m_webView UIDelegate];
242     return [wd respondsToSelector:@selector(webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:)];
243 }
244
245 bool WebChromeClient::runBeforeUnloadConfirmPanel(const String& message, Frame* frame)
246 {
247     id wd = [m_webView UIDelegate];
248     if ([wd respondsToSelector:@selector(webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:)])
249         return [wd webView:m_webView runBeforeUnloadConfirmPanelWithMessage:message initiatedByFrame:kit(frame)];
250     return true;
251 }
252
253 void WebChromeClient::closeWindowSoon()
254 {
255     // We need to remove the parent WebView from WebViewSets here, before it actually
256     // closes, to make sure that JavaScript code that executes before it closes
257     // can't find it. Otherwise, window.open will select a closed WebView instead of 
258     // opening a new one <rdar://problem/3572585>.
259
260     // We also need to stop the load to prevent further parsing or JavaScript execution
261     // after the window has torn down <rdar://problem/4161660>.
262   
263     // FIXME: This code assumes that the UI delegate will respond to a webViewClose
264     // message by actually closing the WebView. Safari guarantees this behavior, but other apps might not.
265     // This approach is an inherent limitation of not making a close execute immediately
266     // after a call to window.close.
267
268     [m_webView setGroupName:nil];
269     [m_webView stopLoading:nil];
270     [m_webView performSelector:@selector(_closeWindow) withObject:nil afterDelay:0.0];
271 }
272
273 void WebChromeClient::runJavaScriptAlert(Frame* frame, const String& message)
274 {
275     id wd = [m_webView UIDelegate];
276     // Check whether delegate implements new version, then whether delegate implements old version. If neither,
277     // fall back to shared delegate's implementation of new version.
278     if ([wd respondsToSelector:@selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:)])
279         [wd webView:m_webView runJavaScriptAlertPanelWithMessage:message initiatedByFrame:kit(frame)];
280     else if ([wd respondsToSelector:@selector(webView:runJavaScriptAlertPanelWithMessage:)])
281         [wd webView:m_webView runJavaScriptAlertPanelWithMessage:message];
282     else
283         [[WebDefaultUIDelegate sharedUIDelegate] webView:m_webView runJavaScriptAlertPanelWithMessage:message initiatedByFrame:kit(frame)];    
284 }
285
286 bool WebChromeClient::runJavaScriptConfirm(Frame* frame, const String& message)
287 {
288     id wd = [m_webView UIDelegate];
289     // Check whether delegate implements new version, then whether delegate implements old version. If neither,
290     // fall back to shared delegate's implementation of new version.
291     if ([wd respondsToSelector:@selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:)])
292         return [wd webView:m_webView runJavaScriptConfirmPanelWithMessage:message initiatedByFrame:kit(frame)];
293     if ([wd respondsToSelector:@selector(webView:runJavaScriptConfirmPanelWithMessage:)])
294         return [wd webView:m_webView runJavaScriptConfirmPanelWithMessage:message];    
295     return [[WebDefaultUIDelegate sharedUIDelegate] webView:m_webView runJavaScriptConfirmPanelWithMessage:message initiatedByFrame:kit(frame)];
296 }
297
298 bool WebChromeClient::runJavaScriptPrompt(Frame* frame, const String& prompt, const String& defaultText, String& result)
299 {
300     id wd = [m_webView UIDelegate];
301     // Check whether delegate implements new version, then whether delegate implements old version. If neither,
302     // fall back to shared delegate's implementation of new version.
303     if ([wd respondsToSelector:@selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:)])
304         result = [wd webView:m_webView runJavaScriptTextInputPanelWithPrompt:prompt defaultText:defaultText initiatedByFrame:kit(frame)];
305     else if ([wd respondsToSelector:@selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:)])
306         result = [wd webView:m_webView runJavaScriptTextInputPanelWithPrompt:prompt defaultText:defaultText];
307     else
308         result = [[WebDefaultUIDelegate sharedUIDelegate] webView:m_webView runJavaScriptTextInputPanelWithPrompt:prompt defaultText:defaultText initiatedByFrame:kit(frame)];
309     
310     return !result.isNull();
311 }
312
313 bool WebChromeClient::shouldInterruptJavaScript()
314 {
315     BEGIN_BLOCK_OBJC_EXCEPTIONS;
316     id wd = [m_webView UIDelegate];
317     if ([wd respondsToSelector:@selector(webViewShouldInterruptJavaScript:)])
318         return [wd webViewShouldInterruptJavaScript:m_webView];
319     return false;
320     END_BLOCK_OBJC_EXCEPTIONS;
321     
322     return false;
323 }
324
325 void WebChromeClient::setStatusbarText(const WebCore::String& status)
326 {
327     id wd = [m_webView UIDelegate];
328
329     if ([wd respondsToSelector:@selector(webView:setStatusText:)]) {
330         // We want the temporaries allocated here to be released even before returning to the 
331         // event loop; see <http://bugs.webkit.org/show_bug.cgi?id=9880>.
332         NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init];
333     
334         [wd webView:m_webView setStatusText:status];
335         
336         [localPool release];
337     }
338 }
339
340 bool WebChromeClient::tabsToLinks() const
341 {
342     return [[m_webView preferences] tabsToLinks];
343 }
344
345 IntRect WebChromeClient::windowResizerRect() const
346 {
347     return IntRect();
348 }
349
350 void WebChromeClient::addToDirtyRegion(const IntRect&)
351 {
352 }
353
354 void WebChromeClient::scrollBackingStore(int, int, const IntRect&, const IntRect&)
355 {
356 }
357
358 void WebChromeClient::updateBackingStore()
359 {
360 }