[Qt][WK2] Do not apply new viewport properties until after the first visually non...
[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 "QtWebError.h"
25 #include "qwebdownloaditem.h"
26 #include "qwebdownloaditem_p.h"
27 #include "qwebpreferences.h"
28 #include "qwebpreferences_p.h"
29
30 #include "ClientImpl.h"
31 #include "DownloadProxy.h"
32 #include "DrawingAreaProxyImpl.h"
33 #include "qwkhistory.h"
34 #include "qwkhistory_p.h"
35 #include "FindIndicator.h"
36 #include "LocalizedStrings.h"
37 #include "MutableArray.h"
38 #include "NativeWebKeyboardEvent.h"
39 #include "NativeWebMouseEvent.h"
40 #include "NativeWebWheelEvent.h"
41 #include "NotImplemented.h"
42 #include "QtPolicyInterface.h"
43 #include "QtViewInterface.h"
44 #include "QtViewportInteractionEngine.h"
45 #include "QtWebUndoCommand.h"
46 #include "WebBackForwardList.h"
47 #include "WebContext.h"
48 #include "WebContextMenuProxyQt.h"
49 #include "WebEditCommandProxy.h"
50 #include "WebEventFactoryQt.h"
51 #include "WebPopupMenuProxyQt.h"
52 #include "WKStringQt.h"
53 #include "WKURLQt.h"
54 #include <QGuiApplication>
55 #include <QGraphicsSceneMouseEvent>
56 #include <QJSEngine>
57 #include <QMimeData>
58 #include <QStyleHints>
59 #include <QTouchEvent>
60 #include <QUndoStack>
61 #include <QtDebug>
62 #include <WebCore/Cursor.h>
63 #include <WebCore/DragData.h>
64 #include <WebCore/FloatRect.h>
65 #include <WebCore/NotImplemented.h>
66 #include <WebCore/Region.h>
67 #include <WebKit2/WKFrame.h>
68 #include <WebKit2/WKPageGroup.h>
69 #include <WebKit2/WKRetainPtr.h>
70
71 using namespace WebKit;
72 using namespace WebCore;
73
74 RefPtr<WebContext> QtWebPageProxy::s_defaultContext;
75 RefPtr<QtDownloadManager> QtWebPageProxy::s_downloadManager;
76
77 unsigned QtWebPageProxy::s_defaultPageProxyCount = 0;
78
79 PassRefPtr<WebContext> QtWebPageProxy::defaultWKContext()
80 {
81     if (!s_defaultContext) {
82         s_defaultContext = WebContext::create(String());
83         setupContextInjectedBundleClient(toAPI(s_defaultContext.get()));
84         s_downloadManager = QtDownloadManager::create(s_defaultContext.get());
85     }
86     return s_defaultContext;
87 }
88
89 static inline Qt::DropAction dragOperationToDropAction(unsigned dragOperation)
90 {
91     Qt::DropAction result = Qt::IgnoreAction;
92     if (dragOperation & DragOperationCopy)
93         result = Qt::CopyAction;
94     else if (dragOperation & DragOperationMove)
95         result = Qt::MoveAction;
96     else if (dragOperation & DragOperationGeneric)
97         result = Qt::MoveAction;
98     else if (dragOperation & DragOperationLink)
99         result = Qt::LinkAction;
100     return result;
101 }
102
103 static inline Qt::DropActions dragOperationToDropActions(unsigned dragOperations)
104 {
105     Qt::DropActions result = Qt::IgnoreAction;
106     if (dragOperations & DragOperationCopy)
107         result |= Qt::CopyAction;
108     if (dragOperations & DragOperationMove)
109         result |= Qt::MoveAction;
110     if (dragOperations & DragOperationGeneric)
111         result |= Qt::MoveAction;
112     if (dragOperations & DragOperationLink)
113         result |= Qt::LinkAction;
114     return result;
115 }
116
117 WebCore::DragOperation dropActionToDragOperation(Qt::DropActions actions)
118 {
119     unsigned result = 0;
120     if (actions & Qt::CopyAction)
121         result |= DragOperationCopy;
122     if (actions & Qt::MoveAction)
123         result |= (DragOperationMove | DragOperationGeneric);
124     if (actions & Qt::LinkAction)
125         result |= DragOperationLink;
126     if (result == (DragOperationCopy | DragOperationMove | DragOperationGeneric | DragOperationLink))
127         result = DragOperationEvery;
128     return (DragOperation)result;
129 }
130
131 QtWebPageProxy::QtWebPageProxy(QtViewInterface* viewInterface, QtViewportInteractionEngine* viewportInteractionEngine, QtPolicyInterface* policyInterface, WKContextRef contextRef, WKPageGroupRef pageGroupRef)
132     : m_viewInterface(viewInterface)
133     , m_interactionEngine(viewportInteractionEngine)
134     , m_panGestureRecognizer(viewportInteractionEngine)
135     , m_pinchGestureRecognizer(viewportInteractionEngine)
136     , m_tapGestureRecognizer(viewportInteractionEngine, this)
137     , m_policyInterface(policyInterface)
138     , m_context(contextRef ? toImpl(contextRef) : defaultWKContext())
139     , m_undoStack(adoptPtr(new QUndoStack(this)))
140     , m_loadProgress(0)
141     , m_navigatorQtObjectEnabled(false)
142 {
143     ASSERT(viewInterface);
144     m_webPageProxy = m_context->createWebPage(this, toImpl(pageGroupRef));
145     m_history = QWKHistoryPrivate::createHistory(this, m_webPageProxy->backForwardList());
146     if (!contextRef)
147         s_defaultPageProxyCount++;
148 }
149
150 void QtWebPageProxy::init()
151 {
152     m_webPageProxy->initializeWebPage();
153
154     setupPageLoaderClient(this, m_webPageProxy.get());
155     setupPageUiClient(this, m_webPageProxy.get());
156
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     return ev->isAccepted();
268 }
269
270 bool QtWebPageProxy::handleHoverLeaveEvent(QHoverEvent* ev)
271 {
272     // To get the correct behavior of mouseout, we need to turn the Leave event of our webview into a mouse move
273     // to a very far region.
274     QHoverEvent fakeEvent(QEvent::HoverMove, QPoint(INT_MIN, INT_MIN), ev->oldPos());
275     return handleHoverMoveEvent(&fakeEvent);
276 }
277
278 bool QtWebPageProxy::handleHoverMoveEvent(QHoverEvent* ev)
279 {
280     QMouseEvent me(QEvent::MouseMove, ev->pos(), Qt::NoButton, Qt::NoButton, Qt::NoModifier);
281     me.setAccepted(ev->isAccepted());
282
283     return handleMouseMoveEvent(&me);
284 }
285
286 bool QtWebPageProxy::handleDragEnterEvent(QDragEnterEvent* ev)
287 {
288     m_webPageProxy->resetDragOperation();
289     // FIXME: Should not use QCursor::pos()
290     DragData dragData(ev->mimeData(), ev->pos(), QCursor::pos(), dropActionToDragOperation(ev->possibleActions()));
291     m_webPageProxy->dragEntered(&dragData);
292     ev->acceptProposedAction();
293     return true;
294 }
295
296 bool QtWebPageProxy::handleDragLeaveEvent(QDragLeaveEvent* ev)
297 {
298     bool accepted = ev->isAccepted();
299
300     // FIXME: Should not use QCursor::pos()
301     DragData dragData(0, IntPoint(), QCursor::pos(), DragOperationNone);
302     m_webPageProxy->dragExited(&dragData);
303     m_webPageProxy->resetDragOperation();
304
305     ev->setAccepted(accepted);
306     return accepted;
307 }
308
309 bool QtWebPageProxy::handleDragMoveEvent(QDragMoveEvent* ev)
310 {
311     bool accepted = ev->isAccepted();
312
313     // FIXME: Should not use QCursor::pos()
314     DragData dragData(ev->mimeData(), ev->pos(), QCursor::pos(), dropActionToDragOperation(ev->possibleActions()));
315     m_webPageProxy->dragUpdated(&dragData);
316     ev->setDropAction(dragOperationToDropAction(m_webPageProxy->dragSession().operation));
317     if (m_webPageProxy->dragSession().operation != DragOperationNone)
318         ev->accept();
319
320     ev->setAccepted(accepted);
321     return accepted;
322 }
323
324 bool QtWebPageProxy::handleDropEvent(QDropEvent* ev)
325 {
326     bool accepted = ev->isAccepted();
327
328     // FIXME: Should not use QCursor::pos()
329     DragData dragData(ev->mimeData(), ev->pos(), QCursor::pos(), dropActionToDragOperation(ev->possibleActions()));
330     SandboxExtension::Handle handle;
331     m_webPageProxy->performDrag(&dragData, String(), handle);
332     ev->setDropAction(dragOperationToDropAction(m_webPageProxy->dragSession().operation));
333     ev->accept();
334
335     ev->setAccepted(accepted);
336     return accepted;
337 }
338
339 void QtWebPageProxy::handleSingleTapEvent(const QTouchEvent::TouchPoint& point)
340 {
341     WebGestureEvent gesture(WebEvent::GestureSingleTap, point.pos().toPoint(), point.screenPos().toPoint(), WebEvent::Modifiers(0), 0);
342     m_webPageProxy->handleGestureEvent(gesture);
343 }
344
345 void QtWebPageProxy::handleDoubleTapEvent(const QTouchEvent::TouchPoint& point)
346 {
347     m_webPageProxy->findZoomableAreaForPoint(point.pos().toPoint());
348 }
349
350 void QtWebPageProxy::timerEvent(QTimerEvent* ev)
351 {
352     int timerId = ev->timerId();
353     if (timerId == m_tripleClickTimer.timerId())
354         m_tripleClickTimer.stop();
355     else
356         QObject::timerEvent(ev);
357 }
358
359 bool QtWebPageProxy::handleKeyPressEvent(QKeyEvent* ev)
360 {
361     m_webPageProxy->handleKeyboardEvent(NativeWebKeyboardEvent(ev));
362     return true;
363 }
364
365 bool QtWebPageProxy::handleKeyReleaseEvent(QKeyEvent* ev)
366 {
367     m_webPageProxy->handleKeyboardEvent(NativeWebKeyboardEvent(ev));
368     return true;
369 }
370
371 bool QtWebPageProxy::handleFocusInEvent(QFocusEvent*)
372 {
373     m_webPageProxy->viewStateDidChange(WebPageProxy::ViewIsFocused | WebPageProxy::ViewWindowIsActive);
374     return true;
375 }
376
377 bool QtWebPageProxy::handleFocusOutEvent(QFocusEvent*)
378 {
379     m_webPageProxy->viewStateDidChange(WebPageProxy::ViewIsFocused | WebPageProxy::ViewWindowIsActive);
380     return true;
381 }
382
383 void QtWebPageProxy::setCursor(const WebCore::Cursor& cursor)
384 {
385     m_viewInterface->didChangeCursor(*cursor.platformCursor());
386 }
387
388 void QtWebPageProxy::setCursorHiddenUntilMouseMoves(bool hiddenUntilMouseMoves)
389 {
390     notImplemented();
391 }
392
393 void QtWebPageProxy::setViewNeedsDisplay(const WebCore::IntRect& rect)
394 {
395     m_viewInterface->setViewNeedsDisplay(QRect(rect));
396 }
397
398 void QtWebPageProxy::displayView()
399 {
400     // FIXME: Implement.
401 }
402
403 void QtWebPageProxy::scrollView(const WebCore::IntRect& scrollRect, const WebCore::IntSize& scrollOffset)
404 {
405     // FIXME: Implement.
406 }
407
408 WebCore::IntSize QtWebPageProxy::viewSize()
409 {
410     return WebCore::IntSize(m_viewInterface->drawingAreaSize());
411 }
412
413 bool QtWebPageProxy::isViewWindowActive()
414 {
415     return m_viewInterface->isActive();
416 }
417
418 bool QtWebPageProxy::isViewFocused()
419 {
420     return m_viewInterface->hasFocus();
421 }
422
423 bool QtWebPageProxy::isViewVisible()
424 {
425     return m_viewInterface->isVisible();
426 }
427
428 bool QtWebPageProxy::isViewInWindow()
429 {
430     // FIXME: Implement.
431     return true;
432 }
433
434 void QtWebPageProxy::enterAcceleratedCompositingMode(const LayerTreeContext&)
435 {
436     // FIXME: Implement.
437 }
438
439 void QtWebPageProxy::exitAcceleratedCompositingMode()
440 {
441     // FIXME: Implement.
442 }
443
444 void QtWebPageProxy::pageDidRequestScroll(const IntPoint& pos)
445 {
446     m_viewInterface->scrollPositionRequested(pos);
447 }
448
449 void QtWebPageProxy::didFinishFirstNonEmptyLayout()
450 {
451     m_viewInterface->didFinishFirstNonEmptyLayout();
452 }
453
454 void QtWebPageProxy::didChangeContentsSize(const IntSize& newSize)
455 {
456     m_viewInterface->didChangeContentsSize(QSize(newSize));
457 }
458
459 void QtWebPageProxy::didChangeViewportProperties(const WebCore::ViewportArguments& args)
460 {
461     m_viewInterface->didChangeViewportProperties(args);
462 }
463
464 void QtWebPageProxy::toolTipChanged(const String&, const String& newTooltip)
465 {
466     m_viewInterface->didChangeToolTip(QString(newTooltip));
467 }
468
469 void QtWebPageProxy::registerEditCommand(PassRefPtr<WebEditCommandProxy> command, WebPageProxy::UndoOrRedo undoOrRedo)
470 {
471     if (undoOrRedo == WebPageProxy::Undo) {
472         const QtWebUndoCommand* webUndoCommand = static_cast<const QtWebUndoCommand*>(m_undoStack->command(m_undoStack->index()));
473         if (webUndoCommand && webUndoCommand->inUndoRedo())
474             return;
475         m_undoStack->push(new QtWebUndoCommand(command));
476     }
477 }
478
479 void QtWebPageProxy::clearAllEditCommands()
480 {
481     m_undoStack->clear();
482 }
483
484 bool QtWebPageProxy::canUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
485 {
486     if (undoOrRedo == WebPageProxy::Undo)
487         return m_undoStack->canUndo();
488     return m_undoStack->canRedo();
489 }
490
491 void QtWebPageProxy::executeUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
492 {
493     if (undoOrRedo == WebPageProxy::Undo)
494         m_undoStack->undo();
495     else
496         m_undoStack->redo();
497 }
498
499 FloatRect QtWebPageProxy::convertToDeviceSpace(const FloatRect& rect)
500 {
501     return rect;
502 }
503
504 IntPoint QtWebPageProxy::screenToWindow(const IntPoint& point)
505 {
506     return point;
507 }
508
509 IntRect QtWebPageProxy::windowToScreen(const IntRect& rect)
510 {
511     return rect;
512 }
513
514 FloatRect QtWebPageProxy::convertToUserSpace(const FloatRect& rect)
515 {
516     return rect;
517 }
518
519 void QtWebPageProxy::selectionChanged(bool, bool, bool, bool)
520 {
521 }
522
523 void QtWebPageProxy::doneWithKeyEvent(const NativeWebKeyboardEvent&, bool)
524 {
525 }
526
527 PassRefPtr<WebPopupMenuProxy> QtWebPageProxy::createPopupMenuProxy(WebPageProxy*)
528 {
529     return WebPopupMenuProxyQt::create();
530 }
531
532 PassRefPtr<WebContextMenuProxy> QtWebPageProxy::createContextMenuProxy(WebPageProxy*)
533 {
534     return WebContextMenuProxyQt::create(m_webPageProxy.get(), m_viewInterface);
535 }
536
537 void QtWebPageProxy::setFindIndicator(PassRefPtr<FindIndicator>, bool fadeOut, bool animate)
538 {
539 }
540
541 void QtWebPageProxy::didCommitLoadForMainFrame(bool useCustomRepresentation)
542 {
543 }
544
545 void QtWebPageProxy::didFinishLoadingDataForCustomRepresentation(const String& suggestedFilename, const CoreIPC::DataReference&)
546 {
547 }
548
549 void QtWebPageProxy::flashBackingStoreUpdates(const Vector<IntRect>&)
550 {
551     notImplemented();
552 }
553
554 WKPageRef QtWebPageProxy::pageRef() const
555 {
556     return toAPI(m_webPageProxy.get());;
557 }
558
559 void QtWebPageProxy::didFindZoomableArea(const IntPoint& target, const IntRect& area)
560 {
561     // FIXME: As the find method might not respond immediately during load etc,
562     // we should ignore all but the latest request.
563     m_interactionEngine->zoomToAreaGestureEnded(QPointF(target), QRectF(area));
564 }
565
566 void QtWebPageProxy::didReceiveMessageFromNavigatorQtObject(const String& message)
567 {
568     QVariantMap variantMap;
569     variantMap.insert(QLatin1String("data"), QString(message));
570     variantMap.insert(QLatin1String("origin"), url());
571     emit receivedMessageFromNavigatorQtObject(variantMap);
572 }
573
574 void QtWebPageProxy::didChangeUrl(const QUrl& url)
575 {
576     m_viewInterface->didChangeUrl(url);
577 }
578
579 void QtWebPageProxy::didChangeTitle(const QString& newTitle)
580 {
581     m_viewInterface->didChangeTitle(newTitle);
582 }
583
584 void QtWebPageProxy::loadDidBegin()
585 {
586     m_viewInterface->loadDidBegin();
587 }
588
589 void QtWebPageProxy::loadDidCommit()
590 {
591     m_viewInterface->loadDidCommit();
592 }
593
594 void QtWebPageProxy::loadDidSucceed()
595 {
596     m_viewInterface->loadDidSucceed();
597 }
598
599 void QtWebPageProxy::loadDidFail(const QtWebError& error)
600 {
601     m_viewInterface->loadDidFail(error);
602 }
603
604 void QtWebPageProxy::didChangeLoadProgress(int newLoadProgress)
605 {
606     m_loadProgress = newLoadProgress;
607     m_viewInterface->didChangeLoadProgress(newLoadProgress);
608 }
609
610 void QtWebPageProxy::paint(QPainter* painter, const QRect& area)
611 {
612     if (m_webPageProxy->isValid())
613         paintContent(painter, area);
614     else
615         painter->fillRect(area, Qt::white);
616 }
617
618 bool QtWebPageProxy::canGoBack() const
619 {
620     return m_webPageProxy->canGoBack();
621 }
622
623 void QtWebPageProxy::goBack()
624 {
625     m_webPageProxy->goBack();
626 }
627
628 bool QtWebPageProxy::canGoForward() const
629 {
630     return m_webPageProxy->canGoForward();
631 }
632
633 void QtWebPageProxy::goForward()
634 {
635     m_webPageProxy->goForward();
636 }
637
638 bool QtWebPageProxy::canStop() const
639 {
640     RefPtr<WebKit::WebFrameProxy> mainFrame = m_webPageProxy->mainFrame();
641     return mainFrame && !(WebFrameProxy::LoadStateFinished == mainFrame->loadState());
642 }
643
644 void QtWebPageProxy::stop()
645 {
646     m_webPageProxy->stopLoading();
647 }
648
649 bool QtWebPageProxy::canReload() const
650 {
651     RefPtr<WebKit::WebFrameProxy> mainFrame = m_webPageProxy->mainFrame();
652     if (mainFrame)
653         return (WebFrameProxy::LoadStateFinished == mainFrame->loadState());
654     return m_webPageProxy->backForwardList()->currentItem();
655 }
656
657 void QtWebPageProxy::reload()
658 {
659     m_webPageProxy->reload(/* reloadFromOrigin */ true);
660 }
661
662 void QtWebPageProxy::navigationStateChanged()
663 {
664     emit updateNavigationState();
665 }
666
667 void QtWebPageProxy::didRelaunchProcess()
668 {
669     updateNavigationState();
670     m_viewInterface->didRelaunchProcess();
671     setDrawingAreaSize(m_viewInterface->drawingAreaSize());
672 }
673
674 void QtWebPageProxy::processDidCrash()
675 {
676     updateNavigationState();
677     m_panGestureRecognizer.reset();
678     m_pinchGestureRecognizer.reset();
679     m_tapGestureRecognizer.reset();
680     m_viewInterface->processDidCrash();
681 }
682
683 QWebPreferences* QtWebPageProxy::preferences() const
684 {
685     if (!m_preferences)
686         m_preferences = adoptPtr(QWebPreferencesPrivate::createPreferences(const_cast<QtWebPageProxy*>(this)));
687     return m_preferences.get();
688 }
689
690 void QtWebPageProxy::setCustomUserAgent(const QString& userAgent)
691 {
692     WKRetainPtr<WKStringRef> wkUserAgent(WKStringCreateWithQString(userAgent));
693     WKPageSetCustomUserAgent(pageRef(), wkUserAgent.get());
694 }
695
696 QString QtWebPageProxy::customUserAgent() const
697 {
698     return WKStringCopyQString(WKPageCopyCustomUserAgent(pageRef()));
699 }
700
701 void QtWebPageProxy::setNavigatorQtObjectEnabled(bool enabled)
702 {
703     static String messageName("SetNavigatorQtObjectEnabled");
704
705     ASSERT(enabled != m_navigatorQtObjectEnabled);
706     // FIXME: Currently we have to keep this information in both processes and the setting is asynchronous.
707     m_navigatorQtObjectEnabled = enabled;
708     RefPtr<MutableArray> body = MutableArray::create();
709     body->append(m_webPageProxy.get());
710     RefPtr<WebBoolean> webEnabled = WebBoolean::create(enabled);
711     body->append(webEnabled.get());
712     m_context->postMessageToInjectedBundle(messageName, body.get());
713 }
714
715 void QtWebPageProxy::postMessageToNavigatorQtObject(const QString& message)
716 {
717     static String messageName("MessageToNavigatorQtObject");
718
719     RefPtr<MutableArray> body = MutableArray::create();
720     body->append(m_webPageProxy.get());
721     RefPtr<WebString> contents = WebString::create(String(message));
722     body->append(contents.get());
723     m_context->postMessageToInjectedBundle(messageName, body.get());
724 }
725
726 void QtWebPageProxy::load(const QUrl& url)
727 {
728     WKRetainPtr<WKURLRef> wkurl(WKURLCreateWithQUrl(url));
729     WKPageLoadURL(pageRef(), wkurl.get());
730 }
731
732 QUrl QtWebPageProxy::url() const
733 {
734     WKRetainPtr<WKFrameRef> frame = WKPageGetMainFrame(pageRef());
735     if (!frame)
736         return QUrl();
737     return WKURLCopyQUrl(WKFrameCopyURL(frame.get()));
738 }
739
740 QString QtWebPageProxy::title() const
741 {
742     return WKStringCopyQString(WKPageCopyTitle(toAPI(m_webPageProxy.get())));
743 }
744
745 void QtWebPageProxy::setDrawingAreaSize(const QSize& size)
746 {
747     if (!m_webPageProxy->drawingArea())
748         return;
749     m_webPageProxy->drawingArea()->setSize(IntSize(size), IntSize());
750 }
751
752 qreal QtWebPageProxy::textZoomFactor() const
753 {
754     return WKPageGetTextZoomFactor(pageRef());
755 }
756
757 void QtWebPageProxy::setTextZoomFactor(qreal zoomFactor)
758 {
759     WKPageSetTextZoomFactor(pageRef(), zoomFactor);
760 }
761
762 qreal QtWebPageProxy::pageZoomFactor() const
763 {
764     return WKPageGetPageZoomFactor(pageRef());
765 }
766
767 void QtWebPageProxy::setPageZoomFactor(qreal zoomFactor)
768 {
769     WKPageSetPageZoomFactor(pageRef(), zoomFactor);
770 }
771
772 void QtWebPageProxy::setPageAndTextZoomFactors(qreal pageZoomFactor, qreal textZoomFactor)
773 {
774     WKPageSetPageAndTextZoomFactors(pageRef(), pageZoomFactor, textZoomFactor);
775 }
776
777 QWKHistory* QtWebPageProxy::history() const
778 {
779     return m_history;
780 }
781
782 void QtWebPageProxy::startDrag(const WebCore::DragData& dragData, PassRefPtr<ShareableBitmap> dragImage)
783 {
784     QImage dragQImage;
785     if (dragImage)
786         dragQImage = dragImage->createQImage();
787     else if (dragData.platformData() && dragData.platformData()->hasImage())
788         dragQImage = qvariant_cast<QImage>(dragData.platformData()->imageData());
789
790
791     DragOperation dragOperationMask = dragData.draggingSourceOperationMask();
792     QMimeData* mimeData = const_cast<QMimeData*>(dragData.platformData());
793     Qt::DropActions supportedDropActions = dragOperationToDropActions(dragOperationMask);
794
795     QPoint clientPosition;
796     QPoint globalPosition;
797     Qt::DropAction actualDropAction;
798
799     m_viewInterface->startDrag(supportedDropActions, dragQImage, mimeData,
800                                &clientPosition, &globalPosition, &actualDropAction);
801
802     m_webPageProxy->dragEnded(clientPosition, globalPosition, dropActionToDragOperation(actualDropAction));
803 }
804
805 void QtWebPageProxy::handleDownloadRequest(DownloadProxy* download)
806 {
807     // This function is responsible for hooking up a DownloadProxy to our API layer
808     // by creating a QWebDownloadItem. It will then wait for the QWebDownloadItem to be
809     // ready (filled with the ResourceResponse information) so we can pass it through to
810     // our WebViews.
811     QWebDownloadItem* downloadItem = new QWebDownloadItem();
812     downloadItem->d->downloadProxy = download;
813
814     connect(downloadItem->d, SIGNAL(receivedResponse(QWebDownloadItem*)), this, SLOT(didReceiveDownloadResponse(QWebDownloadItem*)));
815     s_downloadManager->addDownload(download, downloadItem);
816 }
817
818 void QtWebPageProxy::didReceiveDownloadResponse(QWebDownloadItem* download)
819 {
820     // Now that our downloadItem has everything we need we can emit downloadRequested.
821     m_viewInterface->downloadRequested(download);
822 }
823
824 void QtWebPageProxy::paintContent(QPainter* painter, const QRect& area)
825 {
826     // FIXME: Do something with the unpainted region?
827     WebCore::Region unpaintedRegion;
828     static_cast<DrawingAreaProxyImpl*>(m_webPageProxy->drawingArea())->paint(painter, area, unpaintedRegion);
829 }
830
831 PassOwnPtr<DrawingAreaProxy> QtWebPageProxy::createDrawingAreaProxy()
832 {
833     return DrawingAreaProxyImpl::create(m_webPageProxy.get());
834 }
835
836 void QtWebPageProxy::renderToCurrentGLContext(const TransformationMatrix& transform, float opacity)
837 {
838     DrawingAreaProxy* drawingArea = m_webPageProxy->drawingArea();
839     if (drawingArea)
840         drawingArea->paintToCurrentGLContext(transform, opacity);
841 }
842
843 #if ENABLE(TOUCH_EVENTS)
844 void QtWebPageProxy::doneWithTouchEvent(const NativeWebTouchEvent& event, bool wasEventHandled)
845 {
846     if (!m_interactionEngine)
847         return;
848
849     if (wasEventHandled || event.type() == WebEvent::TouchCancel) {
850         m_panGestureRecognizer.reset();
851         m_pinchGestureRecognizer.reset();
852         m_tapGestureRecognizer.reset();
853         return;
854     }
855
856     const QTouchEvent* ev = event.nativeEvent();
857
858     switch (ev->type()) {
859     case QEvent::TouchBegin:
860         ASSERT(!m_interactionEngine->panGestureActive());
861         ASSERT(!m_interactionEngine->pinchGestureActive());
862
863         // The interaction engine might still be animating kinetic scrolling or a scale animation
864         // such as double-tap to zoom or the bounce back effect. A touch stops the kinetic scrolling
865         // where as it does not stop the scale animation.
866         if (m_interactionEngine->scrollAnimationActive())
867             m_interactionEngine->interruptScrollAnimation();
868         break;
869     case QEvent::TouchUpdate:
870         // The scale animation can only be interrupted by a pinch gesture, which will then take over.
871         if (m_interactionEngine->scaleAnimationActive() && m_pinchGestureRecognizer.isRecognized())
872             m_interactionEngine->interruptScaleAnimation();
873         break;
874     default:
875         break;
876     }
877
878     // If the scale animation is active we don't pass the event to the recognizers. In the future
879     // we would want to queue the event here and repost then when the animation ends.
880     if (m_interactionEngine->scaleAnimationActive())
881         return;
882
883     // Convert the event timestamp from second to millisecond.
884     qint64 eventTimestampMillis = static_cast<qint64>(event.timestamp() * 1000);
885     m_panGestureRecognizer.recognize(ev, eventTimestampMillis);
886     m_pinchGestureRecognizer.recognize(ev);
887
888     if (m_panGestureRecognizer.isRecognized() || m_pinchGestureRecognizer.isRecognized())
889         m_tapGestureRecognizer.reset();
890     else {
891         const QTouchEvent* ev = event.nativeEvent();
892         m_tapGestureRecognizer.recognize(ev, eventTimestampMillis);
893     }
894 }
895 #endif
896
897 void QtWebPageProxy::setVisibleContentRectAndScale(const QRectF& visibleContentRect, float scale)
898 {
899     QRect alignedVisibleContentRect = visibleContentRect.toAlignedRect();
900     m_webPageProxy->drawingArea()->setVisibleContentsRectAndScale(alignedVisibleContentRect, scale);
901
902     // FIXME: Once we support suspend and resume, this should be delayed until the page is active if the page is suspended.
903     m_webPageProxy->setFixedVisibleContentRect(alignedVisibleContentRect);
904 }
905
906 void QtWebPageProxy::setVisibleContentRectTrajectoryVector(const QPointF& trajectoryVector)
907 {
908     m_webPageProxy->drawingArea()->setVisibleContentRectTrajectoryVector(trajectoryVector);
909 }
910
911 void QtWebPageProxy::touchEvent(QTouchEvent* event)
912 {
913 #if ENABLE(TOUCH_EVENTS)
914     m_webPageProxy->handleTouchEvent(NativeWebTouchEvent(event));
915     event->accept();
916 #else
917     ASSERT_NOT_REACHED();
918     ev->ignore();
919 #endif
920 }
921
922 void QtWebPageProxy::findZoomableAreaForPoint(const QPoint& point)
923 {
924     m_webPageProxy->findZoomableAreaForPoint(point);
925 }
926
927 #include "moc_QtWebPageProxy.cpp"