Reviewed by Adam and Steve.
[WebKit-https.git] / WebKit / win / WebChromeClient.cpp
1 /*
2  * Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "WebChromeClient.h"
28
29 #include "WebElementPropertyBag.h"
30 #include "WebFrame.h"
31 #include "WebMutableURLRequest.h"
32 #include "WebView.h"
33 #pragma warning(push, 0)
34 #include <WebCore/BString.h>
35 #include <WebCore/ContextMenu.h>
36 #include <WebCore/FloatRect.h>
37 #include <WebCore/FrameLoadRequest.h>
38 #include <WebCore/FrameView.h>
39 #include <WebCore/NotImplemented.h>
40 #include <WebCore/WindowFeatures.h>
41 #pragma warning(pop)
42
43 using namespace WebCore;
44
45 WebChromeClient::WebChromeClient(WebView* webView)
46     : m_webView(webView)
47 {
48 }
49
50 void WebChromeClient::chromeDestroyed()
51 {
52     delete this;
53 }
54
55 void WebChromeClient::setWindowRect(const FloatRect& r)
56 {
57     IWebUIDelegate* uiDelegate = 0;
58     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
59         RECT rect = IntRect(r);
60         uiDelegate->setFrame(m_webView, &rect);
61         uiDelegate->Release();
62     }
63 }
64
65 FloatRect WebChromeClient::windowRect()
66 {
67     IWebUIDelegate* uiDelegate = 0;
68     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
69         RECT rect;
70         HRESULT retval = uiDelegate->webViewFrame(m_webView, &rect);
71
72         uiDelegate->Release();
73
74         if (SUCCEEDED(retval))
75             return rect;
76     }
77
78     return FloatRect();
79 }
80
81 FloatRect WebChromeClient::pageRect()
82 {
83     RECT rect;
84     m_webView->frameRect(&rect);
85     return rect;
86 }
87
88 float WebChromeClient::scaleFactor()
89 {
90     // Windows doesn't support UI scaling.
91     return 1.0;
92 }
93
94 void WebChromeClient::focus()
95 {
96     IWebUIDelegate* uiDelegate = 0;
97     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
98         uiDelegate->webViewFocus(m_webView);
99         uiDelegate->Release();
100     }
101 }
102
103 void WebChromeClient::unfocus()
104 {
105     IWebUIDelegate* uiDelegate = 0;
106     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
107         uiDelegate->webViewUnfocus(m_webView);
108         uiDelegate->Release();
109     }
110 }
111
112 bool WebChromeClient::canTakeFocus(FocusDirection direction)
113 {
114     IWebUIDelegate* uiDelegate = 0;
115     BOOL bForward = (direction == FocusDirectionForward) ? TRUE : FALSE;
116     BOOL result = FALSE;
117     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
118         uiDelegate->canTakeFocus(m_webView, bForward, &result);
119         uiDelegate->Release();
120     }
121
122     return !!result;
123 }
124
125 void WebChromeClient::takeFocus(FocusDirection direction)
126 {
127     IWebUIDelegate* uiDelegate = 0;
128     BOOL bForward = (direction == FocusDirectionForward) ? TRUE : FALSE;
129     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
130         uiDelegate->takeFocus(m_webView, bForward);
131         uiDelegate->Release();
132     }
133 }
134
135 Page* WebChromeClient::createWindow(Frame*, const FrameLoadRequest& frameLoadRequest, const WindowFeatures& features)
136 {
137     if (features.dialog) {
138         COMPtr<IWebUIDelegate3> delegate = uiDelegate3();
139         if (!delegate)
140             return 0;
141         COMPtr<IWebMutableURLRequest> request(AdoptCOM, WebMutableURLRequest::createInstance(frameLoadRequest.resourceRequest()));
142         COMPtr<IWebView> dialog;
143         if (FAILED(delegate->createModalDialog(m_webView, request.get(), &dialog)))
144             return 0;
145         return core(dialog.get());
146     }
147
148     Page* page = 0;
149     IWebUIDelegate* uiDelegate = 0;
150     IWebMutableURLRequest* request = WebMutableURLRequest::createInstance(frameLoadRequest.resourceRequest());
151
152     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
153         IWebView* webView = 0;
154         if (SUCCEEDED(uiDelegate->createWebViewWithRequest(m_webView, request, &webView))) {
155             page = core(webView);
156             webView->Release();
157         }
158     
159         uiDelegate->Release();
160     }
161
162     request->Release();
163     return page;
164 }
165
166 void WebChromeClient::show()
167 {
168     IWebUIDelegate* uiDelegate = 0;
169     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
170         uiDelegate->webViewShow(m_webView);
171         uiDelegate->Release();
172     }
173 }
174
175 bool WebChromeClient::canRunModal()
176 {
177     BOOL result = FALSE;
178     if (COMPtr<IWebUIDelegate3> delegate = uiDelegate3())
179         delegate->canRunModal(m_webView, &result);
180     return result;
181 }
182
183 void WebChromeClient::runModal()
184 {
185     if (COMPtr<IWebUIDelegate3> delegate = uiDelegate3())
186         delegate->runModal(m_webView);
187 }
188
189 void WebChromeClient::setToolbarsVisible(bool visible)
190 {
191     IWebUIDelegate* uiDelegate = 0;
192     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
193         uiDelegate->setToolbarsVisible(m_webView, visible);
194         uiDelegate->Release();
195     }
196 }
197
198 bool WebChromeClient::toolbarsVisible()
199 {
200     BOOL result = false;
201     IWebUIDelegate* uiDelegate = 0;
202     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
203         uiDelegate->webViewAreToolbarsVisible(m_webView, &result);
204         uiDelegate->Release();
205     }
206     return result != false;
207 }
208
209 void WebChromeClient::setStatusbarVisible(bool visible)
210 {
211     IWebUIDelegate* uiDelegate = 0;
212     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
213         uiDelegate->setStatusBarVisible(m_webView, visible);
214         uiDelegate->Release();
215     }
216 }
217
218 bool WebChromeClient::statusbarVisible()
219 {
220     BOOL result = false;
221     IWebUIDelegate* uiDelegate = 0;
222     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
223         uiDelegate->webViewIsStatusBarVisible(m_webView, &result);
224         uiDelegate->Release();
225     }
226     return result != false;
227 }
228
229 void WebChromeClient::setScrollbarsVisible(bool b)
230 {
231     WebFrame* webFrame = m_webView->topLevelFrame();
232     if (webFrame) {
233         webFrame->setAllowsScrolling(b);
234         FrameView* frameView = core(webFrame)->view();
235         frameView->setHScrollbarMode(frameView->hScrollbarMode());  // I know this looks weird but the call to v/hScrollbarMode goes to ScrollView
236         frameView->setVScrollbarMode(frameView->vScrollbarMode());  // and the call to setV/hScrollbarMode goes to FrameView.
237                                                                     // This oddity is a result of matching a design in the mac code.
238     }
239 }
240
241 bool WebChromeClient::scrollbarsVisible()
242 {
243     WebFrame* webFrame = m_webView->topLevelFrame();
244     BOOL b = false;
245     if (webFrame)
246         webFrame->allowsScrolling(&b);
247
248     return !!b;
249 }
250
251 void WebChromeClient::setMenubarVisible(bool)
252 {
253     IWebUIDelegate* uiDelegate = 0;
254     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
255         notImplemented();
256         uiDelegate->Release();
257     }
258 }
259
260 bool WebChromeClient::menubarVisible()
261 {
262     bool result = false;
263     IWebUIDelegate* uiDelegate = 0;
264     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
265         notImplemented();
266         uiDelegate->Release();
267     }
268     return result;
269 }
270
271 void WebChromeClient::setResizable(bool resizable)
272 {
273     IWebUIDelegate* uiDelegate = 0;
274     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
275         uiDelegate->setResizable(m_webView, resizable);
276         uiDelegate->Release();
277     }
278 }
279
280 void WebChromeClient::addMessageToConsole(const String& message, unsigned line, const String& url)
281 {
282     COMPtr<IWebUIDelegate> uiDelegate;
283     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
284         COMPtr<IWebUIDelegatePrivate> uiPrivate;
285         if (SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&uiPrivate)))
286             uiPrivate->webViewAddMessageToConsole(m_webView, BString(message), line, BString(url), true);
287     }
288 }
289
290 bool WebChromeClient::canRunBeforeUnloadConfirmPanel()
291 {
292     IWebUIDelegate* ui;
293     if (SUCCEEDED(m_webView->uiDelegate(&ui)) && ui) {
294         ui->Release();
295         return true;
296     }
297     return false;
298 }
299
300 bool WebChromeClient::runBeforeUnloadConfirmPanel(const String& message, Frame* frame)
301 {
302     BOOL result = TRUE;
303     IWebUIDelegate* ui;
304     if (SUCCEEDED(m_webView->uiDelegate(&ui)) && ui) {
305         WebFrame* webFrame = kit(frame);
306         ui->runBeforeUnloadConfirmPanelWithMessage(m_webView, BString(message), webFrame, &result);
307         ui->Release();
308     }
309     return !!result;
310 }
311
312 void WebChromeClient::closeWindowSoon()
313 {
314     // We need to remove the parent WebView from WebViewSets here, before it actually
315     // closes, to make sure that JavaScript code that executes before it closes
316     // can't find it. Otherwise, window.open will select a closed WebView instead of 
317     // opening a new one <rdar://problem/3572585>.
318
319     // We also need to stop the load to prevent further parsing or JavaScript execution
320     // after the window has torn down <rdar://problem/4161660>.
321   
322     // FIXME: This code assumes that the UI delegate will respond to a webViewClose
323     // message by actually closing the WebView. Safari guarantees this behavior, but other apps might not.
324     // This approach is an inherent limitation of not making a close execute immediately
325     // after a call to window.close.
326
327     m_webView->setGroupName(0);
328     m_webView->stopLoading(0);
329     m_webView->closeWindowSoon();
330 }
331
332 void WebChromeClient::runJavaScriptAlert(Frame*, const String& message)
333 {
334     COMPtr<IWebUIDelegate> ui;
335     if (SUCCEEDED(m_webView->uiDelegate(&ui)))
336         ui->runJavaScriptAlertPanelWithMessage(m_webView, BString(message));
337 }
338
339 bool WebChromeClient::runJavaScriptConfirm(Frame*, const String& message)
340 {
341     BOOL result = FALSE;
342     COMPtr<IWebUIDelegate> ui;
343     if (SUCCEEDED(m_webView->uiDelegate(&ui)))
344         ui->runJavaScriptConfirmPanelWithMessage(m_webView, BString(message), &result);
345     return !!result;
346 }
347
348 bool WebChromeClient::runJavaScriptPrompt(Frame*, const String& message, const String& defaultValue, String& result)
349 {
350     COMPtr<IWebUIDelegate> ui;
351     if (FAILED(m_webView->uiDelegate(&ui)))
352         return false;
353
354     BSTR resultBSTR = 0;
355     if (FAILED(ui->runJavaScriptTextInputPanelWithPrompt(m_webView, BString(message), BString(defaultValue), &resultBSTR)))
356         return false;
357
358     if (resultBSTR) {
359         result = String(resultBSTR, SysStringLen(resultBSTR));
360         SysFreeString(resultBSTR);
361         return true;
362     }
363
364     return false;
365 }
366
367 void WebChromeClient::setStatusbarText(const String& statusText)
368 {
369     COMPtr<IWebUIDelegate> uiDelegate;
370     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
371         uiDelegate->setStatusText(m_webView, BString(statusText));
372     }
373 }
374
375 bool WebChromeClient::shouldInterruptJavaScript()
376 {
377     COMPtr<IWebUIDelegate> uiDelegate;
378     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
379         COMPtr<IWebUIDelegatePrivate> uiPrivate;
380         if (SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&uiPrivate))) {
381             BOOL result;
382             if (SUCCEEDED(uiPrivate->webViewShouldInterruptJavaScript(m_webView, &result)))
383                 return !!result;
384         }
385     }
386     return false;
387 }
388
389 bool WebChromeClient::tabsToLinks() const
390 {
391     BOOL enabled = FALSE;
392     IWebPreferences* preferences;
393     if (SUCCEEDED(m_webView->preferences(&preferences)))
394         preferences->tabsToLinks(&enabled);
395
396     return !!enabled;
397 }
398
399 IntRect WebChromeClient::windowResizerRect() const
400 {
401     IntRect intRect;
402
403     IWebUIDelegate* ui;
404     if (SUCCEEDED(m_webView->uiDelegate(&ui)) && ui) {
405         IWebUIDelegatePrivate* uiPrivate;
406         if (SUCCEEDED(ui->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&uiPrivate))) {
407             RECT r;
408             if (SUCCEEDED(uiPrivate->webViewResizerRect(m_webView, &r)))
409                 intRect = IntRect(r.left, r.top, r.right-r.left, r.bottom-r.top);
410             uiPrivate->Release();
411         }
412         ui->Release();
413     }
414     return intRect;
415 }
416
417 void WebChromeClient::addToDirtyRegion(const IntRect& dirtyRect)
418 {
419     m_webView->addToDirtyRegion(dirtyRect);
420 }
421
422 void WebChromeClient::scrollBackingStore(int dx, int dy, const IntRect& scrollViewRect, const IntRect& clipRect)
423 {
424     ASSERT(core(m_webView->topLevelFrame()));
425
426     m_webView->scrollBackingStore(core(m_webView->topLevelFrame())->view(), dx, dy, scrollViewRect, clipRect);
427 }
428
429 void WebChromeClient::updateBackingStore()
430 {
431     ASSERT(core(m_webView->topLevelFrame()));
432
433     m_webView->updateBackingStore(core(m_webView->topLevelFrame())->view(), 0, false);
434 }
435
436 void WebChromeClient::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags)
437 {
438     COMPtr<IWebUIDelegate> uiDelegate;
439     if (FAILED(m_webView->uiDelegate(&uiDelegate)))
440         return;
441
442     COMPtr<WebElementPropertyBag> element;
443     element.adoptRef(WebElementPropertyBag::createInstance(result));
444
445     uiDelegate->mouseDidMoveOverElement(m_webView, element.get(), modifierFlags);
446 }
447
448 void WebChromeClient::setToolTip(const String& toolTip)
449 {
450     m_webView->setToolTip(toolTip);
451 }
452
453 void WebChromeClient::print(Frame* frame)
454 {
455     COMPtr<IWebUIDelegate> uiDelegate;
456     COMPtr<IWebUIDelegate2> uiDelegate2;
457     if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate)))
458         if (SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegate2, (void**)&uiDelegate2)))
459             uiDelegate2->printFrame(m_webView, kit(frame));
460 }
461
462 bool WebChromeClient::runDatabaseSizeLimitPrompt(Frame*, const String&)
463 {
464     notImplemented();
465     return false;
466 }
467
468 COMPtr<IWebUIDelegate> WebChromeClient::uiDelegate()
469 {
470     COMPtr<IWebUIDelegate> delegate;
471     m_webView->uiDelegate(&delegate);
472     return delegate;
473 }
474
475 COMPtr<IWebUIDelegate2> WebChromeClient::uiDelegate2()
476 {
477     return COMPtr<IWebUIDelegate2>(Query, uiDelegate());
478 }
479
480 COMPtr<IWebUIDelegate3> WebChromeClient::uiDelegate3()
481 {
482     return COMPtr<IWebUIDelegate3>(Query, uiDelegate());
483 }