[Qt][WK2] Do not apply new viewport properties until after the first visually non...
[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_didFirstVisuallyNonEmptyLayoutForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void *clientInfo)
155 {
156     if (!WKFrameIsMainFrame(frame))
157         return;
158
159     toQtWebPageProxy(clientInfo)->didFinishFirstNonEmptyLayout();
160 }
161
162 static void qt_wk_runJavaScriptAlert(WKPageRef page, WKStringRef alertText, WKFrameRef frame, const void* clientInfo)
163 {
164     QString qAlertText = WKStringCopyQString(alertText);
165     toQtViewInterface(clientInfo)->runJavaScriptAlert(qAlertText);
166 }
167
168 static bool qt_wk_runJavaScriptConfirm(WKPageRef, WKStringRef message, WKFrameRef, const void* clientInfo)
169 {
170     QString qMessage = WKStringCopyQString(message);
171     return toQtViewInterface(clientInfo)->runJavaScriptConfirm(qMessage);
172 }
173
174 static inline WKStringRef createNullWKString()
175 {
176     RefPtr<WebString> webString = WebString::createNull();
177     return toAPI(webString.release().leakRef());
178 }
179
180 static WKStringRef qt_wk_runJavaScriptPrompt(WKPageRef, WKStringRef message, WKStringRef defaultValue, WKFrameRef, const void* clientInfo)
181 {
182     QString qMessage = WKStringCopyQString(message);
183     QString qDefaultValue = WKStringCopyQString(defaultValue);
184     bool ok = false;
185     QString result = toQtViewInterface(clientInfo)->runJavaScriptPrompt(qMessage, qDefaultValue, ok);
186     if (!ok)
187         return createNullWKString();
188     return WKStringCreateWithQString(result);
189 }
190
191 static void qt_wk_setStatusText(WKPageRef, WKStringRef text, const void *clientInfo)
192 {
193     QString qText = WKStringCopyQString(text);
194     toQtViewInterface(clientInfo)->didChangeStatusText(qText);
195 }
196
197 static void qt_wk_runOpenPanel(WKPageRef, WKFrameRef, WKOpenPanelParametersRef parameters, WKOpenPanelResultListenerRef listener, const void* clientInfo)
198 {
199     Vector<String> wkSelectedFileNames = toImpl(parameters)->selectedFileNames();
200
201     QStringList selectedFileNames;
202     if (!wkSelectedFileNames.isEmpty())
203         for (unsigned i = 0; wkSelectedFileNames.size(); ++i)
204             selectedFileNames += wkSelectedFileNames.at(i);
205
206     QtViewInterface::FileChooserType allowMultipleFiles = WKOpenPanelParametersGetAllowsMultipleFiles(parameters) ? QtViewInterface::MultipleFilesSelection : QtViewInterface::SingleFileSelection;
207     toQtViewInterface(clientInfo)->chooseFiles(listener, selectedFileNames, allowMultipleFiles);
208 }
209
210 static void qt_wk_mouseDidMoveOverElement(WKPageRef page, WKHitTestResultRef hitTestResult, WKEventModifiers modifiers, WKTypeRef userData, const void* clientInfo)
211 {
212     const QUrl absoluteLinkUrl = WKURLCopyQUrl(WKHitTestResultCopyAbsoluteLinkURL(hitTestResult));
213     const QString linkTitle = WKStringCopyQString(WKHitTestResultCopyLinkTitle(hitTestResult));
214     toQtViewInterface(clientInfo)->didMouseMoveOverElement(absoluteLinkUrl, linkTitle);
215 }
216
217 static Qt::MouseButton toQtMouseButton(WKEventMouseButton button)
218 {
219     switch (button) {
220     case kWKEventMouseButtonLeftButton:
221         return Qt::LeftButton;
222     case kWKEventMouseButtonMiddleButton:
223         return Qt::MiddleButton;
224     case kWKEventMouseButtonRightButton:
225         return Qt::RightButton;
226     }
227     return Qt::NoButton;
228 }
229
230 static Qt::KeyboardModifiers toQtKeyboardModifiers(WKEventModifiers modifiers)
231 {
232     Qt::KeyboardModifiers qtModifiers = Qt::NoModifier;
233     if (modifiers & kWKEventModifiersShiftKey)
234         qtModifiers |= Qt::ShiftModifier;
235     if (modifiers & kWKEventModifiersControlKey)
236         qtModifiers |= Qt::ControlModifier;
237     if (modifiers & kWKEventModifiersAltKey)
238         qtModifiers |= Qt::AltModifier;
239     if (modifiers & kWKEventModifiersMetaKey)
240         qtModifiers |= Qt::MetaModifier;
241     return qtModifiers;
242 }
243
244 static void qt_wk_decidePolicyForNavigationAction(WKPageRef page, WKFrameRef frame, WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, WKURLRequestRef request, WKFramePolicyListenerRef listener, WKTypeRef userData, const void* clientInfo)
245 {
246     QtPolicyInterface* policyInterface = toQtPolicyInterface(clientInfo);
247     WKURLRef requestURL = WKURLRequestCopyURL(request);
248     QUrl qUrl = WKURLCopyQUrl(requestURL);
249     WKRelease(requestURL);
250
251     QtPolicyInterface::PolicyAction action = policyInterface->navigationPolicyForURL(qUrl, toQtMouseButton(mouseButton), toQtKeyboardModifiers(modifiers));
252     switch (action) {
253     case QtPolicyInterface::Use:
254         WKFramePolicyListenerUse(listener);
255         break;
256     case QtPolicyInterface::Download:
257         WKFramePolicyListenerDownload(listener);
258         break;
259     case QtPolicyInterface::Ignore:
260         WKFramePolicyListenerIgnore(listener);
261         break;
262     }
263 }
264
265 static void qt_wk_decidePolicyForResponse(WKPageRef page, WKFrameRef frame, WKURLResponseRef response, WKURLRequestRef request, WKFramePolicyListenerRef listener, WKTypeRef userData, const void* clientInfo)
266 {
267     String type = toImpl(response)->resourceResponse().mimeType();
268     type.makeLower();
269     bool canShowMIMEType = toImpl(frame)->canShowMIMEType(type);
270
271     if (WKPageGetMainFrame(page) == frame) {
272         if (canShowMIMEType) {
273             WKFramePolicyListenerUse(listener);
274             return;
275         }
276
277         // If we can't use (show) it then we should download it.
278         WKFramePolicyListenerDownload(listener);
279         return;
280     }
281
282     // 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.
283     // It makes the browser intentionally behave differently when it comes to text(application)/xml content in subframes vs. mainframe.
284     if (!canShowMIMEType && !(type == "text/xml" || type == "application/xml")) {
285         WKFramePolicyListenerIgnore(listener);
286         return;
287     }
288
289     WKFramePolicyListenerUse(listener);
290 }
291
292 void qt_wk_didReceiveMessageFromInjectedBundle(WKContextRef, WKStringRef messageName, WKTypeRef messageBody, const void*)
293 {
294     if (!WKStringIsEqualToUTF8CString(messageName, "MessageFromNavigatorQtObject"))
295         return;
296
297     ASSERT(messageBody);
298     ASSERT(WKGetTypeID(messageBody) == WKArrayGetTypeID());
299
300     WKArrayRef body = static_cast<WKArrayRef>(messageBody);
301     ASSERT(WKArrayGetSize(body) == 2);
302     ASSERT(WKGetTypeID(WKArrayGetItemAtIndex(body, 0)) == WKPageGetTypeID());
303     ASSERT(WKGetTypeID(WKArrayGetItemAtIndex(body, 1)) == WKStringGetTypeID());
304
305     WKPageRef page = static_cast<WKPageRef>(WKArrayGetItemAtIndex(body, 0));
306     WKStringRef str = static_cast<WKStringRef>(WKArrayGetItemAtIndex(body, 1));
307
308     toImpl(page)->didReceiveMessageFromNavigatorQtObject(toImpl(str)->string());
309 }
310
311 void setupPageLoaderClient(QtWebPageProxy* qtWebPageProxy, WebPageProxy* webPageProxy)
312 {
313     WKPageLoaderClient loadClient;
314     memset(&loadClient, 0, sizeof(WKPageLoaderClient));
315     loadClient.version = kWKPageLoaderClientCurrentVersion;
316     loadClient.clientInfo = qtWebPageProxy;
317     loadClient.didStartProvisionalLoadForFrame = qt_wk_didStartProvisionalLoadForFrame;
318     loadClient.didFailProvisionalLoadWithErrorForFrame = qt_wk_didFailProvisionalLoadWithErrorForFrame;
319     loadClient.didCommitLoadForFrame = qt_wk_didCommitLoadForFrame;
320     loadClient.didFinishLoadForFrame = qt_wk_didFinishLoadForFrame;
321     loadClient.didFailLoadWithErrorForFrame = qt_wk_didFailLoadWithErrorForFrame;
322     loadClient.didSameDocumentNavigationForFrame = qt_wk_didSameDocumentNavigationForFrame;
323     loadClient.didReceiveTitleForFrame = qt_wk_didReceiveTitleForFrame;
324     loadClient.didStartProgress = qt_wk_didStartProgress;
325     loadClient.didChangeProgress = qt_wk_didChangeProgress;
326     loadClient.didFinishProgress = qt_wk_didFinishProgress;
327     loadClient.didFirstVisuallyNonEmptyLayoutForFrame = qt_wk_didFirstVisuallyNonEmptyLayoutForFrame;
328     WKPageSetPageLoaderClient(qtWebPageProxy->pageRef(), &loadClient);
329 }
330
331 void setupPageUiClient(QtWebPageProxy* qtWebPageProxy, WebPageProxy* webPageProxy)
332 {
333     WKPageUIClient uiClient;
334     memset(&uiClient, 0, sizeof(WKPageUIClient));
335     uiClient.version = kWKPageUIClientCurrentVersion;
336     uiClient.clientInfo = qtWebPageProxy->viewInterface();
337     uiClient.runJavaScriptAlert = qt_wk_runJavaScriptAlert;
338     uiClient.runJavaScriptConfirm = qt_wk_runJavaScriptConfirm;
339     uiClient.runJavaScriptPrompt = qt_wk_runJavaScriptPrompt;
340     uiClient.setStatusText = qt_wk_setStatusText;
341     uiClient.runOpenPanel = qt_wk_runOpenPanel;
342     uiClient.mouseDidMoveOverElement = qt_wk_mouseDidMoveOverElement;
343     WKPageSetPageUIClient(toAPI(webPageProxy), &uiClient);
344 }
345
346 void setupPagePolicyClient(QtPolicyInterface* policyInterface, WebPageProxy* webPageProxy)
347 {
348     WKPagePolicyClient policyClient;
349     memset(&policyClient, 0, sizeof(WKPagePolicyClient));
350     policyClient.version = kWKPagePolicyClientCurrentVersion;
351     policyClient.clientInfo = policyInterface;
352     policyClient.decidePolicyForNavigationAction = qt_wk_decidePolicyForNavigationAction;
353     policyClient.decidePolicyForResponse = qt_wk_decidePolicyForResponse;
354     WKPageSetPagePolicyClient(toAPI(webPageProxy), &policyClient);
355 }
356
357 void setupContextInjectedBundleClient(WKContextRef context)
358 {
359     WKContextInjectedBundleClient injectedBundleClient;
360     memset(&injectedBundleClient, 0, sizeof(WKContextInjectedBundleClient));
361     injectedBundleClient.version = kWKContextInjectedBundleClientCurrentVersion;
362     injectedBundleClient.didReceiveMessageFromInjectedBundle = qt_wk_didReceiveMessageFromInjectedBundle;
363     WKContextSetInjectedBundleClient(context, &injectedBundleClient);
364 }