Rename deviceDPI to devicePixelRatio https://bugs.webkit.org/show_bug.cgi?id=85049
[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     wkPrefs->setDeviceWidth(viewportSize.width());
756     wkPrefs->setDeviceHeight(viewportSize.height());
757
758     // Let the WebProcess know about the new viewport size, so that
759     // it can resize the content accordingly.
760     webPageProxy->setViewportSize(viewportSize);
761
762     _q_contentViewportChanged(QPointF());
763 }
764
765 void QQuickWebViewFlickablePrivate::_q_contentViewportChanged(const QPointF& trajectoryVector)
766 {
767     Q_Q(QQuickWebView);
768     // This is only for our QML ViewportInfo debugging API.
769     q->experimental()->viewportInfo()->didUpdateCurrentScale();
770
771     DrawingAreaProxy* drawingArea = webPageProxy->drawingArea();
772     if (!drawingArea)
773         return;
774
775     const QRect visibleRect(visibleContentsRect());
776     float scale = pageView->contentsScale();
777
778     QRectF accurateVisibleRect(q->boundingRect());
779     accurateVisibleRect.translate(contentPos());
780     drawingArea->setVisibleContentsRect(visibleRect, scale, trajectoryVector, FloatPoint(accurateVisibleRect.x(), accurateVisibleRect.y()));
781
782     // Ensure that updatePaintNode is always called before painting.
783     pageView->update();
784 }
785
786 void QQuickWebViewFlickablePrivate::_q_suspend()
787 {
788     pageIsSuspended = true;
789     webPageProxy->suspendActiveDOMObjectsAndAnimations();
790 }
791
792 void QQuickWebViewFlickablePrivate::_q_resume()
793 {
794     if (!interactionEngine)
795         return;
796
797     pageIsSuspended = false;
798     webPageProxy->resumeActiveDOMObjectsAndAnimations();
799
800     _q_contentViewportChanged(QPointF());
801 }
802
803 void QQuickWebViewFlickablePrivate::pageDidRequestScroll(const QPoint& pos)
804 {
805     interactionEngine->pagePositionRequest(pos);
806 }
807
808 void QQuickWebViewFlickablePrivate::didChangeContentsSize(const QSize& newSize)
809 {
810     Q_Q(QQuickWebView);
811     pageView->setContentsSize(newSize);
812     q->experimental()->viewportInfo()->didUpdateContentsSize();
813 }
814
815 /*!
816     \qmlsignal WebView::onNavigationRequested(WebNavigationRequest request)
817
818     This signal is emitted for every navigation request. The request object contains url,
819     button and modifiers properties describing the navigation action, e.g. "a middle click
820     with shift key pressed to 'http://qt-project.org'".
821
822     The navigation will be accepted by default. To change that, one can set the action
823     property to WebView.IgnoreRequest to reject the request or WebView.DownloadRequest to
824     trigger a download instead of navigating to the url.
825
826     The request object cannot be used after the signal handler function ends.
827
828     \sa WebNavigationRequest
829 */
830
831 QQuickWebViewAttached::QQuickWebViewAttached(QObject* object)
832     : QObject(object)
833     , m_view(0)
834 {
835
836 }
837
838 void QQuickWebViewAttached::setView(QQuickWebView* view)
839 {
840     if (m_view == view)
841         return;
842     m_view = view;
843     emit viewChanged();
844 }
845
846 QQuickWebViewExperimental::QQuickWebViewExperimental(QQuickWebView *webView)
847     : QObject(webView)
848     , q_ptr(webView)
849     , d_ptr(webView->d_ptr.data())
850     , schemeParent(new QObject(this))
851     , m_viewportInfo(new QWebViewportInfo(webView->d_ptr.data(), this))
852 {
853 }
854
855 QQuickWebViewExperimental::~QQuickWebViewExperimental()
856 {
857 }
858
859 void QQuickWebViewExperimental::setRenderToOffscreenBuffer(bool enable)
860 {
861     Q_D(QQuickWebView);
862     d->setRenderToOffscreenBuffer(enable);
863 }
864
865 bool QQuickWebViewExperimental::renderToOffscreenBuffer() const
866 {
867     Q_D(const QQuickWebView);
868     return d->renderToOffscreenBuffer();
869 }
870
871 bool QQuickWebViewExperimental::transparentBackground() const
872 {
873     Q_D(const QQuickWebView);
874     return d->transparentBackground();
875 }
876 void QQuickWebViewExperimental::setTransparentBackground(bool enable)
877 {
878     Q_D(QQuickWebView);
879     d->setTransparentBackground(enable);
880 }
881
882 bool QQuickWebViewExperimental::useDefaultContentItemSize() const
883 {
884     Q_D(const QQuickWebView);
885     return d->m_useDefaultContentItemSize;
886 }
887
888 void QQuickWebViewExperimental::setUseDefaultContentItemSize(bool enable)
889 {
890     Q_D(QQuickWebView);
891     d->m_useDefaultContentItemSize = enable;
892 }
893
894 /*!
895     \internal
896
897     \qmlproperty int WebViewExperimental::preferredMinimumContentsWidth
898     \brief Minimum contents width when not overriden by the page itself.
899
900     Unless the page defines how contents should be laid out, using e.g.
901     the viewport meta tag, it is laid out given the width of the viewport
902     (in CSS units).
903
904     This setting can be used to enforce a minimum width when the page
905     does not define a width itself. This is useful for laying out pages
906     designed for big screens, commonly knows as desktop pages, on small
907     devices.
908
909     The default value is 0, but the value of 980 is recommented for small
910     screens as it provides a good trade off between legitable pages and
911     non-broken content.
912  */
913 int QQuickWebViewExperimental::preferredMinimumContentsWidth() const
914 {
915     Q_D(const QQuickWebView);
916     return d->webPageProxy->pageGroup()->preferences()->layoutFallbackWidth();
917 }
918
919 void QQuickWebViewExperimental::setPreferredMinimumContentsWidth(int width)
920 {
921     Q_D(QQuickWebView);
922     d->webPageProxy->pageGroup()->preferences()->setLayoutFallbackWidth(width);
923 }
924
925 void QQuickWebViewExperimental::setFlickableViewportEnabled(bool enable)
926 {
927     s_flickableViewportEnabled = enable;
928 }
929
930 bool QQuickWebViewExperimental::flickableViewportEnabled()
931 {
932     return s_flickableViewportEnabled;
933 }
934
935 /*!
936     \internal
937
938     \qmlmethod void WebViewExperimental::postMessage(string message)
939
940     \brief Post a message to an onmessage function registered with the navigator.qt object
941            by JavaScript code executing on the page.
942
943     \sa onMessageReceived
944 */
945
946 void QQuickWebViewExperimental::postMessage(const QString& message)
947 {
948     Q_D(QQuickWebView);
949     d->context->postMessageToNavigatorQtObject(d->webPageProxy.get(), message);
950 }
951
952 QDeclarativeComponent* QQuickWebViewExperimental::alertDialog() const
953 {
954     Q_D(const QQuickWebView);
955     return d->alertDialog;
956 }
957
958 void QQuickWebViewExperimental::setAlertDialog(QDeclarativeComponent* alertDialog)
959 {
960     Q_D(QQuickWebView);
961     if (d->alertDialog == alertDialog)
962         return;
963     d->alertDialog = alertDialog;
964     emit alertDialogChanged();
965 }
966
967 QDeclarativeComponent* QQuickWebViewExperimental::confirmDialog() const
968 {
969     Q_D(const QQuickWebView);
970     return d->confirmDialog;
971 }
972
973 void QQuickWebViewExperimental::setConfirmDialog(QDeclarativeComponent* confirmDialog)
974 {
975     Q_D(QQuickWebView);
976     if (d->confirmDialog == confirmDialog)
977         return;
978     d->confirmDialog = confirmDialog;
979     emit confirmDialogChanged();
980 }
981
982 QWebNavigationHistory* QQuickWebViewExperimental::navigationHistory() const
983 {
984     return d_ptr->navigationHistory.get();
985 }
986
987 QDeclarativeComponent* QQuickWebViewExperimental::promptDialog() const
988 {
989     Q_D(const QQuickWebView);
990     return d->promptDialog;
991 }
992
993 QWebPreferences* QQuickWebViewExperimental::preferences() const
994 {
995     QQuickWebViewPrivate* const d = d_ptr;
996     if (!d->preferences)
997         d->preferences = adoptPtr(QWebPreferencesPrivate::createPreferences(d));
998     return d->preferences.get();
999 }
1000
1001 void QQuickWebViewExperimental::setPromptDialog(QDeclarativeComponent* promptDialog)
1002 {
1003     Q_D(QQuickWebView);
1004     if (d->promptDialog == promptDialog)
1005         return;
1006     d->promptDialog = promptDialog;
1007     emit promptDialogChanged();
1008 }
1009
1010 QDeclarativeComponent* QQuickWebViewExperimental::authenticationDialog() const
1011 {
1012     Q_D(const QQuickWebView);
1013     return d->authenticationDialog;
1014 }
1015
1016 void QQuickWebViewExperimental::setAuthenticationDialog(QDeclarativeComponent* authenticationDialog)
1017 {
1018     Q_D(QQuickWebView);
1019     if (d->authenticationDialog == authenticationDialog)
1020         return;
1021     d->authenticationDialog = authenticationDialog;
1022     emit authenticationDialogChanged();
1023 }
1024
1025 QDeclarativeComponent* QQuickWebViewExperimental::proxyAuthenticationDialog() const
1026 {
1027     Q_D(const QQuickWebView);
1028     return d->proxyAuthenticationDialog;
1029 }
1030
1031 void QQuickWebViewExperimental::setProxyAuthenticationDialog(QDeclarativeComponent* proxyAuthenticationDialog)
1032 {
1033     Q_D(QQuickWebView);
1034     if (d->proxyAuthenticationDialog == proxyAuthenticationDialog)
1035         return;
1036     d->proxyAuthenticationDialog = proxyAuthenticationDialog;
1037     emit proxyAuthenticationDialogChanged();
1038 }
1039 QDeclarativeComponent* QQuickWebViewExperimental::certificateVerificationDialog() const
1040 {
1041     Q_D(const QQuickWebView);
1042     return d->certificateVerificationDialog;
1043 }
1044
1045 void QQuickWebViewExperimental::setCertificateVerificationDialog(QDeclarativeComponent* certificateVerificationDialog)
1046 {
1047     Q_D(QQuickWebView);
1048     if (d->certificateVerificationDialog == certificateVerificationDialog)
1049         return;
1050     d->certificateVerificationDialog = certificateVerificationDialog;
1051     emit certificateVerificationDialogChanged();
1052 }
1053
1054 QDeclarativeComponent* QQuickWebViewExperimental::itemSelector() const
1055 {
1056     Q_D(const QQuickWebView);
1057     return d->itemSelector;
1058 }
1059
1060 void QQuickWebViewExperimental::setItemSelector(QDeclarativeComponent* itemSelector)
1061 {
1062     Q_D(QQuickWebView);
1063     if (d->itemSelector == itemSelector)
1064         return;
1065     d->itemSelector = itemSelector;
1066     emit itemSelectorChanged();
1067 }
1068
1069 QDeclarativeComponent* QQuickWebViewExperimental::filePicker() const
1070 {
1071     Q_D(const QQuickWebView);
1072     return d->filePicker;
1073 }
1074
1075 void QQuickWebViewExperimental::setFilePicker(QDeclarativeComponent* filePicker)
1076 {
1077     Q_D(QQuickWebView);
1078     if (d->filePicker == filePicker)
1079         return;
1080     d->filePicker = filePicker;
1081     emit filePickerChanged();
1082 }
1083
1084 QDeclarativeComponent* QQuickWebViewExperimental::databaseQuotaDialog() const
1085 {
1086     Q_D(const QQuickWebView);
1087     return d->databaseQuotaDialog;
1088 }
1089
1090 void QQuickWebViewExperimental::setDatabaseQuotaDialog(QDeclarativeComponent* databaseQuotaDialog)
1091 {
1092     Q_D(QQuickWebView);
1093     if (d->databaseQuotaDialog == databaseQuotaDialog)
1094         return;
1095     d->databaseQuotaDialog = databaseQuotaDialog;
1096     emit databaseQuotaDialogChanged();
1097 }
1098
1099 QString QQuickWebViewExperimental::userAgent() const
1100 {
1101     Q_D(const QQuickWebView);
1102     return d->webPageProxy->userAgent();
1103 }
1104
1105 void QQuickWebViewExperimental::setUserAgent(const QString& userAgent)
1106 {
1107     Q_D(QQuickWebView);
1108     if (userAgent == QString(d->webPageProxy->userAgent()))
1109         return;
1110
1111     d->webPageProxy->setUserAgent(userAgent);
1112     emit userAgentChanged();
1113 }
1114
1115 double QQuickWebViewExperimental::devicePixelRatio() const
1116 {
1117     Q_D(const QQuickWebView);
1118     return d->webPageProxy->pageGroup()->preferences()->devicePixelRatio();
1119 }
1120
1121 void QQuickWebViewExperimental::setDevicePixelRatio(double devicePixelRatio)
1122 {
1123     Q_D(QQuickWebView);
1124     if (devicePixelRatio == this->devicePixelRatio())
1125         return;
1126
1127     d->webPageProxy->pageGroup()->preferences()->setDevicePixelRatio(devicePixelRatio);
1128     emit devicePixelRatioChanged();
1129 }
1130
1131 QQuickUrlSchemeDelegate* QQuickWebViewExperimental::schemeDelegates_At(QDeclarativeListProperty<QQuickUrlSchemeDelegate>* property, int index)
1132 {
1133     const QObjectList children = property->object->children();
1134     if (index < children.count())
1135         return static_cast<QQuickUrlSchemeDelegate*>(children.at(index));
1136     return 0;
1137 }
1138
1139 void QQuickWebViewExperimental::schemeDelegates_Append(QDeclarativeListProperty<QQuickUrlSchemeDelegate>* property, QQuickUrlSchemeDelegate *scheme)
1140 {
1141     QObject* schemeParent = property->object;
1142     scheme->setParent(schemeParent);
1143     QQuickWebViewExperimental* webViewExperimental = qobject_cast<QQuickWebViewExperimental*>(property->object->parent());
1144     if (!webViewExperimental)
1145         return;
1146     scheme->reply()->setWebViewExperimental(webViewExperimental);
1147     QQuickWebViewPrivate* d = webViewExperimental->d_func();
1148     d->webPageProxy->registerApplicationScheme(scheme->scheme());
1149 }
1150
1151 int QQuickWebViewExperimental::schemeDelegates_Count(QDeclarativeListProperty<QQuickUrlSchemeDelegate>* property)
1152 {
1153     return property->object->children().count();
1154 }
1155
1156 void QQuickWebViewExperimental::schemeDelegates_Clear(QDeclarativeListProperty<QQuickUrlSchemeDelegate>* property)
1157 {
1158     const QObjectList children = property->object->children();
1159     for (int index = 0; index < children.count(); index++) {
1160         QObject* child = children.at(index);
1161         child->setParent(0);
1162         delete child;
1163     }
1164 }
1165
1166 QDeclarativeListProperty<QQuickUrlSchemeDelegate> QQuickWebViewExperimental::schemeDelegates()
1167 {
1168     return QDeclarativeListProperty<QQuickUrlSchemeDelegate>(schemeParent, 0,
1169             QQuickWebViewExperimental::schemeDelegates_Append,
1170             QQuickWebViewExperimental::schemeDelegates_Count,
1171             QQuickWebViewExperimental::schemeDelegates_At,
1172             QQuickWebViewExperimental::schemeDelegates_Clear);
1173 }
1174
1175 void QQuickWebViewExperimental::invokeApplicationSchemeHandler(PassRefPtr<QtRefCountedNetworkRequestData> request)
1176 {
1177     RefPtr<QtRefCountedNetworkRequestData> req = request;
1178     const QObjectList children = schemeParent->children();
1179     for (int index = 0; index < children.count(); index++) {
1180         QQuickUrlSchemeDelegate* delegate = qobject_cast<QQuickUrlSchemeDelegate*>(children.at(index));
1181         if (!delegate)
1182             continue;
1183         if (!delegate->scheme().compare(QString(req->data().m_scheme), Qt::CaseInsensitive)) {
1184             delegate->request()->setNetworkRequestData(req);
1185             delegate->reply()->setNetworkRequestData(req);
1186             emit delegate->receivedRequest();
1187             return;
1188         }
1189     }
1190 }
1191
1192 void QQuickWebViewExperimental::sendApplicationSchemeReply(QQuickNetworkReply* reply)
1193 {
1194     d_ptr->webPageProxy->sendApplicationSchemeReply(reply);
1195 }
1196
1197 void QQuickWebViewExperimental::goForwardTo(int index)
1198 {
1199     d_ptr->navigationHistory->d->goForwardTo(index);
1200 }
1201
1202 void QQuickWebViewExperimental::goBackTo(int index)
1203 {
1204     d_ptr->navigationHistory->d->goBackTo(index);
1205 }
1206
1207 QWebViewportInfo* QQuickWebViewExperimental::viewportInfo()
1208 {
1209     return m_viewportInfo;
1210 }
1211
1212 QQuickWebPage* QQuickWebViewExperimental::page()
1213 {
1214     return q_ptr->page();
1215 }
1216
1217 /*!
1218     \qmlclass WebView QWebView
1219     \inqmlmodule QtWebKit 3.0
1220 */
1221
1222 /*!
1223    \qmlmethod WebView(Item parent)
1224    \brief Constructs a WebView with a parent.
1225 */
1226
1227 QQuickWebView::QQuickWebView(QQuickItem* parent)
1228     : QQuickFlickable(parent)
1229     , d_ptr(createPrivateObject(this))
1230     , m_experimental(new QQuickWebViewExperimental(this))
1231 {
1232     Q_D(QQuickWebView);
1233     d->initialize();
1234 }
1235
1236 QQuickWebView::QQuickWebView(WKContextRef contextRef, WKPageGroupRef pageGroupRef, QQuickItem* parent)
1237     : QQuickFlickable(parent)
1238     , d_ptr(createPrivateObject(this))
1239     , m_experimental(new QQuickWebViewExperimental(this))
1240 {
1241     Q_D(QQuickWebView);
1242     d->initialize(contextRef, pageGroupRef);
1243 }
1244
1245 QQuickWebView::~QQuickWebView()
1246 {
1247 }
1248
1249 QQuickWebPage* QQuickWebView::page()
1250 {
1251     Q_D(QQuickWebView);
1252     return d->pageView.data();
1253 }
1254
1255 void QQuickWebView::goBack()
1256 {
1257     Q_D(QQuickWebView);
1258     d->webPageProxy->goBack();
1259 }
1260
1261 void QQuickWebView::goForward()
1262 {
1263     Q_D(QQuickWebView);
1264     d->webPageProxy->goForward();
1265 }
1266
1267 void QQuickWebView::stop()
1268 {
1269     Q_D(QQuickWebView);
1270     d->webPageProxy->stopLoading();
1271 }
1272
1273 void QQuickWebView::reload()
1274 {
1275     Q_D(QQuickWebView);
1276     const bool reloadFromOrigin = true;
1277     d->webPageProxy->reload(reloadFromOrigin);
1278 }
1279
1280 QUrl QQuickWebView::url() const
1281 {
1282     Q_D(const QQuickWebView);
1283     RefPtr<WebFrameProxy> mainFrame = d->webPageProxy->mainFrame();
1284     if (!mainFrame)
1285         return QUrl();
1286     return QUrl(QString(mainFrame->url()));
1287 }
1288
1289 void QQuickWebView::setUrl(const QUrl& url)
1290 {
1291     Q_D(QQuickWebView);
1292
1293     if (url.isEmpty())
1294         return;
1295
1296     if (!isComponentComplete()) {
1297         d->m_deferedUrlToLoad = url;
1298         return;
1299     }
1300
1301     d->webPageProxy->loadURL(url.toString());
1302 }
1303
1304 QUrl QQuickWebView::icon() const
1305 {
1306     Q_D(const QQuickWebView);
1307     return d->m_iconURL;
1308 }
1309
1310 /*!
1311     \qmlproperty int WebView::loadProgress
1312     \brief The progress of loading the current web page.
1313
1314     The range is from 0 to 100.
1315 */
1316
1317 int QQuickWebView::loadProgress() const
1318 {
1319     Q_D(const QQuickWebView);
1320     return d->pageLoadClient->loadProgress();
1321 }
1322
1323 bool QQuickWebView::canGoBack() const
1324 {
1325     Q_D(const QQuickWebView);
1326     return d->webPageProxy->canGoBack();
1327 }
1328
1329 bool QQuickWebView::canGoForward() const
1330 {
1331     Q_D(const QQuickWebView);
1332     return d->webPageProxy->canGoForward();
1333 }
1334
1335 /*!
1336     \qmlproperty bool WebView::loading
1337     \brief True if the web view is currently loading a web page, false otherwise.
1338 */
1339
1340 bool QQuickWebView::loading() const
1341 {
1342     Q_D(const QQuickWebView);
1343     RefPtr<WebKit::WebFrameProxy> mainFrame = d->webPageProxy->mainFrame();
1344     return mainFrame && !(WebFrameProxy::LoadStateFinished == mainFrame->loadState());
1345 }
1346
1347 /*!
1348     \internal
1349  */
1350
1351 QPointF QQuickWebView::mapToWebContent(const QPointF& pointInViewCoordinates) const
1352 {
1353     Q_D(const QQuickWebView);
1354     return d->pageView->transformFromItem().map(pointInViewCoordinates);
1355 }
1356
1357 /*!
1358     \internal
1359  */
1360
1361 QRectF QQuickWebView::mapRectToWebContent(const QRectF& rectInViewCoordinates) const
1362 {
1363     Q_D(const QQuickWebView);
1364     return d->pageView->transformFromItem().mapRect(rectInViewCoordinates);
1365 }
1366
1367 /*!
1368     \internal
1369  */
1370
1371 QPointF QQuickWebView::mapFromWebContent(const QPointF& pointInCSSCoordinates) const
1372 {
1373     Q_D(const QQuickWebView);
1374     return d->pageView->transformToItem().map(pointInCSSCoordinates);
1375 }
1376
1377 /*!
1378     \internal
1379  */
1380 QRectF QQuickWebView::mapRectFromWebContent(const QRectF& rectInCSSCoordinates) const
1381 {
1382     Q_D(const QQuickWebView);
1383     return d->pageView->transformToItem().mapRect(rectInCSSCoordinates);
1384 }
1385
1386 /*!
1387     \qmlproperty string WebView::title
1388     \brief The title of the loaded page.
1389 */
1390
1391 QString QQuickWebView::title() const
1392 {
1393     Q_D(const QQuickWebView);
1394     return d->webPageProxy->pageTitle();
1395 }
1396
1397 QVariant QQuickWebView::inputMethodQuery(Qt::InputMethodQuery property) const
1398 {
1399     Q_D(const QQuickWebView);
1400     const EditorState& state = d->webPageProxy->editorState();
1401
1402     switch(property) {
1403     case Qt::ImCursorRectangle:
1404         return QRectF(state.cursorRect);
1405     case Qt::ImFont:
1406         return QVariant();
1407     case Qt::ImCursorPosition:
1408         return QVariant(static_cast<int>(state.cursorPosition));
1409     case Qt::ImAnchorPosition:
1410         return QVariant(static_cast<int>(state.anchorPosition));
1411     case Qt::ImSurroundingText:
1412         return QString(state.surroundingText);
1413     case Qt::ImCurrentSelection:
1414         return QString(state.selectedText);
1415     case Qt::ImMaximumTextLength:
1416         return QVariant(); // No limit.
1417     case Qt::ImHints:
1418         return int(Qt::InputMethodHints(state.inputMethodHints));
1419     default:
1420         // Rely on the base implementation for ImEnabled, ImHints and ImPreferredLanguage.
1421         return QQuickFlickable::inputMethodQuery(property);
1422     }
1423 }
1424
1425 /*!
1426     \preliminary
1427
1428     The experimental module consisting on experimental API which will break
1429     from version to version.
1430 */
1431 QQuickWebViewExperimental* QQuickWebView::experimental() const
1432 {
1433     return m_experimental;
1434 }
1435
1436 QQuickWebViewAttached* QQuickWebView::qmlAttachedProperties(QObject* object)
1437 {
1438     return new QQuickWebViewAttached(object);
1439 }
1440
1441 /*!
1442     \internal
1443 */
1444 void QQuickWebView::platformInitialize()
1445 {
1446     JSC::initializeThreading();
1447     WTF::initializeMainThread();
1448 }
1449
1450 void QQuickWebView::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry)
1451 {
1452     Q_D(QQuickWebView);
1453     QQuickFlickable::geometryChanged(newGeometry, oldGeometry);
1454     if (newGeometry.size() != oldGeometry.size())
1455         d->updateViewportSize();
1456 }
1457
1458 void QQuickWebView::componentComplete()
1459 {
1460     Q_D(QQuickWebView);
1461     QQuickFlickable::componentComplete();
1462
1463     d->onComponentComplete();
1464     d->updateViewportSize();
1465 }
1466
1467 void QQuickWebView::keyPressEvent(QKeyEvent* event)
1468 {
1469     Q_D(QQuickWebView);
1470     d->pageView->eventHandler()->handleKeyPressEvent(event);
1471 }
1472
1473 void QQuickWebView::keyReleaseEvent(QKeyEvent* event)
1474 {
1475     Q_D(QQuickWebView);
1476     d->pageView->eventHandler()->handleKeyReleaseEvent(event);
1477 }
1478
1479 void QQuickWebView::inputMethodEvent(QInputMethodEvent* event)
1480 {
1481     Q_D(QQuickWebView);
1482     d->pageView->eventHandler()->handleInputMethodEvent(event);
1483 }
1484
1485 void QQuickWebView::focusInEvent(QFocusEvent* event)
1486 {
1487     Q_D(QQuickWebView);
1488     d->pageView->eventHandler()->handleFocusInEvent(event);
1489 }
1490
1491 void QQuickWebView::focusOutEvent(QFocusEvent* event)
1492 {
1493     Q_D(QQuickWebView);
1494     d->pageView->eventHandler()->handleFocusOutEvent(event);
1495 }
1496
1497 void QQuickWebView::touchEvent(QTouchEvent* event)
1498 {
1499     Q_D(QQuickWebView);
1500     if (d->m_dialogActive) {
1501         event->ignore();
1502         return;
1503     }
1504
1505     bool lockingDisabled = flickableDirection() != AutoFlickDirection
1506                            || event->touchPoints().size() != 1
1507                            || width() >= contentWidth()
1508                            || height() >= contentHeight();
1509
1510     if (!lockingDisabled)
1511         d->axisLocker.update(event);
1512     else
1513         d->axisLocker.reset();
1514
1515     forceActiveFocus();
1516     d->pageView->eventHandler()->handleTouchEvent(event);
1517 }
1518
1519 void QQuickWebView::mousePressEvent(QMouseEvent* event)
1520 {
1521     Q_D(QQuickWebView);
1522     forceActiveFocus();
1523     d->pageView->eventHandler()->handleMousePressEvent(event);
1524 }
1525
1526 void QQuickWebView::mouseMoveEvent(QMouseEvent* event)
1527 {
1528     Q_D(QQuickWebView);
1529     d->pageView->eventHandler()->handleMouseMoveEvent(event);
1530 }
1531
1532 void QQuickWebView::mouseReleaseEvent(QMouseEvent* event)
1533 {
1534     Q_D(QQuickWebView);
1535     d->pageView->eventHandler()->handleMouseReleaseEvent(event);
1536 }
1537
1538 void QQuickWebView::mouseDoubleClickEvent(QMouseEvent* event)
1539 {
1540     Q_D(QQuickWebView);
1541     // If a MouseButtonDblClick was received then we got a MouseButtonPress before
1542     // handleMousePressEvent will take care of double clicks.
1543     d->pageView->eventHandler()->handleMousePressEvent(event);
1544 }
1545
1546 void QQuickWebView::wheelEvent(QWheelEvent* event)
1547 {
1548     Q_D(QQuickWebView);
1549     d->pageView->eventHandler()->handleWheelEvent(event);
1550 }
1551
1552 void QQuickWebView::hoverEnterEvent(QHoverEvent* event)
1553 {
1554     Q_D(QQuickWebView);
1555     // Map HoverEnter to Move, for WebKit the distinction doesn't matter.
1556     d->pageView->eventHandler()->handleHoverMoveEvent(event);
1557 }
1558
1559 void QQuickWebView::hoverMoveEvent(QHoverEvent* event)
1560 {
1561     Q_D(QQuickWebView);
1562     d->pageView->eventHandler()->handleHoverMoveEvent(event);
1563 }
1564
1565 void QQuickWebView::hoverLeaveEvent(QHoverEvent* event)
1566 {
1567     Q_D(QQuickWebView);
1568     d->pageView->eventHandler()->handleHoverLeaveEvent(event);
1569 }
1570
1571 void QQuickWebView::dragMoveEvent(QDragMoveEvent* event)
1572 {
1573     Q_D(QQuickWebView);
1574     d->pageView->eventHandler()->handleDragMoveEvent(event);
1575 }
1576
1577 void QQuickWebView::dragEnterEvent(QDragEnterEvent* event)
1578 {
1579     Q_D(QQuickWebView);
1580     d->pageView->eventHandler()->handleDragEnterEvent(event);
1581 }
1582
1583 void QQuickWebView::dragLeaveEvent(QDragLeaveEvent* event)
1584 {
1585     Q_D(QQuickWebView);
1586     d->pageView->eventHandler()->handleDragLeaveEvent(event);
1587 }
1588
1589 void QQuickWebView::dropEvent(QDropEvent* event)
1590 {
1591     Q_D(QQuickWebView);
1592     d->pageView->eventHandler()->handleDropEvent(event);
1593 }
1594
1595 bool QQuickWebView::event(QEvent* ev)
1596 {
1597     // Re-implemented for possible future use without breaking binary compatibility.
1598     return QQuickFlickable::event(ev);
1599 }
1600
1601 WKPageRef QQuickWebView::pageRef() const
1602 {
1603     Q_D(const QQuickWebView);
1604     return toAPI(d->webPageProxy.get());
1605 }
1606
1607 QPointF QQuickWebView::contentPos() const
1608 {
1609     Q_D(const QQuickWebView);
1610     return d->contentPos();
1611 }
1612
1613 void QQuickWebView::setContentPos(const QPointF& pos)
1614 {
1615     Q_D(QQuickWebView);
1616     d->setContentPos(pos);
1617 }
1618
1619 void QQuickWebView::handleFlickableMousePress(const QPointF& position, qint64 eventTimestampMillis)
1620 {
1621     Q_D(QQuickWebView);
1622     d->axisLocker.setReferencePosition(position);
1623     QMouseEvent mouseEvent(QEvent::MouseButtonPress, position, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1624     mouseEvent.setTimestamp(eventTimestampMillis);
1625     QQuickFlickable::mousePressEvent(&mouseEvent);
1626 }
1627
1628 void QQuickWebView::handleFlickableMouseMove(const QPointF& position, qint64 eventTimestampMillis)
1629 {
1630     Q_D(QQuickWebView);
1631     QMouseEvent mouseEvent(QEvent::MouseMove, d->axisLocker.adjust(position), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1632     mouseEvent.setTimestamp(eventTimestampMillis);
1633     QQuickFlickable::mouseMoveEvent(&mouseEvent);
1634 }
1635
1636 void QQuickWebView::handleFlickableMouseRelease(const QPointF& position, qint64 eventTimestampMillis)
1637 {
1638     Q_D(QQuickWebView);
1639     QMouseEvent mouseEvent(QEvent::MouseButtonRelease, d->axisLocker.adjust(position), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1640     d->axisLocker.reset();
1641     mouseEvent.setTimestamp(eventTimestampMillis);
1642     QQuickFlickable::mouseReleaseEvent(&mouseEvent);
1643 }
1644
1645 /*!
1646     \qmlmethod void WebView::loadHtml(string html, url baseUrl, url unreachableUrl)
1647     \brief Loads the specified \a html as the content of the web view.
1648
1649     External objects such as stylesheets or images referenced in the HTML
1650     document are located relative to \a baseUrl.
1651
1652     \sa WebView::url
1653 */
1654 void QQuickWebView::loadHtml(const QString& html, const QUrl& baseUrl)
1655 {
1656     Q_D(QQuickWebView);
1657     d->webPageProxy->loadHTMLString(html, baseUrl.toString());
1658 }
1659
1660 QPointF QQuickWebView::pageItemPos()
1661 {
1662     Q_D(QQuickWebView);
1663     return d->pageItemPos();
1664 }
1665
1666 void QQuickWebView::updateContentsSize(const QSizeF& size)
1667 {
1668     Q_D(QQuickWebView);
1669     d->updateContentsSize(size);
1670 }
1671
1672 qreal QQuickWebView::zoomFactor() const
1673 {
1674     Q_D(const QQuickWebView);
1675     return d->zoomFactor();
1676 }
1677
1678 void QQuickWebView::setZoomFactor(qreal factor)
1679 {
1680
1681     Q_D(QQuickWebView);
1682     d->setZoomFactor(factor);
1683 }
1684
1685 struct JSCallbackClosure {
1686     QPointer<QObject> receiver;
1687     QByteArray method;
1688 };
1689
1690 static void javaScriptCallback(WKSerializedScriptValueRef, WKErrorRef, void* context)
1691 {
1692     JSCallbackClosure* closure = reinterpret_cast<JSCallbackClosure*>(context);
1693     QMetaObject::invokeMethod(closure->receiver, closure->method);
1694     delete closure;
1695 }
1696
1697 void QQuickWebView::runJavaScriptInMainFrame(const QString &script, QObject *receiver, const char *method)
1698 {
1699     Q_D(QQuickWebView);
1700     JSCallbackClosure* closure = new JSCallbackClosure;
1701     closure->receiver = receiver;
1702     closure->method = method;
1703     d->webPageProxy.get()->runJavaScriptInMainFrame(script, ScriptValueCallback::create(closure, javaScriptCallback));
1704 }
1705
1706 #include "moc_qquickwebview_p.cpp"