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