[Qt] [WK2] Move PageLoadClient related code to QtWebPageLoadClient
[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 "ClientImpl.h"
36 #include "DownloadProxy.h"
37 #include "DrawingAreaProxyImpl.h"
38 #include "qwkhistory.h"
39 #include "qwkhistory_p.h"
40 #include "FindIndicator.h"
41 #include "LocalizedStrings.h"
42 #include "MutableArray.h"
43 #include "NativeWebKeyboardEvent.h"
44 #include "NativeWebMouseEvent.h"
45 #include "NativeWebWheelEvent.h"
46 #include "NotImplemented.h"
47 #include "QtPolicyInterface.h"
48 #include "QtViewportInteractionEngine.h"
49 #include "QtWebUndoCommand.h"
50 #include "WebBackForwardList.h"
51 #include "WebContext.h"
52 #include "WebContextMenuProxyQt.h"
53 #include "WebEditCommandProxy.h"
54 #include "WebEventFactoryQt.h"
55 #include "WebPopupMenuProxyQtDesktop.h"
56 #include "WKStringQt.h"
57 #include "WKURLQt.h"
58 #include <QDrag>
59 #include <QGuiApplication>
60 #include <QGraphicsSceneMouseEvent>
61 #include <QJSEngine>
62 #include <QMimeData>
63 #include <QStyleHints>
64 #include <QTouchEvent>
65 #include <QUndoStack>
66 #include <QtDebug>
67 #include <WebCore/Cursor.h>
68 #include <WebCore/DragData.h>
69 #include <WebCore/FloatRect.h>
70 #include <WebCore/NotImplemented.h>
71 #include <WebCore/Region.h>
72 #include <WebKit2/WKFrame.h>
73 #include <WebKit2/WKPageGroup.h>
74 #include <WebKit2/WKRetainPtr.h>
75
76 using namespace WebKit;
77 using namespace WebCore;
78
79 RefPtr<WebContext> QtWebPageProxy::s_defaultContext;
80 RefPtr<QtDownloadManager> QtWebPageProxy::s_downloadManager;
81
82 unsigned QtWebPageProxy::s_defaultPageProxyCount = 0;
83
84 PassRefPtr<WebContext> QtWebPageProxy::defaultWKContext()
85 {
86     if (!s_defaultContext) {
87         s_defaultContext = WebContext::create(String());
88         setupContextInjectedBundleClient(toAPI(s_defaultContext.get()));
89         s_downloadManager = QtDownloadManager::create(s_defaultContext.get());
90     }
91     return s_defaultContext;
92 }
93
94 static inline Qt::DropAction dragOperationToDropAction(unsigned dragOperation)
95 {
96     Qt::DropAction result = Qt::IgnoreAction;
97     if (dragOperation & DragOperationCopy)
98         result = Qt::CopyAction;
99     else if (dragOperation & DragOperationMove)
100         result = Qt::MoveAction;
101     else if (dragOperation & DragOperationGeneric)
102         result = Qt::MoveAction;
103     else if (dragOperation & DragOperationLink)
104         result = Qt::LinkAction;
105     return result;
106 }
107
108 static inline Qt::DropActions dragOperationToDropActions(unsigned dragOperations)
109 {
110     Qt::DropActions result = Qt::IgnoreAction;
111     if (dragOperations & DragOperationCopy)
112         result |= Qt::CopyAction;
113     if (dragOperations & DragOperationMove)
114         result |= Qt::MoveAction;
115     if (dragOperations & DragOperationGeneric)
116         result |= Qt::MoveAction;
117     if (dragOperations & DragOperationLink)
118         result |= Qt::LinkAction;
119     return result;
120 }
121
122 WebCore::DragOperation dropActionToDragOperation(Qt::DropActions actions)
123 {
124     unsigned result = 0;
125     if (actions & Qt::CopyAction)
126         result |= DragOperationCopy;
127     if (actions & Qt::MoveAction)
128         result |= (DragOperationMove | DragOperationGeneric);
129     if (actions & Qt::LinkAction)
130         result |= DragOperationLink;
131     if (result == (DragOperationCopy | DragOperationMove | DragOperationGeneric | DragOperationLink))
132         result = DragOperationEvery;
133     return (DragOperation)result;
134 }
135
136 QtWebPageProxy::QtWebPageProxy(QQuickWebPage* qmlWebPage, QQuickWebView* qmlWebView, QtViewportInteractionEngine* viewportInteractionEngine, QtPolicyInterface* policyInterface, WKContextRef contextRef, WKPageGroupRef pageGroupRef)
137     : m_qmlWebPage(qmlWebPage)
138     , m_qmlWebView(qmlWebView)
139     , m_interactionEngine(viewportInteractionEngine)
140     , m_panGestureRecognizer(viewportInteractionEngine)
141     , m_pinchGestureRecognizer(viewportInteractionEngine)
142     , m_tapGestureRecognizer(viewportInteractionEngine, this)
143     , m_policyInterface(policyInterface)
144     , m_context(contextRef ? toImpl(contextRef) : defaultWKContext())
145     , m_undoStack(adoptPtr(new QUndoStack(this)))
146     , m_navigatorQtObjectEnabled(false)
147 {
148     m_webPageProxy = m_context->createWebPage(this, toImpl(pageGroupRef));
149     m_history = QWKHistoryPrivate::createHistory(this, m_webPageProxy->backForwardList());
150     if (!contextRef)
151         s_defaultPageProxyCount++;
152 }
153
154 void QtWebPageProxy::init()
155 {
156     m_webPageProxy->initializeWebPage();
157     if (m_policyInterface)
158         setupPagePolicyClient(m_policyInterface, m_webPageProxy.get());
159 }
160
161 QtWebPageProxy::~QtWebPageProxy()
162 {
163     m_webPageProxy->close();
164     // The context is the default one and we're deleting the last QtWebPageProxy.
165     if (m_context == s_defaultContext) {
166         ASSERT(s_defaultPageProxyCount > 0);
167         s_defaultPageProxyCount--;
168         if (!s_defaultPageProxyCount) {
169             s_defaultContext.clear();
170             s_downloadManager.clear();
171         }
172     }
173     delete m_history;
174 }
175
176 bool QtWebPageProxy::handleEvent(QEvent* ev)
177 {
178     switch (ev->type()) {
179     case QEvent::MouseMove:
180         return handleMouseMoveEvent(reinterpret_cast<QMouseEvent*>(ev));
181     case QEvent::MouseButtonPress:
182         return handleMousePressEvent(reinterpret_cast<QMouseEvent*>(ev));
183     case QEvent::MouseButtonRelease:
184         return handleMouseReleaseEvent(reinterpret_cast<QMouseEvent*>(ev));
185     case QEvent::MouseButtonDblClick:
186         return handleMouseDoubleClickEvent(reinterpret_cast<QMouseEvent*>(ev));
187     case QEvent::Wheel:
188         return handleWheelEvent(reinterpret_cast<QWheelEvent*>(ev));
189     case QEvent::HoverLeave:
190         return handleHoverLeaveEvent(reinterpret_cast<QHoverEvent*>(ev));
191     case QEvent::HoverEnter: // Fall-through, for WebKit the distinction doesn't matter.
192     case QEvent::HoverMove:
193         return handleHoverMoveEvent(reinterpret_cast<QHoverEvent*>(ev));
194     case QEvent::DragEnter:
195         return handleDragEnterEvent(reinterpret_cast<QDragEnterEvent*>(ev));
196     case QEvent::DragLeave:
197         return handleDragLeaveEvent(reinterpret_cast<QDragLeaveEvent*>(ev));
198     case QEvent::DragMove:
199         return handleDragMoveEvent(reinterpret_cast<QDragMoveEvent*>(ev));
200     case QEvent::Drop:
201         return handleDropEvent(reinterpret_cast<QDropEvent*>(ev));
202     case QEvent::KeyPress:
203         return handleKeyPressEvent(reinterpret_cast<QKeyEvent*>(ev));
204     case QEvent::KeyRelease:
205         return handleKeyReleaseEvent(reinterpret_cast<QKeyEvent*>(ev));
206     case QEvent::FocusIn:
207         return handleFocusInEvent(reinterpret_cast<QFocusEvent*>(ev));
208     case QEvent::FocusOut:
209         return handleFocusOutEvent(reinterpret_cast<QFocusEvent*>(ev));
210     case QEvent::TouchBegin:
211     case QEvent::TouchEnd:
212     case QEvent::TouchUpdate:
213         touchEvent(static_cast<QTouchEvent*>(ev));
214         return true;
215     }
216
217     // FIXME: Move all common event handling here.
218     return false;
219 }
220
221 bool QtWebPageProxy::handleMouseMoveEvent(QMouseEvent* ev)
222 {
223     // For some reason mouse press results in mouse hover (which is
224     // converted to mouse move for WebKit). We ignore these hover
225     // events by comparing lastPos with newPos.
226     // NOTE: lastPos from the event always comes empty, so we work
227     // around that here.
228     static QPointF lastPos = QPointF();
229     if (lastPos == ev->pos())
230         return ev->isAccepted();
231     lastPos = ev->pos();
232
233     m_webPageProxy->handleMouseEvent(NativeWebMouseEvent(ev, /*eventClickCount=*/0));
234
235     return ev->isAccepted();
236 }
237
238 bool QtWebPageProxy::handleMousePressEvent(QMouseEvent* ev)
239 {
240     if (m_tripleClickTimer.isActive() && (ev->pos() - m_tripleClick).manhattanLength() < qApp->styleHints()->startDragDistance()) {
241         m_webPageProxy->handleMouseEvent(NativeWebMouseEvent(ev, /*eventClickCount=*/3));
242         return ev->isAccepted();
243     }
244
245     m_webPageProxy->handleMouseEvent(NativeWebMouseEvent(ev, /*eventClickCount=*/1));
246     return ev->isAccepted();
247 }
248
249 bool QtWebPageProxy::handleMouseReleaseEvent(QMouseEvent* ev)
250 {
251     m_webPageProxy->handleMouseEvent(NativeWebMouseEvent(ev, /*eventClickCount=*/0));
252     return ev->isAccepted();
253 }
254
255 bool QtWebPageProxy::handleMouseDoubleClickEvent(QMouseEvent* ev)
256 {
257     m_webPageProxy->handleMouseEvent(NativeWebMouseEvent(ev, /*eventClickCount=*/2));
258
259     m_tripleClickTimer.start(qApp->styleHints()->mouseDoubleClickInterval(), this);
260     m_tripleClick = ev->localPos().toPoint();
261     return ev->isAccepted();
262 }
263
264 bool QtWebPageProxy::handleWheelEvent(QWheelEvent* ev)
265 {
266     m_webPageProxy->handleWheelEvent(NativeWebWheelEvent(ev));
267     // FIXME: Handle whether the page used the wheel event or not.
268     if (m_interactionEngine)
269         m_interactionEngine->wheelEvent(ev);
270     return ev->isAccepted();
271 }
272
273 bool QtWebPageProxy::handleHoverLeaveEvent(QHoverEvent* ev)
274 {
275     // To get the correct behavior of mouseout, we need to turn the Leave event of our webview into a mouse move
276     // to a very far region.
277     QHoverEvent fakeEvent(QEvent::HoverMove, QPoint(INT_MIN, INT_MIN), ev->oldPos());
278     return handleHoverMoveEvent(&fakeEvent);
279 }
280
281 bool QtWebPageProxy::handleHoverMoveEvent(QHoverEvent* ev)
282 {
283     QMouseEvent me(QEvent::MouseMove, ev->pos(), Qt::NoButton, Qt::NoButton, Qt::NoModifier);
284     me.setAccepted(ev->isAccepted());
285
286     return handleMouseMoveEvent(&me);
287 }
288
289 bool QtWebPageProxy::handleDragEnterEvent(QDragEnterEvent* ev)
290 {
291     m_webPageProxy->resetDragOperation();
292     // FIXME: Should not use QCursor::pos()
293     DragData dragData(ev->mimeData(), ev->pos(), QCursor::pos(), dropActionToDragOperation(ev->possibleActions()));
294     m_webPageProxy->dragEntered(&dragData);
295     ev->acceptProposedAction();
296     return true;
297 }
298
299 bool QtWebPageProxy::handleDragLeaveEvent(QDragLeaveEvent* ev)
300 {
301     bool accepted = ev->isAccepted();
302
303     // FIXME: Should not use QCursor::pos()
304     DragData dragData(0, IntPoint(), QCursor::pos(), DragOperationNone);
305     m_webPageProxy->dragExited(&dragData);
306     m_webPageProxy->resetDragOperation();
307
308     ev->setAccepted(accepted);
309     return accepted;
310 }
311
312 bool QtWebPageProxy::handleDragMoveEvent(QDragMoveEvent* ev)
313 {
314     bool accepted = ev->isAccepted();
315
316     // FIXME: Should not use QCursor::pos()
317     DragData dragData(ev->mimeData(), ev->pos(), QCursor::pos(), dropActionToDragOperation(ev->possibleActions()));
318     m_webPageProxy->dragUpdated(&dragData);
319     ev->setDropAction(dragOperationToDropAction(m_webPageProxy->dragSession().operation));
320     if (m_webPageProxy->dragSession().operation != DragOperationNone)
321         ev->accept();
322
323     ev->setAccepted(accepted);
324     return accepted;
325 }
326
327 bool QtWebPageProxy::handleDropEvent(QDropEvent* ev)
328 {
329     bool accepted = ev->isAccepted();
330
331     // FIXME: Should not use QCursor::pos()
332     DragData dragData(ev->mimeData(), ev->pos(), QCursor::pos(), dropActionToDragOperation(ev->possibleActions()));
333     SandboxExtension::Handle handle;
334     m_webPageProxy->performDrag(&dragData, String(), handle);
335     ev->setDropAction(dragOperationToDropAction(m_webPageProxy->dragSession().operation));
336     ev->accept();
337
338     ev->setAccepted(accepted);
339     return accepted;
340 }
341
342 void QtWebPageProxy::handleSingleTapEvent(const QTouchEvent::TouchPoint& point)
343 {
344     WebGestureEvent gesture(WebEvent::GestureSingleTap, point.pos().toPoint(), point.screenPos().toPoint(), WebEvent::Modifiers(0), 0);
345     m_webPageProxy->handleGestureEvent(gesture);
346 }
347
348 void QtWebPageProxy::handleDoubleTapEvent(const QTouchEvent::TouchPoint& point)
349 {
350     m_webPageProxy->findZoomableAreaForPoint(point.pos().toPoint());
351 }
352
353 void QtWebPageProxy::showContextMenu(QSharedPointer<QMenu> menu)
354 {
355     // Remove the active menu in case this function is called twice.
356     if (activeMenu)
357         activeMenu->hide();
358
359     if (menu->isEmpty())
360         return;
361
362     QWindow* window = m_qmlWebView->canvas();
363     if (!window)
364         return;
365
366     activeMenu = menu;
367
368     activeMenu->window()->winId(); // Ensure that the menu has a window
369     Q_ASSERT(activeMenu->window()->windowHandle());
370     activeMenu->window()->windowHandle()->setTransientParent(window);
371
372     QPoint menuPositionInScene = m_qmlWebView->mapToScene(menu->pos()).toPoint();
373     menu->exec(window->mapToGlobal(menuPositionInScene));
374     // The last function to get out of exec() clear the local copy.
375     if (activeMenu == menu)
376         activeMenu.clear();
377 }
378
379 void QtWebPageProxy::hideContextMenu()
380 {
381     if (activeMenu)
382         activeMenu->hide();
383 }
384
385 void QtWebPageProxy::timerEvent(QTimerEvent* ev)
386 {
387     int timerId = ev->timerId();
388     if (timerId == m_tripleClickTimer.timerId())
389         m_tripleClickTimer.stop();
390     else
391         QObject::timerEvent(ev);
392 }
393
394 bool QtWebPageProxy::handleKeyPressEvent(QKeyEvent* ev)
395 {
396     m_webPageProxy->handleKeyboardEvent(NativeWebKeyboardEvent(ev));
397     return true;
398 }
399
400 bool QtWebPageProxy::handleKeyReleaseEvent(QKeyEvent* ev)
401 {
402     m_webPageProxy->handleKeyboardEvent(NativeWebKeyboardEvent(ev));
403     return true;
404 }
405
406 bool QtWebPageProxy::handleFocusInEvent(QFocusEvent*)
407 {
408     m_webPageProxy->viewStateDidChange(WebPageProxy::ViewIsFocused | WebPageProxy::ViewWindowIsActive);
409     return true;
410 }
411
412 bool QtWebPageProxy::handleFocusOutEvent(QFocusEvent*)
413 {
414     m_webPageProxy->viewStateDidChange(WebPageProxy::ViewIsFocused | WebPageProxy::ViewWindowIsActive);
415     return true;
416 }
417
418 void QtWebPageProxy::setCursor(const WebCore::Cursor& cursor)
419 {
420     // FIXME: This is a temporary fix until we get cursor support in QML items.
421     QGuiApplication::setOverrideCursor(*cursor.platformCursor());
422 }
423
424 void QtWebPageProxy::setCursorHiddenUntilMouseMoves(bool hiddenUntilMouseMoves)
425 {
426     notImplemented();
427 }
428
429 void QtWebPageProxy::setViewNeedsDisplay(const WebCore::IntRect&)
430 {
431     m_qmlWebPage->update();
432 }
433
434 void QtWebPageProxy::displayView()
435 {
436     // FIXME: Implement.
437 }
438
439 void QtWebPageProxy::scrollView(const WebCore::IntRect& scrollRect, const WebCore::IntSize& scrollOffset)
440 {
441     // FIXME: Implement.
442 }
443
444 WebCore::IntSize QtWebPageProxy::viewSize()
445 {
446     return WebCore::IntSize(m_qmlWebPage->width(), m_qmlWebPage->height());
447 }
448
449 bool QtWebPageProxy::isViewWindowActive()
450 {
451     // FIXME: The scene graph does not have the concept of being active or not when this was written.
452     return true;
453 }
454
455 bool QtWebPageProxy::isViewFocused()
456 {
457     return m_qmlWebView->hasFocus();
458 }
459
460 bool QtWebPageProxy::isViewVisible()
461 {
462     return m_qmlWebView->isVisible() && m_qmlWebPage->isVisible();
463 }
464
465 bool QtWebPageProxy::isViewInWindow()
466 {
467     // FIXME: Implement.
468     return true;
469 }
470
471 void QtWebPageProxy::enterAcceleratedCompositingMode(const LayerTreeContext&)
472 {
473     // FIXME: Implement.
474 }
475
476 void QtWebPageProxy::exitAcceleratedCompositingMode()
477 {
478     // FIXME: Implement.
479 }
480
481 void QtWebPageProxy::pageDidRequestScroll(const IntPoint& pos)
482 {
483     m_qmlWebView->d_func()->scrollPositionRequested(pos);
484 }
485
486 void QtWebPageProxy::didChangeContentsSize(const IntSize& newSize)
487 {
488     m_qmlWebView->d_func()->didChangeContentsSize(newSize);
489 }
490
491 void QtWebPageProxy::didChangeViewportProperties(const WebCore::ViewportArguments& args)
492 {
493     m_qmlWebView->d_func()->didChangeViewportProperties(args);
494 }
495
496 void QtWebPageProxy::toolTipChanged(const String&, const String& newTooltip)
497 {
498     // There is not yet any UI defined for the tooltips for mobile so we ignore the change.
499 }
500
501 void QtWebPageProxy::registerEditCommand(PassRefPtr<WebEditCommandProxy> command, WebPageProxy::UndoOrRedo undoOrRedo)
502 {
503     if (undoOrRedo == WebPageProxy::Undo) {
504         const QtWebUndoCommand* webUndoCommand = static_cast<const QtWebUndoCommand*>(m_undoStack->command(m_undoStack->index()));
505         if (webUndoCommand && webUndoCommand->inUndoRedo())
506             return;
507         m_undoStack->push(new QtWebUndoCommand(command));
508     }
509 }
510
511 void QtWebPageProxy::clearAllEditCommands()
512 {
513     m_undoStack->clear();
514 }
515
516 bool QtWebPageProxy::canUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
517 {
518     if (undoOrRedo == WebPageProxy::Undo)
519         return m_undoStack->canUndo();
520     return m_undoStack->canRedo();
521 }
522
523 void QtWebPageProxy::executeUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
524 {
525     if (undoOrRedo == WebPageProxy::Undo)
526         m_undoStack->undo();
527     else
528         m_undoStack->redo();
529 }
530
531 FloatRect QtWebPageProxy::convertToDeviceSpace(const FloatRect& rect)
532 {
533     return rect;
534 }
535
536 IntPoint QtWebPageProxy::screenToWindow(const IntPoint& point)
537 {
538     return point;
539 }
540
541 IntRect QtWebPageProxy::windowToScreen(const IntRect& rect)
542 {
543     return rect;
544 }
545
546 FloatRect QtWebPageProxy::convertToUserSpace(const FloatRect& rect)
547 {
548     return rect;
549 }
550
551 void QtWebPageProxy::selectionChanged(bool, bool, bool, bool)
552 {
553 }
554
555 void QtWebPageProxy::doneWithKeyEvent(const NativeWebKeyboardEvent&, bool)
556 {
557 }
558
559 PassRefPtr<WebPopupMenuProxy> QtWebPageProxy::createPopupMenuProxy(WebPageProxy*)
560 {
561     return WebPopupMenuProxyQtDesktop::create(m_webPageProxy.get(), m_qmlWebView);
562 }
563
564 PassRefPtr<WebContextMenuProxy> QtWebPageProxy::createContextMenuProxy(WebPageProxy*)
565 {
566     return WebContextMenuProxyQt::create(this);
567 }
568
569 void QtWebPageProxy::setFindIndicator(PassRefPtr<FindIndicator>, bool fadeOut, bool animate)
570 {
571 }
572
573 void QtWebPageProxy::didCommitLoadForMainFrame(bool useCustomRepresentation)
574 {
575 }
576
577 void QtWebPageProxy::didFinishLoadingDataForCustomRepresentation(const String& suggestedFilename, const CoreIPC::DataReference&)
578 {
579 }
580
581 void QtWebPageProxy::flashBackingStoreUpdates(const Vector<IntRect>&)
582 {
583     notImplemented();
584 }
585
586 WKPageRef QtWebPageProxy::pageRef() const
587 {
588     return toAPI(m_webPageProxy.get());;
589 }
590
591 void QtWebPageProxy::didFindZoomableArea(const IntPoint& target, const IntRect& area)
592 {
593     if (!m_interactionEngine)
594         return;
595
596     // FIXME: As the find method might not respond immediately during load etc,
597     // we should ignore all but the latest request.
598     m_interactionEngine->zoomToAreaGestureEnded(QPointF(target), QRectF(area));
599 }
600
601 void QtWebPageProxy::didReceiveMessageFromNavigatorQtObject(const String& message)
602 {
603     QVariantMap variantMap;
604     variantMap.insert(QLatin1String("data"), QString(message));
605     variantMap.insert(QLatin1String("origin"), url());
606     emit receivedMessageFromNavigatorQtObject(variantMap);
607 }
608
609 bool QtWebPageProxy::canGoBack() const
610 {
611     return m_webPageProxy->canGoBack();
612 }
613
614 void QtWebPageProxy::goBack()
615 {
616     m_webPageProxy->goBack();
617 }
618
619 bool QtWebPageProxy::canGoForward() const
620 {
621     return m_webPageProxy->canGoForward();
622 }
623
624 void QtWebPageProxy::goForward()
625 {
626     m_webPageProxy->goForward();
627 }
628
629 bool QtWebPageProxy::canStop() const
630 {
631     RefPtr<WebKit::WebFrameProxy> mainFrame = m_webPageProxy->mainFrame();
632     return mainFrame && !(WebFrameProxy::LoadStateFinished == mainFrame->loadState());
633 }
634
635 void QtWebPageProxy::stop()
636 {
637     m_webPageProxy->stopLoading();
638 }
639
640 bool QtWebPageProxy::canReload() const
641 {
642     RefPtr<WebKit::WebFrameProxy> mainFrame = m_webPageProxy->mainFrame();
643     if (mainFrame)
644         return (WebFrameProxy::LoadStateFinished == mainFrame->loadState());
645     return m_webPageProxy->backForwardList()->currentItem();
646 }
647
648 void QtWebPageProxy::reload()
649 {
650     m_webPageProxy->reload(/* reloadFromOrigin */ true);
651 }
652
653 void QtWebPageProxy::updateNavigationState()
654 {
655     emit m_qmlWebView->navigationStateChanged();
656 }
657
658 void QtWebPageProxy::didRelaunchProcess()
659 {
660     updateNavigationState();
661     qWarning("WARNING: The web process has been successfully restarted.");
662     setDrawingAreaSize(viewSize());
663 }
664
665 void QtWebPageProxy::processDidCrash()
666 {
667     updateNavigationState();
668     m_panGestureRecognizer.reset();
669     m_pinchGestureRecognizer.reset();
670     m_tapGestureRecognizer.reset();
671
672     WebCore::KURL url(WebCore::ParsedURLString, m_webPageProxy->urlAtProcessExit());
673     qWarning("WARNING: The web process experienced a crash on '%s'.", qPrintable(QUrl(url).toString(QUrl::RemoveUserInfo)));
674 }
675
676 QWebPreferences* QtWebPageProxy::preferences() const
677 {
678     if (!m_preferences)
679         m_preferences = adoptPtr(QWebPreferencesPrivate::createPreferences(const_cast<QtWebPageProxy*>(this)));
680     return m_preferences.get();
681 }
682
683 void QtWebPageProxy::setCustomUserAgent(const QString& userAgent)
684 {
685     WKRetainPtr<WKStringRef> wkUserAgent(WKStringCreateWithQString(userAgent));
686     WKPageSetCustomUserAgent(pageRef(), wkUserAgent.get());
687 }
688
689 QString QtWebPageProxy::customUserAgent() const
690 {
691     return WKStringCopyQString(WKPageCopyCustomUserAgent(pageRef()));
692 }
693
694 void QtWebPageProxy::setNavigatorQtObjectEnabled(bool enabled)
695 {
696     static String messageName("SetNavigatorQtObjectEnabled");
697
698     ASSERT(enabled != m_navigatorQtObjectEnabled);
699     // FIXME: Currently we have to keep this information in both processes and the setting is asynchronous.
700     m_navigatorQtObjectEnabled = enabled;
701     RefPtr<MutableArray> body = MutableArray::create();
702     body->append(m_webPageProxy.get());
703     RefPtr<WebBoolean> webEnabled = WebBoolean::create(enabled);
704     body->append(webEnabled.get());
705     m_context->postMessageToInjectedBundle(messageName, body.get());
706 }
707
708 void QtWebPageProxy::setViewportInteractionEngine(QtViewportInteractionEngine* engine)
709 {
710     m_interactionEngine = engine;
711     m_panGestureRecognizer.setViewportInteractionEngine(engine);
712     m_pinchGestureRecognizer.setViewportInteractionEngine(engine);
713     m_tapGestureRecognizer.setViewportInteractionEngine(engine);
714 }
715
716 void QtWebPageProxy::postMessageToNavigatorQtObject(const QString& message)
717 {
718     static String messageName("MessageToNavigatorQtObject");
719
720     RefPtr<MutableArray> body = MutableArray::create();
721     body->append(m_webPageProxy.get());
722     RefPtr<WebString> contents = WebString::create(String(message));
723     body->append(contents.get());
724     m_context->postMessageToInjectedBundle(messageName, body.get());
725 }
726
727 void QtWebPageProxy::loadHTMLString(const QString& html, const QUrl& baseUrl)
728 {
729     WKRetainPtr<WKURLRef> wkUrl(WKURLCreateWithQUrl(baseUrl));
730     WKRetainPtr<WKStringRef> wkHtmlString(WKStringCreateWithQString(html));
731
732     WKPageLoadHTMLString(pageRef(), wkHtmlString.get(), wkUrl.get());
733 }
734
735 void QtWebPageProxy::load(const QUrl& url)
736 {
737     WKRetainPtr<WKURLRef> wkurl(WKURLCreateWithQUrl(url));
738     WKPageLoadURL(pageRef(), wkurl.get());
739 }
740
741 QUrl QtWebPageProxy::url() const
742 {
743     WKRetainPtr<WKFrameRef> frame = WKPageGetMainFrame(pageRef());
744     if (!frame)
745         return QUrl();
746     return WKURLCopyQUrl(WKFrameCopyURL(frame.get()));
747 }
748
749 QString QtWebPageProxy::title() const
750 {
751     return WKStringCopyQString(WKPageCopyTitle(toAPI(m_webPageProxy.get())));
752 }
753
754 void QtWebPageProxy::setDrawingAreaSize(const QSize& size)
755 {
756     if (!m_webPageProxy->drawingArea())
757         return;
758
759     m_webPageProxy->drawingArea()->setSize(IntSize(size), IntSize());
760 }
761
762 qreal QtWebPageProxy::textZoomFactor() const
763 {
764     return WKPageGetTextZoomFactor(pageRef());
765 }
766
767 void QtWebPageProxy::setTextZoomFactor(qreal zoomFactor)
768 {
769     WKPageSetTextZoomFactor(pageRef(), zoomFactor);
770 }
771
772 qreal QtWebPageProxy::pageZoomFactor() const
773 {
774     return WKPageGetPageZoomFactor(pageRef());
775 }
776
777 void QtWebPageProxy::setPageZoomFactor(qreal zoomFactor)
778 {
779     WKPageSetPageZoomFactor(pageRef(), zoomFactor);
780 }
781
782 void QtWebPageProxy::setPageAndTextZoomFactors(qreal pageZoomFactor, qreal textZoomFactor)
783 {
784     WKPageSetPageAndTextZoomFactors(pageRef(), pageZoomFactor, textZoomFactor);
785 }
786
787 QWKHistory* QtWebPageProxy::history() const
788 {
789     return m_history;
790 }
791
792 void QtWebPageProxy::startDrag(const WebCore::DragData& dragData, PassRefPtr<ShareableBitmap> dragImage)
793 {
794     QImage dragQImage;
795     if (dragImage)
796         dragQImage = dragImage->createQImage();
797     else if (dragData.platformData() && dragData.platformData()->hasImage())
798         dragQImage = qvariant_cast<QImage>(dragData.platformData()->imageData());
799
800
801     DragOperation dragOperationMask = dragData.draggingSourceOperationMask();
802     QMimeData* mimeData = const_cast<QMimeData*>(dragData.platformData());
803     Qt::DropActions supportedDropActions = dragOperationToDropActions(dragOperationMask);
804
805     QPoint clientPosition;
806     QPoint globalPosition;
807     Qt::DropAction actualDropAction = Qt::IgnoreAction;
808
809     if (QWindow* window = m_qmlWebView->canvas()) {
810         QDrag* drag = new QDrag(window);
811         drag->setPixmap(QPixmap::fromImage(dragQImage));
812         drag->setMimeData(mimeData);
813         actualDropAction = drag->exec(supportedDropActions);
814         globalPosition = QCursor::pos();
815         clientPosition = window->mapFromGlobal(globalPosition);
816     }
817
818     m_webPageProxy->dragEnded(clientPosition, globalPosition, dropActionToDragOperation(actualDropAction));
819 }
820
821 void QtWebPageProxy::handleDownloadRequest(DownloadProxy* download)
822 {
823     // This function is responsible for hooking up a DownloadProxy to our API layer
824     // by creating a QWebDownloadItem. It will then wait for the QWebDownloadItem to be
825     // ready (filled with the ResourceResponse information) so we can pass it through to
826     // our WebViews.
827     QWebDownloadItem* downloadItem = new QWebDownloadItem();
828     downloadItem->d->downloadProxy = download;
829
830     connect(downloadItem->d, SIGNAL(receivedResponse(QWebDownloadItem*)), this, SLOT(didReceiveDownloadResponse(QWebDownloadItem*)));
831     s_downloadManager->addDownload(download, downloadItem);
832 }
833
834 void QtWebPageProxy::didReceiveDownloadResponse(QWebDownloadItem* downloadItem)
835 {
836     // Now that our downloadItem has everything we need we can emit downloadRequested.
837     if (!downloadItem)
838         return;
839
840     QDeclarativeEngine::setObjectOwnership(downloadItem, QDeclarativeEngine::JavaScriptOwnership);
841     emit m_qmlWebView->downloadRequested(downloadItem);
842 }
843
844 PassOwnPtr<DrawingAreaProxy> QtWebPageProxy::createDrawingAreaProxy()
845 {
846     return DrawingAreaProxyImpl::create(m_webPageProxy.get());
847 }
848
849 void QtWebPageProxy::renderToCurrentGLContext(const TransformationMatrix& transform, float opacity)
850 {
851     DrawingAreaProxy* drawingArea = m_webPageProxy->drawingArea();
852     if (drawingArea)
853         drawingArea->paintToCurrentGLContext(transform, opacity);
854 }
855
856 #if ENABLE(TOUCH_EVENTS)
857 void QtWebPageProxy::doneWithTouchEvent(const NativeWebTouchEvent& event, bool wasEventHandled)
858 {
859     if (!m_interactionEngine)
860         return;
861
862     if (wasEventHandled || event.type() == WebEvent::TouchCancel) {
863         m_panGestureRecognizer.reset();
864         m_pinchGestureRecognizer.reset();
865         m_tapGestureRecognizer.reset();
866         return;
867     }
868
869     const QTouchEvent* ev = event.nativeEvent();
870
871     switch (ev->type()) {
872     case QEvent::TouchBegin:
873         ASSERT(!m_interactionEngine->panGestureActive());
874         ASSERT(!m_interactionEngine->pinchGestureActive());
875
876         // The interaction engine might still be animating kinetic scrolling or a scale animation
877         // such as double-tap to zoom or the bounce back effect. A touch stops the kinetic scrolling
878         // where as it does not stop the scale animation.
879         if (m_interactionEngine->scrollAnimationActive())
880             m_interactionEngine->interruptScrollAnimation();
881         break;
882     case QEvent::TouchUpdate:
883         // The scale animation can only be interrupted by a pinch gesture, which will then take over.
884         if (m_interactionEngine->scaleAnimationActive() && m_pinchGestureRecognizer.isRecognized())
885             m_interactionEngine->interruptScaleAnimation();
886         break;
887     default:
888         break;
889     }
890
891     // If the scale animation is active we don't pass the event to the recognizers. In the future
892     // we would want to queue the event here and repost then when the animation ends.
893     if (m_interactionEngine->scaleAnimationActive())
894         return;
895
896     // Convert the event timestamp from second to millisecond.
897     qint64 eventTimestampMillis = static_cast<qint64>(event.timestamp() * 1000);
898     m_panGestureRecognizer.recognize(ev, eventTimestampMillis);
899     m_pinchGestureRecognizer.recognize(ev);
900
901     if (m_panGestureRecognizer.isRecognized() || m_pinchGestureRecognizer.isRecognized())
902         m_tapGestureRecognizer.reset();
903     else {
904         const QTouchEvent* ev = event.nativeEvent();
905         m_tapGestureRecognizer.recognize(ev, eventTimestampMillis);
906     }
907 }
908 #endif
909
910 void QtWebPageProxy::setVisibleContentRectAndScale(const QRectF& visibleContentRect, float scale)
911 {
912     if (!m_webPageProxy->drawingArea())
913         return;
914
915     QRect alignedVisibleContentRect = visibleContentRect.toAlignedRect();
916     m_webPageProxy->drawingArea()->setVisibleContentsRectAndScale(alignedVisibleContentRect, scale);
917
918     // FIXME: Once we support suspend and resume, this should be delayed until the page is active if the page is suspended.
919     m_webPageProxy->setFixedVisibleContentRect(alignedVisibleContentRect);
920 }
921
922 void QtWebPageProxy::setVisibleContentRectTrajectoryVector(const QPointF& trajectoryVector)
923 {
924     if (!m_webPageProxy->drawingArea())
925         return;
926
927     m_webPageProxy->drawingArea()->setVisibleContentRectTrajectoryVector(trajectoryVector);
928 }
929
930 void QtWebPageProxy::touchEvent(QTouchEvent* event)
931 {
932 #if ENABLE(TOUCH_EVENTS)
933     m_webPageProxy->handleTouchEvent(NativeWebTouchEvent(event));
934     event->accept();
935 #else
936     ASSERT_NOT_REACHED();
937     ev->ignore();
938 #endif
939 }
940
941 void QtWebPageProxy::findZoomableAreaForPoint(const QPoint& point)
942 {
943     m_webPageProxy->findZoomableAreaForPoint(point);
944 }
945
946 #include "moc_QtWebPageProxy.cpp"