802ede6d613770b6910a6e3fdc7eab3aee0b769a
[WebKit.git] / Source / WebKit2 / UIProcess / qt / ClientImpl.cpp
1 /*
2     Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
3
4     This library is free software; you can redistribute it and/or
5     modify it under the terms of the GNU Library General Public
6     License as published by the Free Software Foundation; either
7     version 2 of the License, or (at your option) any later version.
8
9     This library is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12     Library General Public License for more details.
13
14     You should have received a copy of the GNU Library General Public License
15     along with this library; see the file COPYING.LIB.  If not, write to
16     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17     Boston, MA 02110-1301, USA.
18 */
19
20 #include "config.h"
21 #include "ClientImpl.h"
22
23 #include "QtWebError.h"
24 #include "WebFrameProxy.h"
25 #include "WKAPICast.h"
26 #include "WKStringQt.h"
27 #include "WKURLQt.h"
28 #include <QtPolicyInterface.h>
29 #include <QtViewInterface.h>
30 #include <QtWebPageProxy.h>
31 #include <WKArray.h>
32 #include <WKFrame.h>
33 #include <WKFramePolicyListener.h>
34 #include <WKHitTestResult.h>
35 #include <WKOpenPanelParameters.h>
36 #include <WKOpenPanelResultListener.h>
37 #include <WKPage.h>
38 #include <WKString.h>
39 #include <WKType.h>
40 #include <WKURLRequest.h>
41
42 using namespace WebKit;
43
44 static QtWebPageProxy* toQtWebPageProxy(const void* clientInfo)
45 {
46     if (clientInfo)
47         return reinterpret_cast<QtWebPageProxy*>(const_cast<void*>(clientInfo));
48     return 0;
49 }
50
51 static inline QtViewInterface* toQtViewInterface(const void* clientInfo)
52 {
53     ASSERT(clientInfo);
54     return reinterpret_cast<QtViewInterface*>(const_cast<void*>(clientInfo));
55 }
56
57 static inline QtPolicyInterface* toQtPolicyInterface(const void* clientInfo)
58 {
59     ASSERT(clientInfo);
60     return reinterpret_cast<QtPolicyInterface*>(const_cast<void*>(clientInfo));
61 }
62
63 static void dispatchLoadSucceeded(WKFrameRef frame, const void* clientInfo)
64 {
65     if (!WKFrameIsMainFrame(frame))
66         return;
67
68     toQtWebPageProxy(clientInfo)->updateNavigationState();
69     toQtWebPageProxy(clientInfo)->loadDidSucceed();
70 }
71
72 static void dispatchLoadFailed(WKFrameRef frame, const void* clientInfo, WKErrorRef error)
73 {
74     if (!WKFrameIsMainFrame(frame))
75         return;
76
77     toQtWebPageProxy(clientInfo)->updateNavigationState();
78
79     int errorCode = WKErrorGetErrorCode(error);
80     if (toImpl(error)->platformError().isCancellation() || errorCode == kWKErrorCodeFrameLoadInterruptedByPolicyChange || errorCode == kWKErrorCodePlugInWillHandleLoad)
81         return;
82
83     toQtWebPageProxy(clientInfo)->loadDidFail(QtWebError(error));
84 }
85
86 static void qt_wk_didStartProvisionalLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
87 {
88     if (!WKFrameIsMainFrame(frame))
89         return;
90
91     toQtWebPageProxy(clientInfo)->updateNavigationState();
92     toQtWebPageProxy(clientInfo)->loadDidBegin();
93 }
94
95 static void qt_wk_didFailProvisionalLoadWithErrorForFrame(WKPageRef page, WKFrameRef frame, WKErrorRef error, WKTypeRef userData, const void* clientInfo)
96 {
97     dispatchLoadFailed(frame, clientInfo, error);
98 }
99
100 static void qt_wk_didCommitLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
101 {
102     if (!WKFrameIsMainFrame(frame))
103         return;
104     WebFrameProxy* wkframe = toImpl(frame);
105     QString urlStr(wkframe->url());
106     QUrl qUrl = urlStr;
107     toQtWebPageProxy(clientInfo)->updateNavigationState();
108     toQtWebPageProxy(clientInfo)->didChangeUrl(qUrl);
109     toQtWebPageProxy(clientInfo)->loadDidCommit();
110 }
111
112 static void qt_wk_didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
113 {
114     dispatchLoadSucceeded(frame, clientInfo);
115 }
116
117 static void qt_wk_didFailLoadWithErrorForFrame(WKPageRef page, WKFrameRef frame, WKErrorRef error, WKTypeRef userData, const void* clientInfo)
118 {
119     dispatchLoadFailed(frame, clientInfo, error);
120 }
121
122 static void qt_wk_didSameDocumentNavigationForFrame(WKPageRef page, WKFrameRef frame, WKSameDocumentNavigationType type, WKTypeRef userData, const void* clientInfo)
123 {
124     WebFrameProxy* wkframe = toImpl(frame);
125     QString urlStr(wkframe->url());
126     QUrl qUrl = urlStr;
127     toQtWebPageProxy(clientInfo)->updateNavigationState();
128     toQtWebPageProxy(clientInfo)->didChangeUrl(qUrl);
129 }
130
131 static void qt_wk_didReceiveTitleForFrame(WKPageRef page, WKStringRef title, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
132 {
133     if (!WKFrameIsMainFrame(frame))
134         return;
135     QString qTitle = WKStringCopyQString(title);
136     toQtWebPageProxy(clientInfo)->didChangeTitle(qTitle);
137 }
138
139 static void qt_wk_didStartProgress(WKPageRef page, const void* clientInfo)
140 {
141     toQtWebPageProxy(clientInfo)->didChangeLoadProgress(0);
142 }
143
144 static void qt_wk_didChangeProgress(WKPageRef page, const void* clientInfo)
145 {
146     toQtWebPageProxy(clientInfo)->didChangeLoadProgress(WKPageGetEstimatedProgress(page) * 100);
147 }
148
149 static void qt_wk_didFinishProgress(WKPageRef page, const void* clientInfo)
150 {
151     toQtWebPageProxy(clientInfo)->didChangeLoadProgress(100);
152 }
153
154 static void qt_wk_runJavaScriptAlert(WKPageRef page, WKStringRef alertText, WKFrameRef frame, const void* clientInfo)
155 {
156     QString qAlertText = WKStringCopyQString(alertText);
157     toQtViewInterface(clientInfo)->runJavaScriptAlert(qAlertText);
158 }
159
160 static bool qt_wk_runJavaScriptConfirm(WKPageRef, WKStringRef message, WKFrameRef, const void* clientInfo)
161 {
162     QString qMessage = WKStringCopyQString(message);
163     return toQtViewInterface(clientInfo)->runJavaScriptConfirm(qMessage);
164 }
165
166 static inline WKStringRef createNullWKString()
167 {
168     RefPtr<WebString> webString = WebString::createNull();
169     return toAPI(webString.release().leakRef());
170 }
171
172 static WKStringRef qt_wk_runJavaScriptPrompt(WKPageRef, WKStringRef message, WKStringRef defaultValue, WKFrameRef, const void* clientInfo)
173 {
174     QString qMessage = WKStringCopyQString(message);
175     QString qDefaultValue = WKStringCopyQString(defaultValue);
176     bool ok = false;
177     QString result = toQtViewInterface(clientInfo)->runJavaScriptPrompt(qMessage, qDefaultValue, ok);
178     if (!ok)
179         return createNullWKString();
180     return WKStringCreateWithQString(result);
181 }
182
183 static void qt_wk_setStatusText(WKPageRef, WKStringRef text, const void *clientInfo)
184 {
185     QString qText = WKStringCopyQString(text);
186     toQtViewInterface(clientInfo)->didChangeStatusText(qText);
187 }
188
189 static void qt_wk_runOpenPanel(WKPageRef, WKFrameRef, WKOpenPanelParametersRef parameters, WKOpenPanelResultListenerRef listener, const void* clientInfo)
190 {
191     Vector<String> wkSelectedFileNames = toImpl(parameters)->selectedFileNames();
192
193     QStringList selectedFileNames;
194     if (!wkSelectedFileNames.isEmpty())
195         for (unsigned i = 0; wkSelectedFileNames.size(); ++i)
196             selectedFileNames += wkSelectedFileNames.at(i);
197
198     QtViewInterface::FileChooserType allowMultipleFiles = WKOpenPanelParametersGetAllowsMultipleFiles(parameters) ? QtViewInterface::MultipleFilesSelection : QtViewInterface::SingleFileSelection;
199     toQtViewInterface(clientInfo)->chooseFiles(listener, selectedFileNames, allowMultipleFiles);
200 }
201
202 static void qt_wk_mouseDidMoveOverElement(WKPageRef page, WKHitTestResultRef hitTestResult, WKEventModifiers modifiers, WKTypeRef userData, const void* clientInfo)
203 {
204     const QUrl absoluteLinkUrl = WKURLCopyQUrl(WKHitTestResultCopyAbsoluteLinkURL(hitTestResult));
205     const QString linkTitle = WKStringCopyQString(WKHitTestResultCopyLinkTitle(hitTestResult));
206     toQtViewInterface(clientInfo)->didMouseMoveOverElement(absoluteLinkUrl, linkTitle);
207 }
208
209 static Qt::MouseButton toQtMouseButton(WKEventMouseButton button)
210 {
211     switch (button) {
212     case kWKEventMouseButtonLeftButton:
213         return Qt::LeftButton;
214     case kWKEventMouseButtonMiddleButton:
215         return Qt::MiddleButton;
216     case kWKEventMouseButtonRightButton:
217         return Qt::RightButton;
218     }
219     return Qt::NoButton;
220 }
221
222 static Qt::KeyboardModifiers toQtKeyboardModifiers(WKEventModifiers modifiers)
223 {
224     Qt::KeyboardModifiers qtModifiers = Qt::NoModifier;
225     if (modifiers & kWKEventModifiersShiftKey)
226         qtModifiers |= Qt::ShiftModifier;
227     if (modifiers & kWKEventModifiersControlKey)
228         qtModifiers |= Qt::ControlModifier;
229     if (modifiers & kWKEventModifiersAltKey)
230         qtModifiers |= Qt::AltModifier;
231     if (modifiers & kWKEventModifiersMetaKey)
232         qtModifiers |= Qt::MetaModifier;
233     return qtModifiers;
234 }
235
236 static void qt_wk_decidePolicyForNavigationAction(WKPageRef page, WKFrameRef frame, WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, WKURLRequestRef request, WKFramePolicyListenerRef listener, WKTypeRef userData, const void* clientInfo)
237 {
238     QtPolicyInterface* policyInterface = toQtPolicyInterface(clientInfo);
239     WKURLRef requestURL = WKURLRequestCopyURL(request);
240     QUrl qUrl = WKURLCopyQUrl(requestURL);
241     WKRelease(requestURL);
242
243     QtPolicyInterface::PolicyAction action = policyInterface->navigationPolicyForURL(qUrl, toQtMouseButton(mouseButton), toQtKeyboardModifiers(modifiers));
244     switch (action) {
245     case QtPolicyInterface::Use:
246         WKFramePolicyListenerUse(listener);
247         break;
248     case QtPolicyInterface::Download:
249         WKFramePolicyListenerDownload(listener);
250         break;
251     case QtPolicyInterface::Ignore:
252         WKFramePolicyListenerIgnore(listener);
253         break;
254     }
255 }
256
257 static void qt_wk_decidePolicyForResponse(WKPageRef page, WKFrameRef frame, WKURLResponseRef response, WKURLRequestRef request, WKFramePolicyListenerRef listener, WKTypeRef userData, const void* clientInfo)
258 {
259     String type = toImpl(response)->resourceResponse().mimeType();
260     type.makeLower();
261     bool canShowMIMEType = toImpl(frame)->canShowMIMEType(type);
262
263     if (WKPageGetMainFrame(page) == frame) {
264         if (canShowMIMEType) {
265             WKFramePolicyListenerUse(listener);
266             return;
267         }
268
269         // If we can't use (show) it then we should download it.
270         WKFramePolicyListenerDownload(listener);
271         return;
272     }
273
274     // We should ignore downloadable top-level content for subframes, with an exception for text/xml and application/xml so we can still support Acid3 test.
275     // It makes the browser intentionally behave differently when it comes to text(application)/xml content in subframes vs. mainframe.
276     if (!canShowMIMEType && !(type == "text/xml" || type == "application/xml")) {
277         WKFramePolicyListenerIgnore(listener);
278         return;
279     }
280
281     WKFramePolicyListenerUse(listener);
282 }
283
284 void qt_wk_didReceiveMessageFromInjectedBundle(WKContextRef, WKStringRef messageName, WKTypeRef messageBody, const void*)
285 {
286     if (!WKStringIsEqualToUTF8CString(messageName, "MessageFromNavigatorQtObject"))
287         return;
288
289     ASSERT(messageBody);
290     ASSERT(WKGetTypeID(messageBody) == WKArrayGetTypeID());
291
292     WKArrayRef body = static_cast<WKArrayRef>(messageBody);
293     ASSERT(WKArrayGetSize(body) == 2);
294     ASSERT(WKGetTypeID(WKArrayGetItemAtIndex(body, 0)) == WKPageGetTypeID());
295     ASSERT(WKGetTypeID(WKArrayGetItemAtIndex(body, 1)) == WKStringGetTypeID());
296
297     WKPageRef page = static_cast<WKPageRef>(WKArrayGetItemAtIndex(body, 0));
298     WKStringRef str = static_cast<WKStringRef>(WKArrayGetItemAtIndex(body, 1));
299
300     toImpl(page)->didReceiveMessageFromNavigatorQtObject(toImpl(str)->string());
301 }
302
303 void setupPageLoaderClient(QtWebPageProxy* qtWebPageProxy, WebPageProxy* webPageProxy)
304 {
305     WKPageLoaderClient loadClient;
306     memset(&loadClient, 0, sizeof(WKPageLoaderClient));
307     loadClient.version = kWKPageLoaderClientCurrentVersion;
308     loadClient.clientInfo = qtWebPageProxy;
309     loadClient.didStartProvisionalLoadForFrame = qt_wk_didStartProvisionalLoadForFrame;
310     loadClient.didFailProvisionalLoadWithErrorForFrame = qt_wk_didFailProvisionalLoadWithErrorForFrame;
311     loadClient.didCommitLoadForFrame = qt_wk_didCommitLoadForFrame;
312     loadClient.didFinishLoadForFrame = qt_wk_didFinishLoadForFrame;
313     loadClient.didFailLoadWithErrorForFrame = qt_wk_didFailLoadWithErrorForFrame;
314     loadClient.didSameDocumentNavigationForFrame = qt_wk_didSameDocumentNavigationForFrame;
315     loadClient.didReceiveTitleForFrame = qt_wk_didReceiveTitleForFrame;
316     loadClient.didStartProgress = qt_wk_didStartProgress;
317     loadClient.didChangeProgress = qt_wk_didChangeProgress;
318     loadClient.didFinishProgress = qt_wk_didFinishProgress;
319     WKPageSetPageLoaderClient(qtWebPageProxy->pageRef(), &loadClient);
320 }
321
322 void setupPageUiClient(QtWebPageProxy* qtWebPageProxy, WebPageProxy* webPageProxy)
323 {
324     WKPageUIClient uiClient;
325     memset(&uiClient, 0, sizeof(WKPageUIClient));
326     uiClient.version = kWKPageUIClientCurrentVersion;
327     uiClient.clientInfo = qtWebPageProxy->viewInterface();
328     uiClient.runJavaScriptAlert = qt_wk_runJavaScriptAlert;
329     uiClient.runJavaScriptConfirm = qt_wk_runJavaScriptConfirm;
330     uiClient.runJavaScriptPrompt = qt_wk_runJavaScriptPrompt;
331     uiClient.setStatusText = qt_wk_setStatusText;
332     uiClient.runOpenPanel = qt_wk_runOpenPanel;
333     uiClient.mouseDidMoveOverElement = qt_wk_mouseDidMoveOverElement;
334     WKPageSetPageUIClient(toAPI(webPageProxy), &uiClient);
335 }
336
337 void setupPagePolicyClient(QtPolicyInterface* policyInterface, WebPageProxy* webPageProxy)
338 {
339     WKPagePolicyClient policyClient;
340     memset(&policyClient, 0, sizeof(WKPagePolicyClient));
341     policyClient.version = kWKPagePolicyClientCurrentVersion;
342     policyClient.clientInfo = policyInterface;
343     policyClient.decidePolicyForNavigationAction = qt_wk_decidePolicyForNavigationAction;
344     policyClient.decidePolicyForResponse = qt_wk_decidePolicyForResponse;
345     WKPageSetPagePolicyClient(toAPI(webPageProxy), &policyClient);
346 }
347
348 void setupContextInjectedBundleClient(WKContextRef context)
349 {
350     WKContextInjectedBundleClient injectedBundleClient;
351     memset(&injectedBundleClient, 0, sizeof(WKContextInjectedBundleClient));
352     injectedBundleClient.version = kWKContextInjectedBundleClientCurrentVersion;
353     injectedBundleClient.didReceiveMessageFromInjectedBundle = qt_wk_didReceiveMessageFromInjectedBundle;
354     WKContextSetInjectedBundleClient(context, &injectedBundleClient);
355 }