[Qt][WK2] Split the QtWebPageProxy into PageClient and QtPageProxy
[WebKit.git] / Source / WebKit2 / UIProcess / qt / QtWebPageProxy.cpp
1 /*
2  * Copyright (C) 2010, 2011 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 program 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 program; 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
21 #include "config.h"
22 #include "QtWebPageProxy.h"
23
24 #include <qdeclarativeengine.h>
25 #include <qquickcanvas.h>
26 #include "qquickwebview_p.h"
27 #include "qquickwebview_p_p.h"
28 #include "qquickwebpage_p.h"
29 #include "qwebdownloaditem_p.h"
30 #include "qwebdownloaditem_p_p.h"
31 #include "qwebpreferences_p.h"
32 #include "qwebpreferences_p_p.h"
33
34 #include "DownloadProxy.h"
35 #include "DrawingAreaProxyImpl.h"
36 #include "qwkhistory.h"
37 #include "qwkhistory_p.h"
38 #include "QtDownloadManager.h"
39 #include "QtPageClient.h"
40 #include "QtWebPageEventHandler.h"
41 #include "QtWebUndoCommand.h"
42 #include "WebBackForwardList.h"
43 #include "WebContext.h"
44 #include "WebContextMenuProxyQt.h"
45 #include "WebEditCommandProxy.h"
46 #include "WebPopupMenuProxyQtDesktop.h"
47 #include "WKStringQt.h"
48 #include "WKURLQt.h"
49 #include <QDrag>
50 #include <QMimeData>
51 #include <QUndoStack>
52 #include <WebCore/DragData.h>
53 #include <WebKit2/WKFrame.h>
54 #include <WebKit2/WKPageGroup.h>
55 #include <WebKit2/WKRetainPtr.h>
56
57 using namespace WebKit;
58 using namespace WebCore;
59
60 QtWebPageProxy::QtWebPageProxy(QQuickWebPage* qmlWebPage, QQuickWebView* qmlWebView, QtPageClient *pageClient, WKContextRef contextRef, WKPageGroupRef pageGroupRef)
61     : m_qmlWebPage(qmlWebPage)
62     , m_qmlWebView(qmlWebView)
63     , m_context(contextRef ? QtWebContext::create(toImpl(contextRef)) : QtWebContext::defaultContext())
64     , m_undoStack(adoptPtr(new QUndoStack(this)))
65     , m_navigatorQtObjectEnabled(false)
66 {
67     m_webPageProxy = m_context->createWebPage(pageClient, toImpl(pageGroupRef));
68     m_history = QWKHistoryPrivate::createHistory(this, m_webPageProxy->backForwardList());
69 }
70
71 void QtWebPageProxy::init(QtWebPageEventHandler* eventHandler)
72 {
73     m_eventHandler = eventHandler;
74     m_webPageProxy->initializeWebPage();
75 }
76
77 QtWebPageProxy::~QtWebPageProxy()
78 {
79     m_webPageProxy->close();
80     delete m_history;
81 }
82
83 void QtWebPageProxy::showContextMenu(QSharedPointer<QMenu> menu)
84 {
85     // Remove the active menu in case this function is called twice.
86     if (activeMenu)
87         activeMenu->hide();
88
89     if (menu->isEmpty())
90         return;
91
92     QWindow* window = m_qmlWebView->canvas();
93     if (!window)
94         return;
95
96     activeMenu = menu;
97
98     activeMenu->window()->winId(); // Ensure that the menu has a window
99     Q_ASSERT(activeMenu->window()->windowHandle());
100     activeMenu->window()->windowHandle()->setTransientParent(window);
101
102     QPoint menuPositionInScene = m_qmlWebView->mapToScene(menu->pos()).toPoint();
103     menu->exec(window->mapToGlobal(menuPositionInScene));
104     // The last function to get out of exec() clear the local copy.
105     if (activeMenu == menu)
106         activeMenu.clear();
107 }
108
109 void QtWebPageProxy::hideContextMenu()
110 {
111     if (activeMenu)
112         activeMenu->hide();
113 }
114
115 void QtWebPageProxy::setViewNeedsDisplay(const WebCore::IntRect&)
116 {
117     m_qmlWebPage->update();
118 }
119
120 WebCore::IntSize QtWebPageProxy::viewSize()
121 {
122     return WebCore::IntSize(m_qmlWebPage->width(), m_qmlWebPage->height());
123 }
124
125 bool QtWebPageProxy::isViewFocused()
126 {
127     return m_qmlWebView->hasFocus();
128 }
129
130 bool QtWebPageProxy::isViewVisible()
131 {
132     return m_qmlWebView->isVisible() && m_qmlWebPage->isVisible();
133 }
134
135 void QtWebPageProxy::pageDidRequestScroll(const IntPoint& pos)
136 {
137     m_qmlWebView->d_func()->scrollPositionRequested(pos);
138 }
139
140 void QtWebPageProxy::didChangeContentsSize(const IntSize& newSize)
141 {
142     m_qmlWebView->d_func()->didChangeContentsSize(newSize);
143 }
144
145 void QtWebPageProxy::didChangeViewportProperties(const WebCore::ViewportArguments& args)
146 {
147     m_qmlWebView->d_func()->didChangeViewportProperties(args);
148 }
149
150 void QtWebPageProxy::registerEditCommand(PassRefPtr<WebEditCommandProxy> command, WebPageProxy::UndoOrRedo undoOrRedo)
151 {
152     if (undoOrRedo == WebPageProxy::Undo) {
153         const QtWebUndoCommand* webUndoCommand = static_cast<const QtWebUndoCommand*>(m_undoStack->command(m_undoStack->index()));
154         if (webUndoCommand && webUndoCommand->inUndoRedo())
155             return;
156         m_undoStack->push(new QtWebUndoCommand(command));
157     }
158 }
159
160 void QtWebPageProxy::clearAllEditCommands()
161 {
162     m_undoStack->clear();
163 }
164
165 bool QtWebPageProxy::canUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
166 {
167     if (undoOrRedo == WebPageProxy::Undo)
168         return m_undoStack->canUndo();
169     return m_undoStack->canRedo();
170 }
171
172 void QtWebPageProxy::executeUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
173 {
174     if (undoOrRedo == WebPageProxy::Undo)
175         m_undoStack->undo();
176     else
177         m_undoStack->redo();
178 }
179
180 void QtWebPageProxy::selectionChanged(bool, bool, bool, bool)
181 {
182 }
183
184 PassRefPtr<WebPopupMenuProxy> QtWebPageProxy::createPopupMenuProxy(WebPageProxy*)
185 {
186     return WebPopupMenuProxyQtDesktop::create(m_webPageProxy.get(), m_qmlWebView);
187 }
188
189 WKPageRef QtWebPageProxy::pageRef() const
190 {
191     return toAPI(m_webPageProxy.get());;
192 }
193
194 void QtWebPageProxy::didReceiveMessageFromNavigatorQtObject(const String& message)
195 {
196     QVariantMap variantMap;
197     variantMap.insert(QLatin1String("data"), QString(message));
198     variantMap.insert(QLatin1String("origin"), url());
199     emit receivedMessageFromNavigatorQtObject(variantMap);
200 }
201
202 bool QtWebPageProxy::canGoBack() const
203 {
204     return m_webPageProxy->canGoBack();
205 }
206
207 void QtWebPageProxy::goBack()
208 {
209     m_webPageProxy->goBack();
210 }
211
212 bool QtWebPageProxy::canGoForward() const
213 {
214     return m_webPageProxy->canGoForward();
215 }
216
217 void QtWebPageProxy::goForward()
218 {
219     m_webPageProxy->goForward();
220 }
221
222 bool QtWebPageProxy::canStop() const
223 {
224     RefPtr<WebKit::WebFrameProxy> mainFrame = m_webPageProxy->mainFrame();
225     return mainFrame && !(WebFrameProxy::LoadStateFinished == mainFrame->loadState());
226 }
227
228 void QtWebPageProxy::stop()
229 {
230     m_webPageProxy->stopLoading();
231 }
232
233 bool QtWebPageProxy::canReload() const
234 {
235     RefPtr<WebKit::WebFrameProxy> mainFrame = m_webPageProxy->mainFrame();
236     if (mainFrame)
237         return (WebFrameProxy::LoadStateFinished == mainFrame->loadState());
238     return m_webPageProxy->backForwardList()->currentItem();
239 }
240
241 void QtWebPageProxy::reload()
242 {
243     m_webPageProxy->reload(/* reloadFromOrigin */ true);
244 }
245
246 void QtWebPageProxy::updateNavigationState()
247 {
248     emit m_qmlWebView->navigationStateChanged();
249 }
250
251 void QtWebPageProxy::didRelaunchProcess()
252 {
253     updateNavigationState();
254     qWarning("WARNING: The web process has been successfully restarted.");
255     setDrawingAreaSize(viewSize());
256 }
257
258 void QtWebPageProxy::processDidCrash()
259 {
260     updateNavigationState();
261
262     ASSERT(m_eventHandler);
263     m_eventHandler->resetGestureRecognizers();
264
265     WebCore::KURL url(WebCore::ParsedURLString, m_webPageProxy->urlAtProcessExit());
266     qWarning("WARNING: The web process experienced a crash on '%s'.", qPrintable(QUrl(url).toString(QUrl::RemoveUserInfo)));
267 }
268
269 QWebPreferences* QtWebPageProxy::preferences() const
270 {
271     if (!m_preferences)
272         m_preferences = adoptPtr(QWebPreferencesPrivate::createPreferences(const_cast<QtWebPageProxy*>(this)));
273     return m_preferences.get();
274 }
275
276 void QtWebPageProxy::setCustomUserAgent(const QString& userAgent)
277 {
278     WKRetainPtr<WKStringRef> wkUserAgent(WKStringCreateWithQString(userAgent));
279     WKPageSetCustomUserAgent(pageRef(), wkUserAgent.get());
280 }
281
282 QString QtWebPageProxy::customUserAgent() const
283 {
284     return WKStringCopyQString(WKPageCopyCustomUserAgent(pageRef()));
285 }
286
287 void QtWebPageProxy::setNavigatorQtObjectEnabled(bool enabled)
288 {
289     ASSERT(enabled != m_navigatorQtObjectEnabled);
290     // FIXME: Currently we have to keep this information in both processes and the setting is asynchronous.
291     m_navigatorQtObjectEnabled = enabled;
292     m_context->setNavigatorQtObjectEnabled(m_webPageProxy.get(), enabled);
293 }
294
295 void QtWebPageProxy::postMessageToNavigatorQtObject(const QString& message)
296 {
297     m_context->postMessageToNavigatorQtObject(m_webPageProxy.get(), message);
298 }
299
300 void QtWebPageProxy::loadHTMLString(const QString& html, const QUrl& baseUrl)
301 {
302     WKRetainPtr<WKURLRef> wkUrl(WKURLCreateWithQUrl(baseUrl));
303     WKRetainPtr<WKStringRef> wkHtmlString(WKStringCreateWithQString(html));
304
305     WKPageLoadHTMLString(pageRef(), wkHtmlString.get(), wkUrl.get());
306 }
307
308 void QtWebPageProxy::load(const QUrl& url)
309 {
310     WKRetainPtr<WKURLRef> wkurl = adoptWK(WKURLCreateWithQUrl(url));
311     WKPageLoadURL(pageRef(), wkurl.get());
312 }
313
314 QUrl QtWebPageProxy::url() const
315 {
316     WKRetainPtr<WKFrameRef> frame = WKPageGetMainFrame(pageRef());
317     if (!frame)
318         return QUrl();
319     return WKURLCopyQUrl(adoptWK(WKFrameCopyURL(frame.get())).get());
320 }
321
322 QString QtWebPageProxy::title() const
323 {
324     return WKStringCopyQString(adoptWK(WKPageCopyTitle(toAPI(m_webPageProxy.get()))).get());
325 }
326
327 void QtWebPageProxy::setDrawingAreaSize(const QSize& size)
328 {
329     if (!m_webPageProxy->drawingArea())
330         return;
331
332     m_webPageProxy->drawingArea()->setSize(IntSize(size), IntSize());
333 }
334
335 qreal QtWebPageProxy::textZoomFactor() const
336 {
337     return WKPageGetTextZoomFactor(pageRef());
338 }
339
340 void QtWebPageProxy::setTextZoomFactor(qreal zoomFactor)
341 {
342     WKPageSetTextZoomFactor(pageRef(), zoomFactor);
343 }
344
345 qreal QtWebPageProxy::pageZoomFactor() const
346 {
347     return WKPageGetPageZoomFactor(pageRef());
348 }
349
350 void QtWebPageProxy::setPageZoomFactor(qreal zoomFactor)
351 {
352     WKPageSetPageZoomFactor(pageRef(), zoomFactor);
353 }
354
355 void QtWebPageProxy::setPageAndTextZoomFactors(qreal pageZoomFactor, qreal textZoomFactor)
356 {
357     WKPageSetPageAndTextZoomFactors(pageRef(), pageZoomFactor, textZoomFactor);
358 }
359
360 QWKHistory* QtWebPageProxy::history() const
361 {
362     return m_history;
363 }
364
365 void QtWebPageProxy::startDrag(const WebCore::DragData& dragData, PassRefPtr<ShareableBitmap> dragImage)
366 {
367     QImage dragQImage;
368     if (dragImage)
369         dragQImage = dragImage->createQImage();
370     else if (dragData.platformData() && dragData.platformData()->hasImage())
371         dragQImage = qvariant_cast<QImage>(dragData.platformData()->imageData());
372
373
374     DragOperation dragOperationMask = dragData.draggingSourceOperationMask();
375     QMimeData* mimeData = const_cast<QMimeData*>(dragData.platformData());
376     Qt::DropActions supportedDropActions = QtWebPageEventHandler::dragOperationToDropActions(dragOperationMask);
377
378     QPoint clientPosition;
379     QPoint globalPosition;
380     Qt::DropAction actualDropAction = Qt::IgnoreAction;
381
382     if (QWindow* window = m_qmlWebView->canvas()) {
383         QDrag* drag = new QDrag(window);
384         drag->setPixmap(QPixmap::fromImage(dragQImage));
385         drag->setMimeData(mimeData);
386         actualDropAction = drag->exec(supportedDropActions);
387         globalPosition = QCursor::pos();
388         clientPosition = window->mapFromGlobal(globalPosition);
389     }
390
391     m_webPageProxy->dragEnded(clientPosition, globalPosition, QtWebPageEventHandler::dropActionToDragOperation(actualDropAction));
392 }
393
394 void QtWebPageProxy::handleDownloadRequest(DownloadProxy* download)
395 {
396     // This function is responsible for hooking up a DownloadProxy to our API layer
397     // by creating a QWebDownloadItem. It will then wait for the QWebDownloadItem to be
398     // ready (filled with the ResourceResponse information) so we can pass it through to
399     // our WebViews.
400     QWebDownloadItem* downloadItem = new QWebDownloadItem();
401     downloadItem->d->downloadProxy = download;
402
403     connect(downloadItem->d, SIGNAL(receivedResponse(QWebDownloadItem*)), this, SLOT(didReceiveDownloadResponse(QWebDownloadItem*)));
404     m_context->downloadManager()->addDownload(download, downloadItem);
405 }
406
407 void QtWebPageProxy::didReceiveDownloadResponse(QWebDownloadItem* downloadItem)
408 {
409     // Now that our downloadItem has everything we need we can emit downloadRequested.
410     if (!downloadItem)
411         return;
412
413     QDeclarativeEngine::setObjectOwnership(downloadItem, QDeclarativeEngine::JavaScriptOwnership);
414     emit m_qmlWebView->experimental()->downloadRequested(downloadItem);
415 }
416
417 PassOwnPtr<DrawingAreaProxy> QtWebPageProxy::createDrawingAreaProxy()
418 {
419     return DrawingAreaProxyImpl::create(m_webPageProxy.get());
420 }
421
422 void QtWebPageProxy::renderToCurrentGLContext(const TransformationMatrix& transform, float opacity)
423 {
424     DrawingAreaProxy* drawingArea = m_webPageProxy->drawingArea();
425     if (drawingArea)
426         drawingArea->paintToCurrentGLContext(transform, opacity);
427 }
428
429 void QtWebPageProxy::setVisibleContentRectAndScale(const QRectF& visibleContentRect, float scale)
430 {
431     if (!m_webPageProxy->drawingArea())
432         return;
433
434     QRect alignedVisibleContentRect = visibleContentRect.toAlignedRect();
435     m_webPageProxy->drawingArea()->setVisibleContentsRectAndScale(alignedVisibleContentRect, scale);
436
437     // FIXME: Once we support suspend and resume, this should be delayed until the page is active if the page is suspended.
438     m_webPageProxy->setFixedVisibleContentRect(alignedVisibleContentRect);
439 }
440
441 void QtWebPageProxy::setVisibleContentRectTrajectoryVector(const QPointF& trajectoryVector)
442 {
443     if (!m_webPageProxy->drawingArea())
444         return;
445
446     m_webPageProxy->drawingArea()->setVisibleContentRectTrajectoryVector(trajectoryVector);
447 }
448
449 #include "moc_QtWebPageProxy.cpp"