4ac04f4dfdbeb8844a4431356a27be03f3ab4f62
[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 "QtWebError.h"
30 #include "qwebdownloaditem_p.h"
31 #include "qwebdownloaditem_p_p.h"
32 #include "qwebpreferences_p.h"
33 #include "qwebpreferences_p_p.h"
34
35 #include "DownloadProxy.h"
36 #include "DrawingAreaProxyImpl.h"
37 #include "qwkhistory.h"
38 #include "qwkhistory_p.h"
39 #include "FindIndicator.h"
40 #include "LocalizedStrings.h"
41 #include "NotImplemented.h"
42 #include "QtDownloadManager.h"
43 #include "QtWebPageEventHandler.h"
44 #include "QtWebUndoCommand.h"
45 #include "WebBackForwardList.h"
46 #include "WebContext.h"
47 #include "WebContextMenuProxyQt.h"
48 #include "WebEditCommandProxy.h"
49 #include "WebPopupMenuProxyQtDesktop.h"
50 #include "WKStringQt.h"
51 #include "WKURLQt.h"
52 #include <QDrag>
53 #include <QGuiApplication>
54 #include <QJSEngine>
55 #include <QMimeData>
56 #include <QStyleHints>
57 #include <QUndoStack>
58 #include <QtDebug>
59 #include <WebCore/Cursor.h>
60 #include <WebCore/DragData.h>
61 #include <WebCore/FloatRect.h>
62 #include <WebCore/Region.h>
63 #include <WebKit2/WKFrame.h>
64 #include <WebKit2/WKPageGroup.h>
65 #include <WebKit2/WKRetainPtr.h>
66
67 using namespace WebKit;
68 using namespace WebCore;
69
70 QtWebPageProxy::QtWebPageProxy(QQuickWebPage* qmlWebPage, QQuickWebView* qmlWebView, WKContextRef contextRef, WKPageGroupRef pageGroupRef)
71     : m_qmlWebPage(qmlWebPage)
72     , m_qmlWebView(qmlWebView)
73     , m_context(contextRef ? QtWebContext::create(toImpl(contextRef)) : QtWebContext::defaultContext())
74     , m_undoStack(adoptPtr(new QUndoStack(this)))
75     , m_navigatorQtObjectEnabled(false)
76 {
77     m_webPageProxy = m_context->createWebPage(this, toImpl(pageGroupRef));
78     m_history = QWKHistoryPrivate::createHistory(this, m_webPageProxy->backForwardList());
79 }
80
81 void QtWebPageProxy::init(QtWebPageEventHandler* eventHandler)
82 {
83     m_eventHandler = eventHandler;
84     m_webPageProxy->initializeWebPage();
85 }
86
87 QtWebPageProxy::~QtWebPageProxy()
88 {
89     m_webPageProxy->close();
90     delete m_history;
91 }
92
93 void QtWebPageProxy::showContextMenu(QSharedPointer<QMenu> menu)
94 {
95     // Remove the active menu in case this function is called twice.
96     if (activeMenu)
97         activeMenu->hide();
98
99     if (menu->isEmpty())
100         return;
101
102     QWindow* window = m_qmlWebView->canvas();
103     if (!window)
104         return;
105
106     activeMenu = menu;
107
108     activeMenu->window()->winId(); // Ensure that the menu has a window
109     Q_ASSERT(activeMenu->window()->windowHandle());
110     activeMenu->window()->windowHandle()->setTransientParent(window);
111
112     QPoint menuPositionInScene = m_qmlWebView->mapToScene(menu->pos()).toPoint();
113     menu->exec(window->mapToGlobal(menuPositionInScene));
114     // The last function to get out of exec() clear the local copy.
115     if (activeMenu == menu)
116         activeMenu.clear();
117 }
118
119 void QtWebPageProxy::hideContextMenu()
120 {
121     if (activeMenu)
122         activeMenu->hide();
123 }
124
125 void QtWebPageProxy::setCursor(const WebCore::Cursor& cursor)
126 {
127     // FIXME: This is a temporary fix until we get cursor support in QML items.
128     QGuiApplication::setOverrideCursor(*cursor.platformCursor());
129 }
130
131 void QtWebPageProxy::setCursorHiddenUntilMouseMoves(bool hiddenUntilMouseMoves)
132 {
133     notImplemented();
134 }
135
136 void QtWebPageProxy::setViewNeedsDisplay(const WebCore::IntRect&)
137 {
138     m_qmlWebPage->update();
139 }
140
141 void QtWebPageProxy::displayView()
142 {
143     // FIXME: Implement.
144 }
145
146 void QtWebPageProxy::scrollView(const WebCore::IntRect& scrollRect, const WebCore::IntSize& scrollOffset)
147 {
148     // FIXME: Implement.
149 }
150
151 WebCore::IntSize QtWebPageProxy::viewSize()
152 {
153     return WebCore::IntSize(m_qmlWebPage->width(), m_qmlWebPage->height());
154 }
155
156 bool QtWebPageProxy::isViewWindowActive()
157 {
158     // FIXME: The scene graph does not have the concept of being active or not when this was written.
159     return true;
160 }
161
162 bool QtWebPageProxy::isViewFocused()
163 {
164     return m_qmlWebView->hasFocus();
165 }
166
167 bool QtWebPageProxy::isViewVisible()
168 {
169     return m_qmlWebView->isVisible() && m_qmlWebPage->isVisible();
170 }
171
172 bool QtWebPageProxy::isViewInWindow()
173 {
174     // FIXME: Implement.
175     return true;
176 }
177
178 void QtWebPageProxy::enterAcceleratedCompositingMode(const LayerTreeContext&)
179 {
180     // FIXME: Implement.
181 }
182
183 void QtWebPageProxy::exitAcceleratedCompositingMode()
184 {
185     // FIXME: Implement.
186 }
187
188 void QtWebPageProxy::pageDidRequestScroll(const IntPoint& pos)
189 {
190     m_qmlWebView->d_func()->scrollPositionRequested(pos);
191 }
192
193 void QtWebPageProxy::didChangeContentsSize(const IntSize& newSize)
194 {
195     m_qmlWebView->d_func()->didChangeContentsSize(newSize);
196 }
197
198 void QtWebPageProxy::didChangeViewportProperties(const WebCore::ViewportArguments& args)
199 {
200     m_qmlWebView->d_func()->didChangeViewportProperties(args);
201 }
202
203 void QtWebPageProxy::toolTipChanged(const String&, const String& newTooltip)
204 {
205     // There is not yet any UI defined for the tooltips for mobile so we ignore the change.
206 }
207
208 void QtWebPageProxy::registerEditCommand(PassRefPtr<WebEditCommandProxy> command, WebPageProxy::UndoOrRedo undoOrRedo)
209 {
210     if (undoOrRedo == WebPageProxy::Undo) {
211         const QtWebUndoCommand* webUndoCommand = static_cast<const QtWebUndoCommand*>(m_undoStack->command(m_undoStack->index()));
212         if (webUndoCommand && webUndoCommand->inUndoRedo())
213             return;
214         m_undoStack->push(new QtWebUndoCommand(command));
215     }
216 }
217
218 void QtWebPageProxy::clearAllEditCommands()
219 {
220     m_undoStack->clear();
221 }
222
223 bool QtWebPageProxy::canUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
224 {
225     if (undoOrRedo == WebPageProxy::Undo)
226         return m_undoStack->canUndo();
227     return m_undoStack->canRedo();
228 }
229
230 void QtWebPageProxy::executeUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
231 {
232     if (undoOrRedo == WebPageProxy::Undo)
233         m_undoStack->undo();
234     else
235         m_undoStack->redo();
236 }
237
238 FloatRect QtWebPageProxy::convertToDeviceSpace(const FloatRect& rect)
239 {
240     return rect;
241 }
242
243 IntPoint QtWebPageProxy::screenToWindow(const IntPoint& point)
244 {
245     return point;
246 }
247
248 IntRect QtWebPageProxy::windowToScreen(const IntRect& rect)
249 {
250     return rect;
251 }
252
253 FloatRect QtWebPageProxy::convertToUserSpace(const FloatRect& rect)
254 {
255     return rect;
256 }
257
258 void QtWebPageProxy::selectionChanged(bool, bool, bool, bool)
259 {
260 }
261
262 void QtWebPageProxy::doneWithKeyEvent(const NativeWebKeyboardEvent&, bool)
263 {
264 }
265
266 PassRefPtr<WebPopupMenuProxy> QtWebPageProxy::createPopupMenuProxy(WebPageProxy*)
267 {
268     return WebPopupMenuProxyQtDesktop::create(m_webPageProxy.get(), m_qmlWebView);
269 }
270
271 PassRefPtr<WebContextMenuProxy> QtWebPageProxy::createContextMenuProxy(WebPageProxy*)
272 {
273     return WebContextMenuProxyQt::create(this);
274 }
275
276 void QtWebPageProxy::setFindIndicator(PassRefPtr<FindIndicator>, bool fadeOut, bool animate)
277 {
278 }
279
280 void QtWebPageProxy::didCommitLoadForMainFrame(bool useCustomRepresentation)
281 {
282 }
283
284 void QtWebPageProxy::didFinishLoadingDataForCustomRepresentation(const String& suggestedFilename, const CoreIPC::DataReference&)
285 {
286 }
287
288 void QtWebPageProxy::flashBackingStoreUpdates(const Vector<IntRect>&)
289 {
290     notImplemented();
291 }
292
293 WKPageRef QtWebPageProxy::pageRef() const
294 {
295     return toAPI(m_webPageProxy.get());;
296 }
297
298 void QtWebPageProxy::didFindZoomableArea(const IntPoint& target, const IntRect& area)
299 {
300     ASSERT(m_eventHandler);
301     m_eventHandler->didFindZoomableArea(target, area);
302 }
303
304 void QtWebPageProxy::didReceiveMessageFromNavigatorQtObject(const String& message)
305 {
306     QVariantMap variantMap;
307     variantMap.insert(QLatin1String("data"), QString(message));
308     variantMap.insert(QLatin1String("origin"), url());
309     emit receivedMessageFromNavigatorQtObject(variantMap);
310 }
311
312 bool QtWebPageProxy::canGoBack() const
313 {
314     return m_webPageProxy->canGoBack();
315 }
316
317 void QtWebPageProxy::goBack()
318 {
319     m_webPageProxy->goBack();
320 }
321
322 bool QtWebPageProxy::canGoForward() const
323 {
324     return m_webPageProxy->canGoForward();
325 }
326
327 void QtWebPageProxy::goForward()
328 {
329     m_webPageProxy->goForward();
330 }
331
332 bool QtWebPageProxy::canStop() const
333 {
334     RefPtr<WebKit::WebFrameProxy> mainFrame = m_webPageProxy->mainFrame();
335     return mainFrame && !(WebFrameProxy::LoadStateFinished == mainFrame->loadState());
336 }
337
338 void QtWebPageProxy::stop()
339 {
340     m_webPageProxy->stopLoading();
341 }
342
343 bool QtWebPageProxy::canReload() const
344 {
345     RefPtr<WebKit::WebFrameProxy> mainFrame = m_webPageProxy->mainFrame();
346     if (mainFrame)
347         return (WebFrameProxy::LoadStateFinished == mainFrame->loadState());
348     return m_webPageProxy->backForwardList()->currentItem();
349 }
350
351 void QtWebPageProxy::reload()
352 {
353     m_webPageProxy->reload(/* reloadFromOrigin */ true);
354 }
355
356 void QtWebPageProxy::updateNavigationState()
357 {
358     emit m_qmlWebView->navigationStateChanged();
359 }
360
361 void QtWebPageProxy::didRelaunchProcess()
362 {
363     updateNavigationState();
364     qWarning("WARNING: The web process has been successfully restarted.");
365     setDrawingAreaSize(viewSize());
366 }
367
368 void QtWebPageProxy::processDidCrash()
369 {
370     updateNavigationState();
371
372     ASSERT(m_eventHandler);
373     m_eventHandler->resetGestureRecognizers();
374
375     WebCore::KURL url(WebCore::ParsedURLString, m_webPageProxy->urlAtProcessExit());
376     qWarning("WARNING: The web process experienced a crash on '%s'.", qPrintable(QUrl(url).toString(QUrl::RemoveUserInfo)));
377 }
378
379 QWebPreferences* QtWebPageProxy::preferences() const
380 {
381     if (!m_preferences)
382         m_preferences = adoptPtr(QWebPreferencesPrivate::createPreferences(const_cast<QtWebPageProxy*>(this)));
383     return m_preferences.get();
384 }
385
386 void QtWebPageProxy::setCustomUserAgent(const QString& userAgent)
387 {
388     WKRetainPtr<WKStringRef> wkUserAgent(WKStringCreateWithQString(userAgent));
389     WKPageSetCustomUserAgent(pageRef(), wkUserAgent.get());
390 }
391
392 QString QtWebPageProxy::customUserAgent() const
393 {
394     return WKStringCopyQString(WKPageCopyCustomUserAgent(pageRef()));
395 }
396
397 void QtWebPageProxy::setNavigatorQtObjectEnabled(bool enabled)
398 {
399     ASSERT(enabled != m_navigatorQtObjectEnabled);
400     // FIXME: Currently we have to keep this information in both processes and the setting is asynchronous.
401     m_navigatorQtObjectEnabled = enabled;
402     m_context->setNavigatorQtObjectEnabled(m_webPageProxy.get(), enabled);
403 }
404
405 void QtWebPageProxy::postMessageToNavigatorQtObject(const QString& message)
406 {
407     m_context->postMessageToNavigatorQtObject(m_webPageProxy.get(), message);
408 }
409
410 void QtWebPageProxy::loadHTMLString(const QString& html, const QUrl& baseUrl)
411 {
412     WKRetainPtr<WKURLRef> wkUrl(WKURLCreateWithQUrl(baseUrl));
413     WKRetainPtr<WKStringRef> wkHtmlString(WKStringCreateWithQString(html));
414
415     WKPageLoadHTMLString(pageRef(), wkHtmlString.get(), wkUrl.get());
416 }
417
418 void QtWebPageProxy::load(const QUrl& url)
419 {
420     WKRetainPtr<WKURLRef> wkurl = adoptWK(WKURLCreateWithQUrl(url));
421     WKPageLoadURL(pageRef(), wkurl.get());
422 }
423
424 QUrl QtWebPageProxy::url() const
425 {
426     WKRetainPtr<WKFrameRef> frame = WKPageGetMainFrame(pageRef());
427     if (!frame)
428         return QUrl();
429     return WKURLCopyQUrl(adoptWK(WKFrameCopyURL(frame.get())).get());
430 }
431
432 QString QtWebPageProxy::title() const
433 {
434     return WKStringCopyQString(adoptWK(WKPageCopyTitle(toAPI(m_webPageProxy.get()))).get());
435 }
436
437 void QtWebPageProxy::setDrawingAreaSize(const QSize& size)
438 {
439     if (!m_webPageProxy->drawingArea())
440         return;
441
442     m_webPageProxy->drawingArea()->setSize(IntSize(size), IntSize());
443 }
444
445 qreal QtWebPageProxy::textZoomFactor() const
446 {
447     return WKPageGetTextZoomFactor(pageRef());
448 }
449
450 void QtWebPageProxy::setTextZoomFactor(qreal zoomFactor)
451 {
452     WKPageSetTextZoomFactor(pageRef(), zoomFactor);
453 }
454
455 qreal QtWebPageProxy::pageZoomFactor() const
456 {
457     return WKPageGetPageZoomFactor(pageRef());
458 }
459
460 void QtWebPageProxy::setPageZoomFactor(qreal zoomFactor)
461 {
462     WKPageSetPageZoomFactor(pageRef(), zoomFactor);
463 }
464
465 void QtWebPageProxy::setPageAndTextZoomFactors(qreal pageZoomFactor, qreal textZoomFactor)
466 {
467     WKPageSetPageAndTextZoomFactors(pageRef(), pageZoomFactor, textZoomFactor);
468 }
469
470 QWKHistory* QtWebPageProxy::history() const
471 {
472     return m_history;
473 }
474
475 void QtWebPageProxy::startDrag(const WebCore::DragData& dragData, PassRefPtr<ShareableBitmap> dragImage)
476 {
477     QImage dragQImage;
478     if (dragImage)
479         dragQImage = dragImage->createQImage();
480     else if (dragData.platformData() && dragData.platformData()->hasImage())
481         dragQImage = qvariant_cast<QImage>(dragData.platformData()->imageData());
482
483
484     DragOperation dragOperationMask = dragData.draggingSourceOperationMask();
485     QMimeData* mimeData = const_cast<QMimeData*>(dragData.platformData());
486     Qt::DropActions supportedDropActions = QtWebPageEventHandler::dragOperationToDropActions(dragOperationMask);
487
488     QPoint clientPosition;
489     QPoint globalPosition;
490     Qt::DropAction actualDropAction = Qt::IgnoreAction;
491
492     if (QWindow* window = m_qmlWebView->canvas()) {
493         QDrag* drag = new QDrag(window);
494         drag->setPixmap(QPixmap::fromImage(dragQImage));
495         drag->setMimeData(mimeData);
496         actualDropAction = drag->exec(supportedDropActions);
497         globalPosition = QCursor::pos();
498         clientPosition = window->mapFromGlobal(globalPosition);
499     }
500
501     m_webPageProxy->dragEnded(clientPosition, globalPosition, QtWebPageEventHandler::dropActionToDragOperation(actualDropAction));
502 }
503
504 void QtWebPageProxy::handleDownloadRequest(DownloadProxy* download)
505 {
506     // This function is responsible for hooking up a DownloadProxy to our API layer
507     // by creating a QWebDownloadItem. It will then wait for the QWebDownloadItem to be
508     // ready (filled with the ResourceResponse information) so we can pass it through to
509     // our WebViews.
510     QWebDownloadItem* downloadItem = new QWebDownloadItem();
511     downloadItem->d->downloadProxy = download;
512
513     connect(downloadItem->d, SIGNAL(receivedResponse(QWebDownloadItem*)), this, SLOT(didReceiveDownloadResponse(QWebDownloadItem*)));
514     m_context->downloadManager()->addDownload(download, downloadItem);
515 }
516
517 void QtWebPageProxy::didReceiveDownloadResponse(QWebDownloadItem* downloadItem)
518 {
519     // Now that our downloadItem has everything we need we can emit downloadRequested.
520     if (!downloadItem)
521         return;
522
523     QDeclarativeEngine::setObjectOwnership(downloadItem, QDeclarativeEngine::JavaScriptOwnership);
524     emit m_qmlWebView->experimental()->downloadRequested(downloadItem);
525 }
526
527 PassOwnPtr<DrawingAreaProxy> QtWebPageProxy::createDrawingAreaProxy()
528 {
529     return DrawingAreaProxyImpl::create(m_webPageProxy.get());
530 }
531
532 void QtWebPageProxy::renderToCurrentGLContext(const TransformationMatrix& transform, float opacity)
533 {
534     DrawingAreaProxy* drawingArea = m_webPageProxy->drawingArea();
535     if (drawingArea)
536         drawingArea->paintToCurrentGLContext(transform, opacity);
537 }
538
539 #if ENABLE(TOUCH_EVENTS)
540 void QtWebPageProxy::doneWithTouchEvent(const NativeWebTouchEvent& event, bool wasEventHandled)
541 {
542     ASSERT(m_eventHandler);
543     m_eventHandler->doneWithTouchEvent(event, wasEventHandled);
544 }
545 #endif
546
547 void QtWebPageProxy::setVisibleContentRectAndScale(const QRectF& visibleContentRect, float scale)
548 {
549     if (!m_webPageProxy->drawingArea())
550         return;
551
552     QRect alignedVisibleContentRect = visibleContentRect.toAlignedRect();
553     m_webPageProxy->drawingArea()->setVisibleContentsRectAndScale(alignedVisibleContentRect, scale);
554
555     // FIXME: Once we support suspend and resume, this should be delayed until the page is active if the page is suspended.
556     m_webPageProxy->setFixedVisibleContentRect(alignedVisibleContentRect);
557 }
558
559 void QtWebPageProxy::setVisibleContentRectTrajectoryVector(const QPointF& trajectoryVector)
560 {
561     if (!m_webPageProxy->drawingArea())
562         return;
563
564     m_webPageProxy->drawingArea()->setVisibleContentRectTrajectoryVector(trajectoryVector);
565 }
566
567 #include "moc_QtWebPageProxy.cpp"