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