2cd57bc39fa736690bddc7470006f69dfeeaec5e
[WebKit-https.git] / Source / WebKit2 / UIProcess / API / qt / qquickwebview.cpp
1 /*
2  * Copyright (C) 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 "qquickwebview_p.h"
23
24 #include "DownloadProxy.h"
25 #include "DrawingAreaProxyImpl.h"
26 #include "QtDialogRunner.h"
27 #include "QtDownloadManager.h"
28 #include "QtViewportInteractionEngine.h"
29 #include "QtWebContext.h"
30 #include "QtWebIconDatabaseClient.h"
31 #include "QtWebPageEventHandler.h"
32 #include "QtWebPageLoadClient.h"
33 #include "QtWebPagePolicyClient.h"
34 #include "UtilsQt.h"
35 #include "WebBackForwardList.h"
36 #include "WebPageGroup.h"
37 #include "WebPreferences.h"
38
39 #include "qquicknetworkreply_p.h"
40 #include "qquicknetworkrequest_p.h"
41 #include "qquickwebpage_p_p.h"
42 #include "qquickwebview_p_p.h"
43 #include "qwebdownloaditem_p_p.h"
44 #include "qwebloadrequest_p.h"
45 #include "qwebnavigationhistory_p.h"
46 #include "qwebnavigationhistory_p_p.h"
47 #include "qwebpreferences_p.h"
48 #include "qwebpreferences_p_p.h"
49 #include "qwebviewportinfo_p.h"
50
51 #include <JavaScriptCore/InitializeThreading.h>
52 #include <QDateTime>
53 #include <WebCore/IntPoint.h>
54 #include <WebCore/IntRect.h>
55 #include <WKOpenPanelResultListener.h>
56 #include <wtf/Assertions.h>
57 #include <wtf/MainThread.h>
58 #include <wtf/text/WTFString.h>
59
60 using namespace WebCore;
61 using namespace WebKit;
62
63 static bool s_flickableViewportEnabled = true;
64 static const int kAxisLockSampleCount = 5;
65 static const qreal kAxisLockVelocityThreshold = 300;
66 static const qreal kAxisLockVelocityDirectionThreshold = 50;
67
68 static QQuickWebViewPrivate* createPrivateObject(QQuickWebView* publicObject)
69 {
70     if (s_flickableViewportEnabled)
71         return new QQuickWebViewFlickablePrivate(publicObject);
72     return new QQuickWebViewLegacyPrivate(publicObject);
73 }
74
75 QQuickWebViewPrivate::FlickableAxisLocker::FlickableAxisLocker()
76     : m_allowedDirection(QQuickFlickable::AutoFlickDirection)
77     , m_sampleCount(0)
78 {
79 }
80
81 QVector2D QQuickWebViewPrivate::FlickableAxisLocker::touchVelocity(const QTouchEvent* event)
82 {
83     static bool touchVelocityAvailable = event->device()->capabilities().testFlag(QTouchDevice::Velocity);
84     const QTouchEvent::TouchPoint& touchPoint = event->touchPoints().first();
85
86     if (touchVelocityAvailable)
87         return touchPoint.velocity();
88
89     const QLineF movementLine(touchPoint.screenPos(), m_initialScreenPosition);
90     const qint64 elapsed = m_time.elapsed();
91
92     if (!elapsed)
93         return QVector2D(0, 0);
94
95     // Calculate an approximate velocity vector in the unit of pixel / second.
96     return QVector2D(1000 * movementLine.dx() / elapsed, 1000 * movementLine.dy() / elapsed);
97 }
98
99 void QQuickWebViewPrivate::FlickableAxisLocker::update(const QTouchEvent* event)
100 {
101     ASSERT(event->touchPoints().size() == 1);
102     const QTouchEvent::TouchPoint& touchPoint = event->touchPoints().first();
103
104     ++m_sampleCount;
105
106     if (m_sampleCount == 1) {
107         m_initialScreenPosition = touchPoint.screenPos();
108         m_time.restart();
109         return;
110     }
111
112     if (m_sampleCount > kAxisLockSampleCount
113             || m_allowedDirection == QQuickFlickable::HorizontalFlick
114             || m_allowedDirection == QQuickFlickable::VerticalFlick)
115         return;
116
117     QVector2D velocity = touchVelocity(event);
118
119     qreal directionIndicator = qAbs(velocity.x()) - qAbs(velocity.y());
120
121     if (velocity.length() > kAxisLockVelocityThreshold && qAbs(directionIndicator) > kAxisLockVelocityDirectionThreshold)
122         m_allowedDirection = (directionIndicator > 0) ? QQuickFlickable::HorizontalFlick : QQuickFlickable::VerticalFlick;
123 }
124
125 void QQuickWebViewPrivate::FlickableAxisLocker::setReferencePosition(const QPointF& position)
126 {
127     m_lockReferencePosition = position;
128 }
129
130 void QQuickWebViewPrivate::FlickableAxisLocker::reset()
131 {
132     m_allowedDirection = QQuickFlickable::AutoFlickDirection;
133     m_sampleCount = 0;
134 }
135
136 QPointF QQuickWebViewPrivate::FlickableAxisLocker::adjust(const QPointF& position)
137 {
138     if (m_allowedDirection == QQuickFlickable::HorizontalFlick)
139         return QPointF(position.x(), m_lockReferencePosition.y());
140
141     if (m_allowedDirection == QQuickFlickable::VerticalFlick)
142         return QPointF(m_lockReferencePosition.x(), position.y());
143
144     return position;
145 }
146
147 QQuickWebViewPrivate::QQuickWebViewPrivate(QQuickWebView* viewport)
148     : q_ptr(viewport)
149     , alertDialog(0)
150     , confirmDialog(0)
151     , promptDialog(0)
152     , authenticationDialog(0)
153     , certificateVerificationDialog(0)
154     , itemSelector(0)
155     , proxyAuthenticationDialog(0)
156     , filePicker(0)
157     , databaseQuotaDialog(0)
158     , m_useDefaultContentItemSize(true)
159     , m_navigatorQtObjectEnabled(false)
160     , m_renderToOffscreenBuffer(false)
161     , m_dialogActive(false)
162 {
163     viewport->setClip(true);
164     viewport->setPixelAligned(true);
165     QObject::connect(viewport, SIGNAL(visibleChanged()), viewport, SLOT(_q_onVisibleChanged()));
166     QObject::connect(viewport, SIGNAL(urlChanged()), viewport, SLOT(_q_onUrlChanged()));
167     pageView.reset(new QQuickWebPage(viewport));
168 }
169
170 QQuickWebViewPrivate::~QQuickWebViewPrivate()
171 {
172     webPageProxy->close();
173 }
174
175 // Note: we delay this initialization to make sure that QQuickWebView has its d-ptr in-place.
176 void QQuickWebViewPrivate::initialize(WKContextRef contextRef, WKPageGroupRef pageGroupRef)
177 {
178     RefPtr<WebPageGroup> pageGroup;
179     if (pageGroupRef)
180         pageGroup = toImpl(pageGroupRef);
181     else
182         pageGroup = WebPageGroup::create();
183
184     context = contextRef ? QtWebContext::create(toImpl(contextRef)) : QtWebContext::defaultContext();
185     webPageProxy = context->createWebPage(&pageClient, pageGroup.get());
186
187     QQuickWebPagePrivate* const pageViewPrivate = pageView.data()->d;
188     pageViewPrivate->initialize(webPageProxy.get());
189
190     pageLoadClient.reset(new QtWebPageLoadClient(toAPI(webPageProxy.get()), q_ptr));
191     pagePolicyClient.reset(new QtWebPagePolicyClient(toAPI(webPageProxy.get()), q_ptr));
192     pageUIClient.reset(new QtWebPageUIClient(toAPI(webPageProxy.get()), q_ptr));
193     navigationHistory = adoptPtr(QWebNavigationHistoryPrivate::createHistory(toAPI(webPageProxy.get())));
194
195     QtWebIconDatabaseClient* iconDatabase = context->iconDatabase();
196     QObject::connect(iconDatabase, SIGNAL(iconChangedForPageURL(QUrl, QUrl)), q_ptr, SLOT(_q_onIconChangedForPageURL(QUrl, QUrl)));
197
198     // Any page setting should preferrable be set before creating the page.
199     webPageProxy->pageGroup()->preferences()->setAcceleratedCompositingEnabled(true);
200     webPageProxy->pageGroup()->preferences()->setForceCompositingMode(true);
201     webPageProxy->pageGroup()->preferences()->setFrameFlatteningEnabled(true);
202
203     pageClient.initialize(q_ptr, pageViewPrivate->eventHandler.data(), &undoController);
204     webPageProxy->initializeWebPage();
205 }
206
207 void QQuickWebViewPrivate::setTransparentBackground(bool enable)
208 {
209     webPageProxy->setDrawsTransparentBackground(enable);
210 }
211
212 bool QQuickWebViewPrivate::transparentBackground() const
213 {
214     return webPageProxy->drawsTransparentBackground();
215 }
216
217 QPointF QQuickWebViewPrivate::pageItemPos()
218 {
219     ASSERT(pageView);
220     return pageView->pos();
221 }
222
223 /*!
224     \qmlsignal WebView::loadingChanged(WebLoadRequest request)
225 */
226
227 void QQuickWebViewPrivate::loadDidSucceed()
228 {
229     Q_Q(QQuickWebView);
230     ASSERT(!q->loading());
231     QWebLoadRequest loadRequest(q->url(), QQuickWebView::LoadSucceededStatus);
232     emit q->loadingChanged(&loadRequest);
233 }
234
235 void QQuickWebViewPrivate::onComponentComplete()
236 {
237     if (m_deferedUrlToLoad.isEmpty())
238         return;
239
240     q_ptr->setUrl(m_deferedUrlToLoad);
241 }
242
243 void QQuickWebViewPrivate::setNeedsDisplay()
244 {
245     Q_Q(QQuickWebView);
246     if (renderToOffscreenBuffer()) {
247         // TODO: we can maintain a real image here and use it for pixel tests. Right now this is used only for running the rendering code-path while running tests.
248         QImage dummyImage(1, 1, QImage::Format_ARGB32);
249         QPainter painter(&dummyImage);
250         q->page()->d->paint(&painter);
251         return;
252     }
253
254     q->page()->update();
255 }
256
257 void QQuickWebViewPrivate::_q_onIconChangedForPageURL(const QUrl& pageURL, const QUrl& iconURL)
258 {
259     Q_Q(QQuickWebView);
260     if (q->url() != pageURL)
261         return;
262
263     setIcon(iconURL);
264 }
265
266 void QQuickWebViewPrivate::didChangeBackForwardList()
267 {
268     navigationHistory->d->reset();
269 }
270
271 void QQuickWebViewPrivate::processDidCrash()
272 {
273     pageView->eventHandler()->resetGestureRecognizers();
274     pageLoadClient->completeLoadWhenProcessDidCrashIfNeeded();
275
276     QUrl url(KURL(WebCore::ParsedURLString, webPageProxy->urlAtProcessExit()));
277     qWarning("WARNING: The web process experienced a crash on '%s'.", qPrintable(url.toString(QUrl::RemoveUserInfo)));
278 }
279
280 void QQuickWebViewPrivate::didRelaunchProcess()
281 {
282     qWarning("WARNING: The web process has been successfully restarted.");
283
284     webPageProxy->drawingArea()->setSize(viewSize(), IntSize());
285     updateViewportSize();
286 }
287
288 PassOwnPtr<DrawingAreaProxy> QQuickWebViewPrivate::createDrawingAreaProxy()
289 {
290     return DrawingAreaProxyImpl::create(webPageProxy.get());
291 }
292
293 void QQuickWebViewPrivate::handleDownloadRequest(DownloadProxy* download)
294 {
295     Q_Q(QQuickWebView);
296     // This function is responsible for hooking up a DownloadProxy to our API layer
297     // by creating a QWebDownloadItem. It will then wait for the QWebDownloadItem to be
298     // ready (filled with the ResourceResponse information) so we can pass it through to
299     // our WebViews.
300     QWebDownloadItem* downloadItem = new QWebDownloadItem();
301     downloadItem->d->downloadProxy = download;
302
303     q->connect(downloadItem->d, SIGNAL(receivedResponse(QWebDownloadItem*)), q, SLOT(_q_onReceivedResponseFromDownload(QWebDownloadItem*)));
304     context->downloadManager()->addDownload(download, downloadItem);
305 }
306
307 void QQuickWebViewPrivate::_q_onVisibleChanged()
308 {
309     webPageProxy->viewStateDidChange(WebPageProxy::ViewIsVisible);
310 }
311
312 void QQuickWebViewPrivate::_q_onUrlChanged()
313 {
314     Q_Q(QQuickWebView);
315     context->iconDatabase()->requestIconForPageURL(q->url());
316 }
317
318 void QQuickWebViewPrivate::_q_onReceivedResponseFromDownload(QWebDownloadItem* downloadItem)
319 {
320     // Now that our downloadItem has everything we need we can emit downloadRequested.
321     if (!downloadItem)
322         return;
323
324     Q_Q(QQuickWebView);
325     QDeclarativeEngine::setObjectOwnership(downloadItem, QDeclarativeEngine::JavaScriptOwnership);
326     emit q->experimental()->downloadRequested(downloadItem);
327 }
328
329 void QQuickWebViewPrivate::runJavaScriptAlert(const QString& alertText)
330 {
331     if (!alertDialog)
332         return;
333
334     Q_Q(QQuickWebView);
335     QtDialogRunner dialogRunner;
336     if (!dialogRunner.initForAlert(alertDialog, q, alertText))
337         return;
338
339     execDialogRunner(dialogRunner);
340 }
341
342 bool QQuickWebViewPrivate::runJavaScriptConfirm(const QString& message)
343 {
344     if (!confirmDialog)
345         return true;
346
347     Q_Q(QQuickWebView);
348     QtDialogRunner dialogRunner;
349     if (!dialogRunner.initForConfirm(confirmDialog, q, message))
350         return true;
351
352     execDialogRunner(dialogRunner);
353
354     return dialogRunner.wasAccepted();
355 }
356
357 QString QQuickWebViewPrivate::runJavaScriptPrompt(const QString& message, const QString& defaultValue, bool& ok)
358 {
359     if (!promptDialog) {
360         ok = true;
361         return defaultValue;
362     }
363
364     Q_Q(QQuickWebView);
365     QtDialogRunner dialogRunner;
366     if (!dialogRunner.initForPrompt(promptDialog, q, message, defaultValue)) {
367         ok = true;
368         return defaultValue;
369     }
370
371     execDialogRunner(dialogRunner);
372
373     ok = dialogRunner.wasAccepted();
374     return dialogRunner.result();
375 }
376
377 void QQuickWebViewPrivate::handleAuthenticationRequiredRequest(const QString& hostname, const QString& realm, const QString& prefilledUsername, QString& username, QString& password)
378 {
379     if (!authenticationDialog)
380         return;
381
382     Q_Q(QQuickWebView);
383     QtDialogRunner dialogRunner;
384     if (!dialogRunner.initForAuthentication(authenticationDialog, q, hostname, realm, prefilledUsername))
385         return;
386
387     execDialogRunner(dialogRunner);
388
389     username = dialogRunner.username();
390     password = dialogRunner.password();
391 }
392
393 void QQuickWebViewPrivate::handleProxyAuthenticationRequiredRequest(const QString& hostname, uint16_t port, const QString& prefilledUsername, QString& username, QString& password)
394 {
395     if (!proxyAuthenticationDialog)
396         return;
397
398     Q_Q(QQuickWebView);
399     QtDialogRunner dialogRunner;
400     if (!dialogRunner.initForProxyAuthentication(proxyAuthenticationDialog, q, hostname, port, prefilledUsername))
401         return;
402
403     execDialogRunner(dialogRunner);
404
405     username = dialogRunner.username();
406     password = dialogRunner.password();
407 }
408
409 bool QQuickWebViewPrivate::handleCertificateVerificationRequest(const QString& hostname)
410 {
411     if (!certificateVerificationDialog)
412         return false;
413
414     Q_Q(QQuickWebView);
415     QtDialogRunner dialogRunner;
416     if (!dialogRunner.initForCertificateVerification(certificateVerificationDialog, q, hostname))
417         return false;
418
419     execDialogRunner(dialogRunner);
420
421     return dialogRunner.wasAccepted();
422 }
423
424 void QQuickWebViewPrivate::execDialogRunner(QtDialogRunner& dialogRunner)
425 {
426     setViewInAttachedProperties(dialogRunner.dialog());
427
428     disableMouseEvents();
429     m_dialogActive = true;
430
431     dialogRunner.exec();
432     m_dialogActive = false;
433     enableMouseEvents();
434 }
435
436 void QQuickWebViewPrivate::chooseFiles(WKOpenPanelResultListenerRef listenerRef, const QStringList& selectedFileNames, QtWebPageUIClient::FileChooserType type)
437 {
438     Q_Q(QQuickWebView);
439
440     if (!filePicker)
441         return;
442
443     QtDialogRunner dialogRunner;
444     if (!dialogRunner.initForFilePicker(filePicker, q, selectedFileNames, (type == QtWebPageUIClient::MultipleFilesSelection)))
445         return;
446
447     execDialogRunner(dialogRunner);
448
449     if (dialogRunner.wasAccepted()) {
450         QStringList selectedPaths = dialogRunner.filePaths();
451
452         Vector<RefPtr<APIObject> > wkFiles(selectedPaths.size());
453         for (unsigned i = 0; i < selectedPaths.size(); ++i)
454             wkFiles[i] = WebURL::create(QUrl::fromLocalFile(selectedPaths.at(i)).toString());            
455
456         WKOpenPanelResultListenerChooseFiles(listenerRef, toAPI(ImmutableArray::adopt(wkFiles).leakRef()));
457     } else
458         WKOpenPanelResultListenerCancel(listenerRef);
459
460 }
461
462 quint64 QQuickWebViewPrivate::exceededDatabaseQuota(const QString& databaseName, const QString& displayName, WKSecurityOriginRef securityOrigin, quint64 currentQuota, quint64 currentOriginUsage, quint64 currentDatabaseUsage, quint64 expectedUsage)
463 {
464     if (!databaseQuotaDialog)
465         return 0;
466
467     Q_Q(QQuickWebView);
468     QtDialogRunner dialogRunner;
469     if (!dialogRunner.initForDatabaseQuotaDialog(databaseQuotaDialog, q, databaseName, displayName, securityOrigin, currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage))
470         return 0;
471
472     execDialogRunner(dialogRunner);
473
474     return dialogRunner.wasAccepted() ? dialogRunner.databaseQuota() : 0;
475 }
476
477 void QQuickWebViewPrivate::setViewInAttachedProperties(QObject* object)
478 {
479     Q_Q(QQuickWebView);
480     QQuickWebViewAttached* attached = static_cast<QQuickWebViewAttached*>(qmlAttachedPropertiesObject<QQuickWebView>(object));
481     attached->setView(q);
482 }
483
484 void QQuickWebViewPrivate::setIcon(const QUrl& iconURL)
485 {
486     Q_Q(QQuickWebView);
487     if (m_iconURL == iconURL)
488         return;
489
490     String oldPageURL = QUrl::fromPercentEncoding(m_iconURL.encodedFragment());
491     String newPageURL = webPageProxy->mainFrame()->url();
492
493     if (oldPageURL != newPageURL) {
494         QtWebIconDatabaseClient* iconDatabase = context->iconDatabase();
495         if (!oldPageURL.isEmpty())
496             iconDatabase->releaseIconForPageURL(oldPageURL);
497
498         if (!newPageURL.isEmpty())
499             iconDatabase->retainIconForPageURL(newPageURL);
500     }
501
502     m_iconURL = iconURL;
503     emit q->iconChanged();
504 }
505
506 bool QQuickWebViewPrivate::navigatorQtObjectEnabled() const
507 {
508     return m_navigatorQtObjectEnabled;
509 }
510
511 void QQuickWebViewPrivate::setNavigatorQtObjectEnabled(bool enabled)
512 {
513     ASSERT(enabled != m_navigatorQtObjectEnabled);
514     // FIXME: Currently we have to keep this information in both processes and the setting is asynchronous.
515     m_navigatorQtObjectEnabled = enabled;
516     context->setNavigatorQtObjectEnabled(webPageProxy.get(), enabled);
517 }
518
519 QPointF QQuickWebViewPrivate::contentPos() const
520 {
521     Q_Q(const QQuickWebView);
522     return QPointF(q->contentX(), q->contentY());
523 }
524
525 void QQuickWebViewPrivate::setContentPos(const QPointF& pos)
526 {
527     Q_Q(QQuickWebView);
528     q->setContentX(pos.x());
529     q->setContentY(pos.y());
530 }
531
532 QRect QQuickWebViewPrivate::visibleContentsRect() const
533 {
534     Q_Q(const QQuickWebView);
535     const QRectF visibleRect(q->boundingRect().intersected(pageView->boundingRect()));
536
537     // We avoid using toAlignedRect() because it produces inconsistent width and height.
538     QRectF mappedRect(q->mapRectToWebContent(visibleRect));
539     return QRect(floor(mappedRect.x()), floor(mappedRect.y()), floor(mappedRect.width()), floor(mappedRect.height()));
540 }
541
542 WebCore::IntSize QQuickWebViewPrivate::viewSize() const
543 {
544     return WebCore::IntSize(pageView->width(), pageView->height());
545 }
546
547 /*!
548     \internal
549
550     \qmlsignal WebViewExperimental::onMessageReceived(var message)
551
552     \brief Emitted when JavaScript code executing on the web page calls navigator.qt.postMessage().
553
554     \sa postMessage
555 */
556 void QQuickWebViewPrivate::didReceiveMessageFromNavigatorQtObject(const String& message)
557 {
558     QVariantMap variantMap;
559     variantMap.insert(QLatin1String("data"), QString(message));
560     variantMap.insert(QLatin1String("origin"), q_ptr->url());
561     emit q_ptr->experimental()->messageReceived(variantMap);
562 }
563
564 QQuickWebViewLegacyPrivate::QQuickWebViewLegacyPrivate(QQuickWebView* viewport)
565     : QQuickWebViewPrivate(viewport)
566 {
567     // Default values for the Legacy view.
568     attributes.devicePixelRatio = 1;
569     attributes.initialScale = 1;
570     attributes.minimumScale = 1;
571     attributes.maximumScale = 1;
572     attributes.userScalable = 0;
573 }
574
575 void QQuickWebViewLegacyPrivate::initialize(WKContextRef contextRef, WKPageGroupRef pageGroupRef)
576 {
577     QQuickWebViewPrivate::initialize(contextRef, pageGroupRef);
578     enableMouseEvents();
579
580     // Trigger setting of correct visibility flags after everything was allocated and initialized.
581     _q_onVisibleChanged();
582 }
583
584 void QQuickWebViewLegacyPrivate::updateViewportSize()
585 {
586     Q_Q(QQuickWebView);
587     QSize viewportSize = q->boundingRect().size().toSize();
588     pageView->setContentsSize(viewportSize);
589     // The fixed layout is handled by the FrameView and the drawing area doesn't behave differently
590     // whether its fixed or not. We still need to tell the drawing area which part of it
591     // has to be rendered on tiles, and in desktop mode it's all of it.
592     webPageProxy->drawingArea()->setSize(viewportSize, IntSize());
593     webPageProxy->drawingArea()->setVisibleContentsRect(IntRect(IntPoint(), viewportSize), 1, FloatPoint());
594 }
595
596 void QQuickWebViewLegacyPrivate::enableMouseEvents()
597 {
598     Q_Q(QQuickWebView);
599     q->setAcceptedMouseButtons(Qt::MouseButtonMask);
600     q->setAcceptHoverEvents(true);
601 }
602
603 void QQuickWebViewLegacyPrivate::disableMouseEvents()
604 {
605     Q_Q(QQuickWebView);
606     q->setAcceptedMouseButtons(Qt::NoButton);
607     q->setAcceptHoverEvents(false);
608 }
609
610 qreal QQuickWebViewLegacyPrivate::zoomFactor() const
611 {
612     return webPageProxy->pageZoomFactor();
613 }
614
615 void QQuickWebViewLegacyPrivate::setZoomFactor(qreal factor)
616 {
617     webPageProxy->setPageZoomFactor(factor);
618 }
619
620 QQuickWebViewFlickablePrivate::QQuickWebViewFlickablePrivate(QQuickWebView* viewport)
621     : QQuickWebViewPrivate(viewport)
622     , pageIsSuspended(true)
623     , loadSuccessDispatchIsPending(false)
624 {
625     // Disable mouse events on the flickable web view so we do not
626     // select text during pan gestures on platforms which send both
627     // touch and mouse events simultaneously.
628     // FIXME: Temporary workaround code which should be removed when
629     // bug http://codereview.qt-project.org/21896 is fixed.
630     viewport->setAcceptedMouseButtons(Qt::NoButton);
631     viewport->setAcceptHoverEvents(false);
632 }
633
634 QQuickWebViewFlickablePrivate::~QQuickWebViewFlickablePrivate()
635 {
636     interactionEngine->disconnect();
637 }
638
639 void QQuickWebViewFlickablePrivate::initialize(WKContextRef contextRef, WKPageGroupRef pageGroupRef)
640 {
641     QQuickWebViewPrivate::initialize(contextRef, pageGroupRef);
642     webPageProxy->setUseFixedLayout(true);
643 }
644
645 QPointF QQuickWebViewFlickablePrivate::pageItemPos()
646 {
647     Q_Q(QQuickWebView);
648     // Flickable moves its contentItem so we need to take that position into account,
649     // as well as the potential displacement of the page on the contentItem because
650     // of additional QML items.
651     qreal xPos = q->contentItem()->x() + pageView->x();
652     qreal yPos = q->contentItem()->y() + pageView->y();
653     return QPointF(xPos, yPos);
654 }
655
656 void QQuickWebViewFlickablePrivate::updateContentsSize(const QSizeF& size)
657 {
658     Q_Q(QQuickWebView);
659
660     // Make sure that the contentItem is sized to the page
661     // if the user did not add other flickable items in QML.
662     // If the user adds items in QML he has to make sure to
663     // disable the default content item size property on the WebView
664     // and bind the contentWidth and contentHeight accordingly.
665     // This is in accordance with normal QML Flickable behaviour.
666     if (!m_useDefaultContentItemSize)
667         return;
668
669     q->setContentWidth(size.width());
670     q->setContentHeight(size.height());
671 }
672
673 void QQuickWebViewFlickablePrivate::onComponentComplete()
674 {
675     Q_Q(QQuickWebView);
676
677     interactionEngine.reset(new QtViewportInteractionEngine(q, pageView.data()));
678     pageView->eventHandler()->setViewportInteractionEngine(interactionEngine.data());
679
680     QObject::connect(interactionEngine.data(), SIGNAL(contentSuspendRequested()), q, SLOT(_q_suspend()));
681     QObject::connect(interactionEngine.data(), SIGNAL(contentResumeRequested()), q, SLOT(_q_resume()));
682     QObject::connect(interactionEngine.data(), SIGNAL(contentViewportChanged(QPointF)), q, SLOT(_q_contentViewportChanged(QPointF)));
683
684     _q_resume();
685
686     if (loadSuccessDispatchIsPending) {
687         QQuickWebViewPrivate::loadDidSucceed();
688         loadSuccessDispatchIsPending = false;
689     }
690
691     // Trigger setting of correct visibility flags after everything was allocated and initialized.
692     _q_onVisibleChanged();
693
694     QQuickWebViewPrivate::onComponentComplete();
695 }
696
697 void QQuickWebViewFlickablePrivate::loadDidSucceed()
698 {
699     if (interactionEngine)
700         QQuickWebViewPrivate::loadDidSucceed();
701     else
702         loadSuccessDispatchIsPending = true;
703 }
704
705 void QQuickWebViewFlickablePrivate::loadDidCommit()
706 {
707     // Due to entering provisional load before committing, we
708     // might actually be suspended here.
709 }
710
711 void QQuickWebViewFlickablePrivate::didFinishFirstNonEmptyLayout()
712 {
713 }
714
715 void QQuickWebViewFlickablePrivate::didChangeViewportProperties(const WebCore::ViewportAttributes& newAttributes)
716 {
717     Q_Q(QQuickWebView);
718
719     QSize viewportSize = q->boundingRect().size().toSize();
720
721     // FIXME: Revise these when implementing fit-to-width.
722     WebCore::ViewportAttributes attr = newAttributes;
723     WebCore::restrictMinimumScaleFactorToViewportSize(attr, viewportSize);
724     WebCore::restrictScaleFactorToInitialScaleIfNotUserScalable(attr);
725
726     // FIXME: Resetting here can reset more than needed. For instance it will end deferrers.
727     // This needs to be revised at some point.
728     interactionEngine->reset();
729
730     interactionEngine->setContentToDevicePixelRatio(attr.devicePixelRatio);
731
732     interactionEngine->setAllowsUserScaling(!!attr.userScalable);
733     interactionEngine->setCSSScaleBounds(attr.minimumScale, attr.maximumScale);
734
735     if (!interactionEngine->hadUserInteraction() && !pageIsSuspended)
736         interactionEngine->setCSSScale(attr.initialScale);
737
738     this->attributes = attr;
739     q->experimental()->viewportInfo()->didUpdateViewportConstraints();
740
741     // If the web app successively changes the viewport on purpose
742     // it wants to be in control and we should disable animations.
743     interactionEngine->ensureContentWithinViewportBoundary(/*immediate*/ true);
744 }
745
746 void QQuickWebViewFlickablePrivate::updateViewportSize()
747 {
748     Q_Q(QQuickWebView);
749     QSize viewportSize = q->boundingRect().size().toSize();
750
751     if (viewportSize.isEmpty() || !interactionEngine)
752         return;
753
754     WebPreferences* wkPrefs = webPageProxy->pageGroup()->preferences();
755
756     // FIXME: Remove later; Hardcode a value for now to make sure the DPI adjustment is being tested.
757     wkPrefs->setDeviceDPI(160);
758
759     wkPrefs->setDeviceWidth(viewportSize.width());
760     wkPrefs->setDeviceHeight(viewportSize.height());
761
762     // Let the WebProcess know about the new viewport size, so that
763     // it can resize the content accordingly.
764     webPageProxy->setViewportSize(viewportSize);
765
766     _q_contentViewportChanged(QPointF());
767 }
768
769 void QQuickWebViewFlickablePrivate::_q_contentViewportChanged(const QPointF& trajectoryVector)
770 {
771     Q_Q(QQuickWebView);
772     // This is only for our QML ViewportInfo debugging API.
773     q->experimental()->viewportInfo()->didUpdateCurrentScale();
774
775     DrawingAreaProxy* drawingArea = webPageProxy->drawingArea();
776     if (!drawingArea)
777         return;
778
779     const QRect visibleRect(visibleContentsRect());
780     float scale = pageView->contentsScale();
781
782     QRectF accurateVisibleRect(q->boundingRect());
783     accurateVisibleRect.translate(contentPos());
784     drawingArea->setVisibleContentsRect(visibleRect, scale, trajectoryVector, FloatPoint(accurateVisibleRect.x(), accurateVisibleRect.y()));
785
786     // Ensure that updatePaintNode is always called before painting.
787     pageView->update();
788 }
789
790 void QQuickWebViewFlickablePrivate::_q_suspend()
791 {
792     pageIsSuspended = true;
793     webPageProxy->suspendActiveDOMObjectsAndAnimations();
794 }
795
796 void QQuickWebViewFlickablePrivate::_q_resume()
797 {
798     if (!interactionEngine)
799         return;
800
801     pageIsSuspended = false;
802     webPageProxy->resumeActiveDOMObjectsAndAnimations();
803
804     _q_contentViewportChanged(QPointF());
805 }
806
807 void QQuickWebViewFlickablePrivate::pageDidRequestScroll(const QPoint& pos)
808 {
809     interactionEngine->pagePositionRequest(pos);
810 }
811
812 void QQuickWebViewFlickablePrivate::didChangeContentsSize(const QSize& newSize)
813 {
814     Q_Q(QQuickWebView);
815     pageView->setContentsSize(newSize);
816     q->experimental()->viewportInfo()->didUpdateContentsSize();
817 }
818
819 /*!
820     \qmlsignal WebView::onNavigationRequested(WebNavigationRequest request)
821
822     This signal is emitted for every navigation request. The request object contains url,
823     button and modifiers properties describing the navigation action, e.g. "a middle click
824     with shift key pressed to 'http://qt-project.org'".
825
826     The navigation will be accepted by default. To change that, one can set the action
827     property to WebView.IgnoreRequest to reject the request or WebView.DownloadRequest to
828     trigger a download instead of navigating to the url.
829
830     The request object cannot be used after the signal handler function ends.
831
832     \sa WebNavigationRequest
833 */
834
835 QQuickWebViewAttached::QQuickWebViewAttached(QObject* object)
836     : QObject(object)
837     , m_view(0)
838 {
839
840 }
841
842 void QQuickWebViewAttached::setView(QQuickWebView* view)
843 {
844     if (m_view == view)
845         return;
846     m_view = view;
847     emit viewChanged();
848 }
849
850 QQuickWebViewExperimental::QQuickWebViewExperimental(QQuickWebView *webView)
851     : QObject(webView)
852     , q_ptr(webView)
853     , d_ptr(webView->d_ptr.data())
854     , schemeParent(new QObject(this))
855     , m_viewportInfo(new QWebViewportInfo(webView->d_ptr.data(), this))
856 {
857 }
858
859 QQuickWebViewExperimental::~QQuickWebViewExperimental()
860 {
861 }
862
863 void QQuickWebViewExperimental::setRenderToOffscreenBuffer(bool enable)
864 {
865     Q_D(QQuickWebView);
866     d->setRenderToOffscreenBuffer(enable);
867 }
868
869 bool QQuickWebViewExperimental::renderToOffscreenBuffer() const
870 {
871     Q_D(const QQuickWebView);
872     return d->renderToOffscreenBuffer();
873 }
874
875 bool QQuickWebViewExperimental::transparentBackground() const
876 {
877     Q_D(const QQuickWebView);
878     return d->transparentBackground();
879 }
880 void QQuickWebViewExperimental::setTransparentBackground(bool enable)
881 {
882     Q_D(QQuickWebView);
883     d->setTransparentBackground(enable);
884 }
885
886 bool QQuickWebViewExperimental::useDefaultContentItemSize() const
887 {
888     Q_D(const QQuickWebView);
889     return d->m_useDefaultContentItemSize;
890 }
891
892 void QQuickWebViewExperimental::setUseDefaultContentItemSize(bool enable)
893 {
894     Q_D(QQuickWebView);
895     d->m_useDefaultContentItemSize = enable;
896 }
897
898 /*!
899     \internal
900
901     \qmlproperty int WebViewExperimental::preferredMinimumContentsWidth
902     \brief Minimum contents width when not overriden by the page itself.
903
904     Unless the page defines how contents should be laid out, using e.g.
905     the viewport meta tag, it is laid out given the width of the viewport
906     (in CSS units).
907
908     This setting can be used to enforce a minimum width when the page
909     does not define a width itself. This is useful for laying out pages
910     designed for big screens, commonly knows as desktop pages, on small
911     devices.
912
913     The default value is 0, but the value of 980 is recommented for small
914     screens as it provides a good trade off between legitable pages and
915     non-broken content.
916  */
917 int QQuickWebViewExperimental::preferredMinimumContentsWidth() const
918 {
919     Q_D(const QQuickWebView);
920     return d->webPageProxy->pageGroup()->preferences()->layoutFallbackWidth();
921 }
922
923 void QQuickWebViewExperimental::setPreferredMinimumContentsWidth(int width)
924 {
925     Q_D(QQuickWebView);
926     d->webPageProxy->pageGroup()->preferences()->setLayoutFallbackWidth(width);
927 }
928
929 void QQuickWebViewExperimental::setFlickableViewportEnabled(bool enable)
930 {
931     s_flickableViewportEnabled = enable;
932 }
933
934 bool QQuickWebViewExperimental::flickableViewportEnabled()
935 {
936     return s_flickableViewportEnabled;
937 }
938
939 /*!
940     \internal
941
942     \qmlmethod void WebViewExperimental::postMessage(string message)
943
944     \brief Post a message to an onmessage function registered with the navigator.qt object
945            by JavaScript code executing on the page.
946
947     \sa onMessageReceived
948 */
949
950 void QQuickWebViewExperimental::postMessage(const QString& message)
951 {
952     Q_D(QQuickWebView);
953     d->context->postMessageToNavigatorQtObject(d->webPageProxy.get(), message);
954 }
955
956 QDeclarativeComponent* QQuickWebViewExperimental::alertDialog() const
957 {
958     Q_D(const QQuickWebView);
959     return d->alertDialog;
960 }
961
962 void QQuickWebViewExperimental::setAlertDialog(QDeclarativeComponent* alertDialog)
963 {
964     Q_D(QQuickWebView);
965     if (d->alertDialog == alertDialog)
966         return;
967     d->alertDialog = alertDialog;
968     emit alertDialogChanged();
969 }
970
971 QDeclarativeComponent* QQuickWebViewExperimental::confirmDialog() const
972 {
973     Q_D(const QQuickWebView);
974     return d->confirmDialog;
975 }
976
977 void QQuickWebViewExperimental::setConfirmDialog(QDeclarativeComponent* confirmDialog)
978 {
979     Q_D(QQuickWebView);
980     if (d->confirmDialog == confirmDialog)
981         return;
982     d->confirmDialog = confirmDialog;
983     emit confirmDialogChanged();
984 }
985
986 QWebNavigationHistory* QQuickWebViewExperimental::navigationHistory() const
987 {
988     return d_ptr->navigationHistory.get();
989 }
990
991 QDeclarativeComponent* QQuickWebViewExperimental::promptDialog() const
992 {
993     Q_D(const QQuickWebView);
994     return d->promptDialog;
995 }
996
997 QWebPreferences* QQuickWebViewExperimental::preferences() const
998 {
999     QQuickWebViewPrivate* const d = d_ptr;
1000     if (!d->preferences)
1001         d->preferences = adoptPtr(QWebPreferencesPrivate::createPreferences(d));
1002     return d->preferences.get();
1003 }
1004
1005 void QQuickWebViewExperimental::setPromptDialog(QDeclarativeComponent* promptDialog)
1006 {
1007     Q_D(QQuickWebView);
1008     if (d->promptDialog == promptDialog)
1009         return;
1010     d->promptDialog = promptDialog;
1011     emit promptDialogChanged();
1012 }
1013
1014 QDeclarativeComponent* QQuickWebViewExperimental::authenticationDialog() const
1015 {
1016     Q_D(const QQuickWebView);
1017     return d->authenticationDialog;
1018 }
1019
1020 void QQuickWebViewExperimental::setAuthenticationDialog(QDeclarativeComponent* authenticationDialog)
1021 {
1022     Q_D(QQuickWebView);
1023     if (d->authenticationDialog == authenticationDialog)
1024         return;
1025     d->authenticationDialog = authenticationDialog;
1026     emit authenticationDialogChanged();
1027 }
1028
1029 QDeclarativeComponent* QQuickWebViewExperimental::proxyAuthenticationDialog() const
1030 {
1031     Q_D(const QQuickWebView);
1032     return d->proxyAuthenticationDialog;
1033 }
1034
1035 void QQuickWebViewExperimental::setProxyAuthenticationDialog(QDeclarativeComponent* proxyAuthenticationDialog)
1036 {
1037     Q_D(QQuickWebView);
1038     if (d->proxyAuthenticationDialog == proxyAuthenticationDialog)
1039         return;
1040     d->proxyAuthenticationDialog = proxyAuthenticationDialog;
1041     emit proxyAuthenticationDialogChanged();
1042 }
1043 QDeclarativeComponent* QQuickWebViewExperimental::certificateVerificationDialog() const
1044 {
1045     Q_D(const QQuickWebView);
1046     return d->certificateVerificationDialog;
1047 }
1048
1049 void QQuickWebViewExperimental::setCertificateVerificationDialog(QDeclarativeComponent* certificateVerificationDialog)
1050 {
1051     Q_D(QQuickWebView);
1052     if (d->certificateVerificationDialog == certificateVerificationDialog)
1053         return;
1054     d->certificateVerificationDialog = certificateVerificationDialog;
1055     emit certificateVerificationDialogChanged();
1056 }
1057
1058 QDeclarativeComponent* QQuickWebViewExperimental::itemSelector() const
1059 {
1060     Q_D(const QQuickWebView);
1061     return d->itemSelector;
1062 }
1063
1064 void QQuickWebViewExperimental::setItemSelector(QDeclarativeComponent* itemSelector)
1065 {
1066     Q_D(QQuickWebView);
1067     if (d->itemSelector == itemSelector)
1068         return;
1069     d->itemSelector = itemSelector;
1070     emit itemSelectorChanged();
1071 }
1072
1073 QDeclarativeComponent* QQuickWebViewExperimental::filePicker() const
1074 {
1075     Q_D(const QQuickWebView);
1076     return d->filePicker;
1077 }
1078
1079 void QQuickWebViewExperimental::setFilePicker(QDeclarativeComponent* filePicker)
1080 {
1081     Q_D(QQuickWebView);
1082     if (d->filePicker == filePicker)
1083         return;
1084     d->filePicker = filePicker;
1085     emit filePickerChanged();
1086 }
1087
1088 QDeclarativeComponent* QQuickWebViewExperimental::databaseQuotaDialog() const
1089 {
1090     Q_D(const QQuickWebView);
1091     return d->databaseQuotaDialog;
1092 }
1093
1094 void QQuickWebViewExperimental::setDatabaseQuotaDialog(QDeclarativeComponent* databaseQuotaDialog)
1095 {
1096     Q_D(QQuickWebView);
1097     if (d->databaseQuotaDialog == databaseQuotaDialog)
1098         return;
1099     d->databaseQuotaDialog = databaseQuotaDialog;
1100     emit databaseQuotaDialogChanged();
1101 }
1102
1103 QString QQuickWebViewExperimental::userAgent() const
1104 {
1105     Q_D(const QQuickWebView);
1106     return d->webPageProxy->userAgent();
1107 }
1108
1109 void QQuickWebViewExperimental::setUserAgent(const QString& userAgent)
1110 {
1111     Q_D(QQuickWebView);
1112     if (userAgent == QString(d->webPageProxy->userAgent()))
1113         return;
1114
1115     d->webPageProxy->setUserAgent(userAgent);
1116     emit userAgentChanged();
1117 }
1118
1119 QQuickUrlSchemeDelegate* QQuickWebViewExperimental::schemeDelegates_At(QDeclarativeListProperty<QQuickUrlSchemeDelegate>* property, int index)
1120 {
1121     const QObjectList children = property->object->children();
1122     if (index < children.count())
1123         return static_cast<QQuickUrlSchemeDelegate*>(children.at(index));
1124     return 0;
1125 }
1126
1127 void QQuickWebViewExperimental::schemeDelegates_Append(QDeclarativeListProperty<QQuickUrlSchemeDelegate>* property, QQuickUrlSchemeDelegate *scheme)
1128 {
1129     QObject* schemeParent = property->object;
1130     scheme->setParent(schemeParent);
1131     QQuickWebViewExperimental* webViewExperimental = qobject_cast<QQuickWebViewExperimental*>(property->object->parent());
1132     if (!webViewExperimental)
1133         return;
1134     scheme->reply()->setWebViewExperimental(webViewExperimental);
1135     QQuickWebViewPrivate* d = webViewExperimental->d_func();
1136     d->webPageProxy->registerApplicationScheme(scheme->scheme());
1137 }
1138
1139 int QQuickWebViewExperimental::schemeDelegates_Count(QDeclarativeListProperty<QQuickUrlSchemeDelegate>* property)
1140 {
1141     return property->object->children().count();
1142 }
1143
1144 void QQuickWebViewExperimental::schemeDelegates_Clear(QDeclarativeListProperty<QQuickUrlSchemeDelegate>* property)
1145 {
1146     const QObjectList children = property->object->children();
1147     for (int index = 0; index < children.count(); index++) {
1148         QObject* child = children.at(index);
1149         child->setParent(0);
1150         delete child;
1151     }
1152 }
1153
1154 QDeclarativeListProperty<QQuickUrlSchemeDelegate> QQuickWebViewExperimental::schemeDelegates()
1155 {
1156     return QDeclarativeListProperty<QQuickUrlSchemeDelegate>(schemeParent, 0,
1157             QQuickWebViewExperimental::schemeDelegates_Append,
1158             QQuickWebViewExperimental::schemeDelegates_Count,
1159             QQuickWebViewExperimental::schemeDelegates_At,
1160             QQuickWebViewExperimental::schemeDelegates_Clear);
1161 }
1162
1163 void QQuickWebViewExperimental::invokeApplicationSchemeHandler(PassRefPtr<QtRefCountedNetworkRequestData> request)
1164 {
1165     RefPtr<QtRefCountedNetworkRequestData> req = request;
1166     const QObjectList children = schemeParent->children();
1167     for (int index = 0; index < children.count(); index++) {
1168         QQuickUrlSchemeDelegate* delegate = qobject_cast<QQuickUrlSchemeDelegate*>(children.at(index));
1169         if (!delegate)
1170             continue;
1171         if (!delegate->scheme().compare(QString(req->data().m_scheme), Qt::CaseInsensitive)) {
1172             delegate->request()->setNetworkRequestData(req);
1173             delegate->reply()->setNetworkRequestData(req);
1174             emit delegate->receivedRequest();
1175             return;
1176         }
1177     }
1178 }
1179
1180 void QQuickWebViewExperimental::sendApplicationSchemeReply(QQuickNetworkReply* reply)
1181 {
1182     d_ptr->webPageProxy->sendApplicationSchemeReply(reply);
1183 }
1184
1185 void QQuickWebViewExperimental::goForwardTo(int index)
1186 {
1187     d_ptr->navigationHistory->d->goForwardTo(index);
1188 }
1189
1190 void QQuickWebViewExperimental::goBackTo(int index)
1191 {
1192     d_ptr->navigationHistory->d->goBackTo(index);
1193 }
1194
1195 QWebViewportInfo* QQuickWebViewExperimental::viewportInfo()
1196 {
1197     return m_viewportInfo;
1198 }
1199
1200 QQuickWebPage* QQuickWebViewExperimental::page()
1201 {
1202     return q_ptr->page();
1203 }
1204
1205 /*!
1206     \qmlclass WebView QWebView
1207     \inqmlmodule QtWebKit 3.0
1208 */
1209
1210 /*!
1211    \qmlmethod WebView(Item parent)
1212    \brief Constructs a WebView with a parent.
1213 */
1214
1215 QQuickWebView::QQuickWebView(QQuickItem* parent)
1216     : QQuickFlickable(parent)
1217     , d_ptr(createPrivateObject(this))
1218     , m_experimental(new QQuickWebViewExperimental(this))
1219 {
1220     Q_D(QQuickWebView);
1221     d->initialize();
1222 }
1223
1224 QQuickWebView::QQuickWebView(WKContextRef contextRef, WKPageGroupRef pageGroupRef, QQuickItem* parent)
1225     : QQuickFlickable(parent)
1226     , d_ptr(createPrivateObject(this))
1227     , m_experimental(new QQuickWebViewExperimental(this))
1228 {
1229     Q_D(QQuickWebView);
1230     d->initialize(contextRef, pageGroupRef);
1231 }
1232
1233 QQuickWebView::~QQuickWebView()
1234 {
1235 }
1236
1237 QQuickWebPage* QQuickWebView::page()
1238 {
1239     Q_D(QQuickWebView);
1240     return d->pageView.data();
1241 }
1242
1243 void QQuickWebView::goBack()
1244 {
1245     Q_D(QQuickWebView);
1246     d->webPageProxy->goBack();
1247 }
1248
1249 void QQuickWebView::goForward()
1250 {
1251     Q_D(QQuickWebView);
1252     d->webPageProxy->goForward();
1253 }
1254
1255 void QQuickWebView::stop()
1256 {
1257     Q_D(QQuickWebView);
1258     d->webPageProxy->stopLoading();
1259 }
1260
1261 void QQuickWebView::reload()
1262 {
1263     Q_D(QQuickWebView);
1264     const bool reloadFromOrigin = true;
1265     d->webPageProxy->reload(reloadFromOrigin);
1266 }
1267
1268 QUrl QQuickWebView::url() const
1269 {
1270     Q_D(const QQuickWebView);
1271     RefPtr<WebFrameProxy> mainFrame = d->webPageProxy->mainFrame();
1272     if (!mainFrame)
1273         return QUrl();
1274     return QUrl(QString(mainFrame->url()));
1275 }
1276
1277 void QQuickWebView::setUrl(const QUrl& url)
1278 {
1279     Q_D(QQuickWebView);
1280
1281     if (url.isEmpty())
1282         return;
1283
1284     if (!isComponentComplete()) {
1285         d->m_deferedUrlToLoad = url;
1286         return;
1287     }
1288
1289     d->webPageProxy->loadURL(url.toString());
1290 }
1291
1292 QUrl QQuickWebView::icon() const
1293 {
1294     Q_D(const QQuickWebView);
1295     return d->m_iconURL;
1296 }
1297
1298 /*!
1299     \qmlproperty int WebView::loadProgress
1300     \brief The progress of loading the current web page.
1301
1302     The range is from 0 to 100.
1303 */
1304
1305 int QQuickWebView::loadProgress() const
1306 {
1307     Q_D(const QQuickWebView);
1308     return d->pageLoadClient->loadProgress();
1309 }
1310
1311 bool QQuickWebView::canGoBack() const
1312 {
1313     Q_D(const QQuickWebView);
1314     return d->webPageProxy->canGoBack();
1315 }
1316
1317 bool QQuickWebView::canGoForward() const
1318 {
1319     Q_D(const QQuickWebView);
1320     return d->webPageProxy->canGoForward();
1321 }
1322
1323 /*!
1324     \qmlproperty bool WebView::loading
1325     \brief True if the web view is currently loading a web page, false otherwise.
1326 */
1327
1328 bool QQuickWebView::loading() const
1329 {
1330     Q_D(const QQuickWebView);
1331     RefPtr<WebKit::WebFrameProxy> mainFrame = d->webPageProxy->mainFrame();
1332     return mainFrame && !(WebFrameProxy::LoadStateFinished == mainFrame->loadState());
1333 }
1334
1335 /*!
1336     \internal
1337  */
1338
1339 QPointF QQuickWebView::mapToWebContent(const QPointF& pointInViewCoordinates) const
1340 {
1341     Q_D(const QQuickWebView);
1342     return d->pageView->transformFromItem().map(pointInViewCoordinates);
1343 }
1344
1345 /*!
1346     \internal
1347  */
1348
1349 QRectF QQuickWebView::mapRectToWebContent(const QRectF& rectInViewCoordinates) const
1350 {
1351     Q_D(const QQuickWebView);
1352     return d->pageView->transformFromItem().mapRect(rectInViewCoordinates);
1353 }
1354
1355 /*!
1356     \internal
1357  */
1358
1359 QPointF QQuickWebView::mapFromWebContent(const QPointF& pointInCSSCoordinates) const
1360 {
1361     Q_D(const QQuickWebView);
1362     return d->pageView->transformToItem().map(pointInCSSCoordinates);
1363 }
1364
1365 /*!
1366     \internal
1367  */
1368 QRectF QQuickWebView::mapRectFromWebContent(const QRectF& rectInCSSCoordinates) const
1369 {
1370     Q_D(const QQuickWebView);
1371     return d->pageView->transformToItem().mapRect(rectInCSSCoordinates);
1372 }
1373
1374 /*!
1375     \qmlproperty string WebView::title
1376     \brief The title of the loaded page.
1377 */
1378
1379 QString QQuickWebView::title() const
1380 {
1381     Q_D(const QQuickWebView);
1382     return d->webPageProxy->pageTitle();
1383 }
1384
1385 QVariant QQuickWebView::inputMethodQuery(Qt::InputMethodQuery property) const
1386 {
1387     Q_D(const QQuickWebView);
1388     const EditorState& state = d->webPageProxy->editorState();
1389
1390     switch(property) {
1391     case Qt::ImCursorRectangle:
1392         return QRectF(state.cursorRect);
1393     case Qt::ImFont:
1394         return QVariant();
1395     case Qt::ImCursorPosition:
1396         return QVariant(static_cast<int>(state.cursorPosition));
1397     case Qt::ImAnchorPosition:
1398         return QVariant(static_cast<int>(state.anchorPosition));
1399     case Qt::ImSurroundingText:
1400         return QString(state.surroundingText);
1401     case Qt::ImCurrentSelection:
1402         return QString(state.selectedText);
1403     case Qt::ImMaximumTextLength:
1404         return QVariant(); // No limit.
1405     case Qt::ImHints:
1406         return int(Qt::InputMethodHints(state.inputMethodHints));
1407     default:
1408         // Rely on the base implementation for ImEnabled, ImHints and ImPreferredLanguage.
1409         return QQuickFlickable::inputMethodQuery(property);
1410     }
1411 }
1412
1413 /*!
1414     \preliminary
1415
1416     The experimental module consisting on experimental API which will break
1417     from version to version.
1418 */
1419 QQuickWebViewExperimental* QQuickWebView::experimental() const
1420 {
1421     return m_experimental;
1422 }
1423
1424 QQuickWebViewAttached* QQuickWebView::qmlAttachedProperties(QObject* object)
1425 {
1426     return new QQuickWebViewAttached(object);
1427 }
1428
1429 /*!
1430     \internal
1431 */
1432 void QQuickWebView::platformInitialize()
1433 {
1434     JSC::initializeThreading();
1435     WTF::initializeMainThread();
1436 }
1437
1438 void QQuickWebView::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry)
1439 {
1440     Q_D(QQuickWebView);
1441     QQuickFlickable::geometryChanged(newGeometry, oldGeometry);
1442     if (newGeometry.size() != oldGeometry.size())
1443         d->updateViewportSize();
1444 }
1445
1446 void QQuickWebView::componentComplete()
1447 {
1448     Q_D(QQuickWebView);
1449     QQuickFlickable::componentComplete();
1450
1451     d->onComponentComplete();
1452     d->updateViewportSize();
1453 }
1454
1455 void QQuickWebView::keyPressEvent(QKeyEvent* event)
1456 {
1457     Q_D(QQuickWebView);
1458     d->pageView->eventHandler()->handleKeyPressEvent(event);
1459 }
1460
1461 void QQuickWebView::keyReleaseEvent(QKeyEvent* event)
1462 {
1463     Q_D(QQuickWebView);
1464     d->pageView->eventHandler()->handleKeyReleaseEvent(event);
1465 }
1466
1467 void QQuickWebView::inputMethodEvent(QInputMethodEvent* event)
1468 {
1469     Q_D(QQuickWebView);
1470     d->pageView->eventHandler()->handleInputMethodEvent(event);
1471 }
1472
1473 void QQuickWebView::focusInEvent(QFocusEvent* event)
1474 {
1475     Q_D(QQuickWebView);
1476     d->pageView->eventHandler()->handleFocusInEvent(event);
1477 }
1478
1479 void QQuickWebView::focusOutEvent(QFocusEvent* event)
1480 {
1481     Q_D(QQuickWebView);
1482     d->pageView->eventHandler()->handleFocusOutEvent(event);
1483 }
1484
1485 void QQuickWebView::touchEvent(QTouchEvent* event)
1486 {
1487     Q_D(QQuickWebView);
1488     if (d->m_dialogActive) {
1489         event->ignore();
1490         return;
1491     }
1492
1493     bool lockingDisabled = flickableDirection() != AutoFlickDirection
1494                            || event->touchPoints().size() != 1
1495                            || width() >= contentWidth()
1496                            || height() >= contentHeight();
1497
1498     if (!lockingDisabled)
1499         d->axisLocker.update(event);
1500     else
1501         d->axisLocker.reset();
1502
1503     forceActiveFocus();
1504     d->pageView->eventHandler()->handleTouchEvent(event);
1505 }
1506
1507 void QQuickWebView::mousePressEvent(QMouseEvent* event)
1508 {
1509     Q_D(QQuickWebView);
1510     forceActiveFocus();
1511     d->pageView->eventHandler()->handleMousePressEvent(event);
1512 }
1513
1514 void QQuickWebView::mouseMoveEvent(QMouseEvent* event)
1515 {
1516     Q_D(QQuickWebView);
1517     d->pageView->eventHandler()->handleMouseMoveEvent(event);
1518 }
1519
1520 void QQuickWebView::mouseReleaseEvent(QMouseEvent* event)
1521 {
1522     Q_D(QQuickWebView);
1523     d->pageView->eventHandler()->handleMouseReleaseEvent(event);
1524 }
1525
1526 void QQuickWebView::mouseDoubleClickEvent(QMouseEvent* event)
1527 {
1528     Q_D(QQuickWebView);
1529     // If a MouseButtonDblClick was received then we got a MouseButtonPress before
1530     // handleMousePressEvent will take care of double clicks.
1531     d->pageView->eventHandler()->handleMousePressEvent(event);
1532 }
1533
1534 void QQuickWebView::wheelEvent(QWheelEvent* event)
1535 {
1536     Q_D(QQuickWebView);
1537     d->pageView->eventHandler()->handleWheelEvent(event);
1538 }
1539
1540 void QQuickWebView::hoverEnterEvent(QHoverEvent* event)
1541 {
1542     Q_D(QQuickWebView);
1543     // Map HoverEnter to Move, for WebKit the distinction doesn't matter.
1544     d->pageView->eventHandler()->handleHoverMoveEvent(event);
1545 }
1546
1547 void QQuickWebView::hoverMoveEvent(QHoverEvent* event)
1548 {
1549     Q_D(QQuickWebView);
1550     d->pageView->eventHandler()->handleHoverMoveEvent(event);
1551 }
1552
1553 void QQuickWebView::hoverLeaveEvent(QHoverEvent* event)
1554 {
1555     Q_D(QQuickWebView);
1556     d->pageView->eventHandler()->handleHoverLeaveEvent(event);
1557 }
1558
1559 void QQuickWebView::dragMoveEvent(QDragMoveEvent* event)
1560 {
1561     Q_D(QQuickWebView);
1562     d->pageView->eventHandler()->handleDragMoveEvent(event);
1563 }
1564
1565 void QQuickWebView::dragEnterEvent(QDragEnterEvent* event)
1566 {
1567     Q_D(QQuickWebView);
1568     d->pageView->eventHandler()->handleDragEnterEvent(event);
1569 }
1570
1571 void QQuickWebView::dragLeaveEvent(QDragLeaveEvent* event)
1572 {
1573     Q_D(QQuickWebView);
1574     d->pageView->eventHandler()->handleDragLeaveEvent(event);
1575 }
1576
1577 void QQuickWebView::dropEvent(QDropEvent* event)
1578 {
1579     Q_D(QQuickWebView);
1580     d->pageView->eventHandler()->handleDropEvent(event);
1581 }
1582
1583 bool QQuickWebView::event(QEvent* ev)
1584 {
1585     // Re-implemented for possible future use without breaking binary compatibility.
1586     return QQuickFlickable::event(ev);
1587 }
1588
1589 WKPageRef QQuickWebView::pageRef() const
1590 {
1591     Q_D(const QQuickWebView);
1592     return toAPI(d->webPageProxy.get());
1593 }
1594
1595 QPointF QQuickWebView::contentPos() const
1596 {
1597     Q_D(const QQuickWebView);
1598     return d->contentPos();
1599 }
1600
1601 void QQuickWebView::setContentPos(const QPointF& pos)
1602 {
1603     Q_D(QQuickWebView);
1604     d->setContentPos(pos);
1605 }
1606
1607 void QQuickWebView::handleFlickableMousePress(const QPointF& position, qint64 eventTimestampMillis)
1608 {
1609     Q_D(QQuickWebView);
1610     d->axisLocker.setReferencePosition(position);
1611     QMouseEvent mouseEvent(QEvent::MouseButtonPress, position, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1612     mouseEvent.setTimestamp(eventTimestampMillis);
1613     QQuickFlickable::mousePressEvent(&mouseEvent);
1614 }
1615
1616 void QQuickWebView::handleFlickableMouseMove(const QPointF& position, qint64 eventTimestampMillis)
1617 {
1618     Q_D(QQuickWebView);
1619     QMouseEvent mouseEvent(QEvent::MouseMove, d->axisLocker.adjust(position), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1620     mouseEvent.setTimestamp(eventTimestampMillis);
1621     QQuickFlickable::mouseMoveEvent(&mouseEvent);
1622 }
1623
1624 void QQuickWebView::handleFlickableMouseRelease(const QPointF& position, qint64 eventTimestampMillis)
1625 {
1626     Q_D(QQuickWebView);
1627     QMouseEvent mouseEvent(QEvent::MouseButtonRelease, d->axisLocker.adjust(position), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1628     d->axisLocker.reset();
1629     mouseEvent.setTimestamp(eventTimestampMillis);
1630     QQuickFlickable::mouseReleaseEvent(&mouseEvent);
1631 }
1632
1633 /*!
1634     \qmlmethod void WebView::loadHtml(string html, url baseUrl, url unreachableUrl)
1635     \brief Loads the specified \a html as the content of the web view.
1636
1637     External objects such as stylesheets or images referenced in the HTML
1638     document are located relative to \a baseUrl.
1639
1640     \sa WebView::url
1641 */
1642 void QQuickWebView::loadHtml(const QString& html, const QUrl& baseUrl)
1643 {
1644     Q_D(QQuickWebView);
1645     d->webPageProxy->loadHTMLString(html, baseUrl.toString());
1646 }
1647
1648 QPointF QQuickWebView::pageItemPos()
1649 {
1650     Q_D(QQuickWebView);
1651     return d->pageItemPos();
1652 }
1653
1654 void QQuickWebView::updateContentsSize(const QSizeF& size)
1655 {
1656     Q_D(QQuickWebView);
1657     d->updateContentsSize(size);
1658 }
1659
1660 qreal QQuickWebView::zoomFactor() const
1661 {
1662     Q_D(const QQuickWebView);
1663     return d->zoomFactor();
1664 }
1665
1666 void QQuickWebView::setZoomFactor(qreal factor)
1667 {
1668
1669     Q_D(QQuickWebView);
1670     d->setZoomFactor(factor);
1671 }
1672
1673 struct JSCallbackClosure {
1674     QPointer<QObject> receiver;
1675     QByteArray method;
1676 };
1677
1678 static void javaScriptCallback(WKSerializedScriptValueRef, WKErrorRef, void* context)
1679 {
1680     JSCallbackClosure* closure = reinterpret_cast<JSCallbackClosure*>(context);
1681     QMetaObject::invokeMethod(closure->receiver, closure->method);
1682     delete closure;
1683 }
1684
1685 void QQuickWebView::runJavaScriptInMainFrame(const QString &script, QObject *receiver, const char *method)
1686 {
1687     Q_D(QQuickWebView);
1688     JSCallbackClosure* closure = new JSCallbackClosure;
1689     closure->receiver = receiver;
1690     closure->method = method;
1691     d->webPageProxy.get()->runJavaScriptInMainFrame(script, ScriptValueCallback::create(closure, javaScriptCallback));
1692 }
1693
1694 #include "moc_qquickwebview_p.cpp"