1a7da43d1d69682d3036491fc83eab6bf833b81e
[WebKit-https.git] / Source / WebKit2 / UIProcess / API / qt / qquickwebview.cpp
1 /*
2  * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
3  * Copyright (c) 2012 Hewlett-Packard Development Company, L.P.
4  * Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this program; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  */
22
23 #include "config.h"
24 #include "qquickwebview_p.h"
25
26 #include "DownloadProxy.h"
27 #include "DrawingAreaProxyImpl.h"
28 #include "PageViewportControllerClientQt.h"
29 #include "QtDialogRunner.h"
30 #include "QtDownloadManager.h"
31 #include "QtWebContext.h"
32 #include "QtWebError.h"
33 #include "QtWebIconDatabaseClient.h"
34 #include "QtWebPageEventHandler.h"
35 #include "QtWebPagePolicyClient.h"
36 #include "WebBackForwardList.h"
37 #include "WebFindOptions.h"
38 #if ENABLE(INSPECTOR_SERVER)
39 #include "WebInspectorProxy.h"
40 #include "WebInspectorServer.h"
41 #endif
42 #if ENABLE(FULLSCREEN_API)
43 #include "WebFullScreenManagerProxy.h"
44 #endif
45 #include "WebPageGroup.h"
46 #include "WebPreferences.h"
47 #include "qquicknetworkreply_p.h"
48 #include "qquicknetworkrequest_p.h"
49 #include "qquickwebpage_p_p.h"
50 #include "qquickwebview_p_p.h"
51 #include "qwebdownloaditem_p_p.h"
52 #include "qwebiconimageprovider_p.h"
53 #include "qwebkittest_p.h"
54 #include "qwebloadrequest_p.h"
55 #include "qwebnavigationhistory_p.h"
56 #include "qwebnavigationhistory_p_p.h"
57 #include "qwebpreferences_p.h"
58 #include "qwebpreferences_p_p.h"
59 #include <JavaScriptCore/InitializeThreading.h>
60 #include <JavaScriptCore/JSBase.h>
61 #include <JavaScriptCore/JSRetainPtr.h>
62 #include <QDateTime>
63 #include <QtCore/QFile>
64 #include <QtQml/QJSValue>
65 #include <QtQuick/QQuickView>
66 #include <WKOpenPanelResultListener.h>
67 #include <WKPageGroup.h>
68 #include <WKSerializedScriptValue.h>
69 #include <WKString.h>
70 #include <WKStringQt.h>
71 #include <WKURLQt.h>
72 #include <WebCore/IntPoint.h>
73 #include <WebCore/IntRect.h>
74 #include <limits>
75 #include <wtf/Assertions.h>
76 #include <wtf/MainThread.h>
77 #include <wtf/Vector.h>
78 #include <wtf/text/WTFString.h>
79
80 using namespace WebCore;
81 using namespace WebKit;
82
83 static bool s_flickableViewportEnabled = true;
84 static const int kAxisLockSampleCount = 5;
85 static const qreal kAxisLockVelocityThreshold = 300;
86 static const qreal kAxisLockVelocityDirectionThreshold = 50;
87
88 static inline QQuickWebViewPrivate* toQQuickWebViewPrivate(const void* clientInfo)
89 {
90     ASSERT(clientInfo);
91     return reinterpret_cast<QQuickWebViewPrivate*>(const_cast<void*>(clientInfo));
92 }
93
94 struct JSCallbackClosure {
95     QPointer<QObject> receiver;
96     QByteArray method;
97     QJSValue value;
98 };
99
100 static inline QString toQString(JSStringRef string)
101 {
102     return QString(reinterpret_cast<const QChar*>(JSStringGetCharactersPtr(string)), JSStringGetLength(string));
103 }
104
105 static inline QJSValue toQJSValue(JSStringRef string)
106 {
107     return QJSValue(toQString(string));
108 }
109
110 static QJSValue buildQJSValue(QJSEngine* engine, JSGlobalContextRef context, JSValueRef value, int depth)
111 {
112     QJSValue var;
113     JSValueRef exception = 0;
114
115     if (depth > 10)
116         return var;
117
118     switch (JSValueGetType(context, value)) {
119     case kJSTypeBoolean:
120         var = QJSValue(JSValueToBoolean(context, value));
121         break;
122     case kJSTypeNumber:
123         {
124             double number = JSValueToNumber(context, value, &exception);
125             if (!exception)
126                 var = QJSValue(number);
127         }
128         break;
129     case kJSTypeString:
130         {
131             JSRetainPtr<JSStringRef> string = JSValueToStringCopy(context, value, &exception);
132             if (!exception)
133                 var = toQJSValue(string.get());
134         }
135         break;
136     case kJSTypeObject:
137         {
138             JSObjectRef obj = JSValueToObject(context, value, &exception);
139
140             JSPropertyNameArrayRef names = JSObjectCopyPropertyNames(context, obj);
141             size_t length = JSPropertyNameArrayGetCount(names);
142
143             var = engine->newObject();
144
145             for (size_t i = 0; i < length; ++i) {
146                 JSRetainPtr<JSStringRef> name = JSPropertyNameArrayGetNameAtIndex(names, i);
147                 JSValueRef property = JSObjectGetProperty(context, obj, name.get(), &exception);
148
149                 if (!exception) {
150                     QJSValue value = buildQJSValue(engine, context, property, depth + 1);
151                     var.setProperty(toQString(name.get()), value);
152                 }
153             }
154         }
155         break;
156     }
157     return var;
158 }
159
160 static void javaScriptCallback(WKSerializedScriptValueRef valueRef, WKErrorRef, void* data)
161 {
162     JSCallbackClosure* closure = reinterpret_cast<JSCallbackClosure*>(data);
163
164     if (closure->method.size())
165         QMetaObject::invokeMethod(closure->receiver, closure->method);
166     else {
167         QJSValue function = closure->value;
168
169         // If a callable function is supplied, we build a JavaScript value accessible
170         // in the QML engine, and calls the function with that.
171         if (function.isCallable()) {
172             QJSValue var;
173             if (valueRef) {
174                 // FIXME: Slow but OK for now.
175                 JSGlobalContextRef context = JSGlobalContextCreate(0);
176
177                 JSValueRef exception = 0;
178                 JSValueRef value = WKSerializedScriptValueDeserialize(valueRef, context, &exception);
179                 var = buildQJSValue(function.engine(), context, value, /* depth */ 0);
180
181                 JSGlobalContextRelease(context);
182             }
183
184             QList<QJSValue> args;
185             args.append(var);
186             function.call(args);
187         }
188     }
189
190     delete closure;
191 }
192
193 static QQuickWebViewPrivate* createPrivateObject(QQuickWebView* publicObject)
194 {
195     if (s_flickableViewportEnabled)
196         return new QQuickWebViewFlickablePrivate(publicObject);
197     return new QQuickWebViewLegacyPrivate(publicObject);
198 }
199
200 QQuickWebViewPrivate::FlickableAxisLocker::FlickableAxisLocker()
201     : m_allowedDirection(QQuickFlickable::AutoFlickDirection)
202     , m_time(0), m_sampleCount(0)
203 {
204 }
205
206 QVector2D QQuickWebViewPrivate::FlickableAxisLocker::touchVelocity(const QTouchEvent* event)
207 {
208     static bool touchVelocityAvailable = event->device()->capabilities().testFlag(QTouchDevice::Velocity);
209     const QTouchEvent::TouchPoint& touchPoint = event->touchPoints().first();
210
211     if (touchVelocityAvailable)
212         return touchPoint.velocity();
213
214     const QLineF movementLine(touchPoint.pos(), m_initialPosition);
215     const ulong elapsed = event->timestamp() - m_time;
216
217     if (!elapsed)
218         return QVector2D(0, 0);
219
220     // Calculate an approximate velocity vector in the unit of pixel / second.
221     return QVector2D(1000 * movementLine.dx() / elapsed, 1000 * movementLine.dy() / elapsed);
222 }
223
224 void QQuickWebViewPrivate::FlickableAxisLocker::update(const QTouchEvent* event)
225 {
226     ASSERT(event->touchPoints().size() == 1);
227     const QTouchEvent::TouchPoint& touchPoint = event->touchPoints().first();
228
229     ++m_sampleCount;
230
231     if (m_sampleCount == 1) {
232         m_initialPosition = touchPoint.pos();
233         m_time = event->timestamp();
234         return;
235     }
236
237     if (m_sampleCount > kAxisLockSampleCount
238             || m_allowedDirection == QQuickFlickable::HorizontalFlick
239             || m_allowedDirection == QQuickFlickable::VerticalFlick)
240         return;
241
242     QVector2D velocity = touchVelocity(event);
243
244     qreal directionIndicator = qAbs(velocity.x()) - qAbs(velocity.y());
245
246     if (velocity.length() > kAxisLockVelocityThreshold && qAbs(directionIndicator) > kAxisLockVelocityDirectionThreshold)
247         m_allowedDirection = (directionIndicator > 0) ? QQuickFlickable::HorizontalFlick : QQuickFlickable::VerticalFlick;
248 }
249
250 void QQuickWebViewPrivate::FlickableAxisLocker::setReferencePosition(const QPointF& position)
251 {
252     m_lockReferencePosition = position;
253 }
254
255 void QQuickWebViewPrivate::FlickableAxisLocker::reset()
256 {
257     m_allowedDirection = QQuickFlickable::AutoFlickDirection;
258     m_sampleCount = 0;
259 }
260
261 QPointF QQuickWebViewPrivate::FlickableAxisLocker::adjust(const QPointF& position)
262 {
263     if (m_allowedDirection == QQuickFlickable::HorizontalFlick)
264         return QPointF(position.x(), m_lockReferencePosition.y());
265
266     if (m_allowedDirection == QQuickFlickable::VerticalFlick)
267         return QPointF(m_lockReferencePosition.x(), position.y());
268
269     return position;
270 }
271
272 QQuickWebViewPrivate::QQuickWebViewPrivate(QQuickWebView* viewport)
273     : q_ptr(viewport)
274     , experimental(new QQuickWebViewExperimental(viewport, this))
275     , alertDialog(0)
276     , confirmDialog(0)
277     , promptDialog(0)
278     , authenticationDialog(0)
279     , certificateVerificationDialog(0)
280     , itemSelector(0)
281     , proxyAuthenticationDialog(0)
282     , filePicker(0)
283     , databaseQuotaDialog(0)
284     , colorChooser(0)
285     , m_betweenLoadCommitAndFirstFrame(false)
286     , m_useDefaultContentItemSize(true)
287     , m_navigatorQtObjectEnabled(false)
288     , m_renderToOffscreenBuffer(false)
289     , m_allowAnyHTTPSCertificateForLocalHost(false)
290     , m_loadProgress(0)
291 {
292     viewport->setClip(true);
293     viewport->setPixelAligned(true);
294     QObject::connect(viewport, SIGNAL(visibleChanged()), viewport, SLOT(_q_onVisibleChanged()));
295     QObject::connect(viewport, SIGNAL(urlChanged()), viewport, SLOT(_q_onUrlChanged()));
296     pageView.reset(new QQuickWebPage(viewport));
297 }
298
299 QQuickWebViewPrivate::~QQuickWebViewPrivate()
300 {
301     webPageProxy->close();
302 }
303
304 // Note: we delay this initialization to make sure that QQuickWebView has its d-ptr in-place.
305 void QQuickWebViewPrivate::initialize(WKContextRef contextRef, WKPageGroupRef pageGroupRef)
306 {
307     pageGroup = pageGroupRef;
308     if (!pageGroup)
309         pageGroup = adoptWK(WKPageGroupCreateWithIdentifier(0));
310
311     context = contextRef ? QtWebContext::create(toImpl(contextRef)) : QtWebContext::defaultContext();
312     webPageProxy = context->createWebPage(&pageClient, toImpl(pageGroup.get()));
313     webPage = toAPI(webPageProxy.get());
314     webPageProxy->setUseFixedLayout(s_flickableViewportEnabled);
315 #if ENABLE(FULLSCREEN_API)
316     webPageProxy->fullScreenManager()->setWebView(q_ptr);
317 #endif
318
319     QQuickWebPagePrivate* const pageViewPrivate = pageView.data()->d;
320     pageViewPrivate->initialize(webPageProxy.get());
321
322     {
323         WKPageFindClient findClient;
324         memset(&findClient, 0, sizeof(WKPageFindClient));
325         findClient.version = kWKPageFindClientCurrentVersion;
326         findClient.clientInfo = this;
327         findClient.didFindString = didFindString;
328         findClient.didFailToFindString = didFailToFindString;
329         WKPageSetPageFindClient(webPage.get(), &findClient);
330     }
331
332     {
333         WKPageLoaderClient loadClient;
334         memset(&loadClient, 0, sizeof(WKPageLoaderClient));
335         loadClient.version = kWKPageLoaderClientCurrentVersion;
336         loadClient.clientInfo = this;
337         loadClient.didStartProvisionalLoadForFrame = didStartProvisionalLoadForFrame;
338         loadClient.didReceiveServerRedirectForProvisionalLoadForFrame = didReceiveServerRedirectForProvisionalLoadForFrame;
339         loadClient.didFailProvisionalLoadWithErrorForFrame = didFailLoad;
340         loadClient.didCommitLoadForFrame = didCommitLoadForFrame;
341         loadClient.didFinishLoadForFrame = didFinishLoadForFrame;
342         loadClient.didFailLoadWithErrorForFrame = didFailLoad;
343         loadClient.didSameDocumentNavigationForFrame = didSameDocumentNavigationForFrame;
344         loadClient.didReceiveTitleForFrame = didReceiveTitleForFrame;
345         loadClient.didStartProgress = didStartProgress;
346         loadClient.didChangeProgress = didChangeProgress;
347         loadClient.didFinishProgress = didFinishProgress;
348         loadClient.didChangeBackForwardList = didChangeBackForwardList;
349         WKPageSetPageLoaderClient(webPage.get(), &loadClient);
350     }
351
352     pagePolicyClient.reset(new QtWebPagePolicyClient(webPage.get(), q_ptr));
353     pageUIClient.reset(new QtWebPageUIClient(webPage.get(), q_ptr));
354     navigationHistory = adoptPtr(QWebNavigationHistoryPrivate::createHistory(webPage.get()));
355
356     QtWebIconDatabaseClient* iconDatabase = context->iconDatabase();
357     QObject::connect(iconDatabase, SIGNAL(iconChangedForPageURL(QString)), q_ptr, SLOT(_q_onIconChangedForPageURL(QString)));
358
359     // Any page setting should preferrable be set before creating the page.
360     webPageProxy->pageGroup()->preferences()->setAcceleratedCompositingEnabled(true);
361     webPageProxy->pageGroup()->preferences()->setForceCompositingMode(true);
362     bool showDebugVisuals = qgetenv("WEBKIT_SHOW_COMPOSITING_DEBUG_VISUALS") == "1";
363     webPageProxy->pageGroup()->preferences()->setCompositingBordersVisible(showDebugVisuals);
364     webPageProxy->pageGroup()->preferences()->setCompositingRepaintCountersVisible(showDebugVisuals);
365     webPageProxy->pageGroup()->preferences()->setFrameFlatteningEnabled(true);
366     webPageProxy->pageGroup()->preferences()->setWebGLEnabled(true);
367
368     pageClient.initialize(q_ptr, pageViewPrivate->eventHandler.data(), &undoController);
369     webPageProxy->initializeWebPage();
370     webPageProxy->registerApplicationScheme(ASCIILiteral("qrc"));
371
372     q_ptr->setAcceptedMouseButtons(Qt::MouseButtonMask);
373     q_ptr->setAcceptHoverEvents(true);
374     q_ptr->setFlag(QQuickItem::ItemAcceptsDrops, true);
375 }
376
377 void QQuickWebViewPrivate::didStartProvisionalLoadForFrame(WKPageRef, WKFrameRef frame, WKTypeRef, const void* clientInfo)
378 {
379     if (!WKFrameIsMainFrame(frame))
380         return;
381
382     WKRetainPtr<WKURLRef> url  = adoptWK(WKFrameCopyProvisionalURL(frame));
383
384     QQuickWebView* const q = toQQuickWebViewPrivate(clientInfo)->q_func();
385
386     q->emitUrlChangeIfNeeded();
387     QWebLoadRequest loadRequest(WKURLCopyQUrl(url.get()), QQuickWebView::LoadStartedStatus);
388     emit q->loadingChanged(&loadRequest);
389 }
390
391 void QQuickWebViewPrivate::didReceiveServerRedirectForProvisionalLoadForFrame(WKPageRef, WKFrameRef frame, WKTypeRef, const void* clientInfo)
392 {
393     if (!WKFrameIsMainFrame(frame))
394         return;
395
396     toQQuickWebViewPrivate(clientInfo)->q_func()->emitUrlChangeIfNeeded();
397 }
398
399 void QQuickWebViewPrivate::didFailLoad(WKPageRef, WKFrameRef frame, WKErrorRef errorRef, WKTypeRef, const void* clientInfo)
400 {
401     if (!WKFrameIsMainFrame(frame))
402         return;
403
404     QQuickWebView* const q = toQQuickWebViewPrivate(clientInfo)->q_func();
405     ASSERT(!q->loading());
406
407     QtWebError error(errorRef);
408     if (error.isCancellation()) {
409         QWebLoadRequest loadRequest(q->url(), QQuickWebView::LoadStoppedStatus);
410         emit q->loadingChanged(&loadRequest);
411         return;
412     }
413
414     int errorCode = error.errorCode();
415     if (errorCode == kWKErrorCodeFrameLoadInterruptedByPolicyChange && errorCode == kWKErrorCodePlugInWillHandleLoad) {
416         QWebLoadRequest loadRequest(q->url(), QQuickWebView::LoadSucceededStatus);
417         q->emitUrlChangeIfNeeded();
418         emit q->loadingChanged(&loadRequest);
419         return;
420     }
421
422     // We set the unreachable url unconditionally so that the current
423     // active url of the webview when the loadingChanged signal is
424     // emitted reflects the failed url, not the previously committed
425     // url. This also ensures that if the user does not do a loadHtml
426     // with an error page and and unreachable url as a reponse to the
427     // failed load, we can still detect the failed url for reloads.
428     // We need to find a way to do this via the C API or find another
429     // way to do this.
430     toImpl(frame)->setUnreachableURL(error.url());
431     q->emitUrlChangeIfNeeded();
432     QWebLoadRequest loadRequest(error.url(), QQuickWebView::LoadFailedStatus, error.description(), static_cast<QQuickWebView::ErrorDomain>(error.type()), errorCode);
433     emit q->loadingChanged(&loadRequest);
434 }
435
436 void QQuickWebViewPrivate::didCommitLoadForFrame(WKPageRef, WKFrameRef frame, WKTypeRef, const void* clientInfo)
437 {
438     if (!WKFrameIsMainFrame(frame))
439         return;
440     QQuickWebViewPrivate* d = toQQuickWebViewPrivate(clientInfo);
441
442     PageViewportController* pageViewportController = d->viewportController();
443     if (pageViewportController)
444         pageViewportController->didCommitLoad();
445
446     QQuickWebView* const q = d->q_func();
447     ASSERT(q->loading());
448     d->m_betweenLoadCommitAndFirstFrame = true;
449     emit q->navigationHistoryChanged();
450     emit q->titleChanged();
451 }
452
453 void QQuickWebViewPrivate::didFinishLoadForFrame(WKPageRef, WKFrameRef frame, WKTypeRef, const void* clientInfo)
454 {
455     if (!WKFrameIsMainFrame(frame))
456         return;
457
458     QQuickWebView* const q = toQQuickWebViewPrivate(clientInfo)->q_func();
459     ASSERT(!q->loading());
460
461     QWebLoadRequest loadRequest(q->url(), QQuickWebView::LoadSucceededStatus);
462     emit q->loadingChanged(&loadRequest);
463 }
464
465 void QQuickWebViewPrivate::didSameDocumentNavigationForFrame(WKPageRef, WKFrameRef frame, WKSameDocumentNavigationType type, WKTypeRef userData, const void* clientInfo)
466 {
467     if (!WKFrameIsMainFrame(frame))
468         return;
469     QQuickWebView* const q = toQQuickWebViewPrivate(clientInfo)->q_func();
470     q->emitUrlChangeIfNeeded();
471     emit q->navigationHistoryChanged();
472 }
473
474 void QQuickWebViewPrivate::didReceiveTitleForFrame(WKPageRef, WKStringRef title, WKFrameRef frame, WKTypeRef, const void* clientInfo)
475 {
476     if (!WKFrameIsMainFrame(frame))
477         return;
478     emit toQQuickWebViewPrivate(clientInfo)->q_func()->titleChanged();
479 }
480
481 void QQuickWebViewPrivate::didStartProgress(WKPageRef, const void* clientInfo)
482 {
483     toQQuickWebViewPrivate(clientInfo)->loadProgressDidChange(0);
484 }
485
486 void QQuickWebViewPrivate::didChangeProgress(WKPageRef page, const void* clientInfo)
487 {
488     toQQuickWebViewPrivate(clientInfo)->loadProgressDidChange(WKPageGetEstimatedProgress(page) * 100);
489 }
490
491 void QQuickWebViewPrivate::didFinishProgress(WKPageRef, const void* clientInfo)
492 {
493     toQQuickWebViewPrivate(clientInfo)->loadProgressDidChange(100);
494 }
495
496 void QQuickWebViewPrivate::didChangeBackForwardList(WKPageRef, WKBackForwardListItemRef, WKArrayRef, const void *clientInfo)
497 {
498     toQQuickWebViewPrivate(clientInfo)->navigationHistory->d->reset();
499 }
500
501 void QQuickWebViewPrivate::setTransparentBackground(bool enable)
502 {
503     webPageProxy->setDrawsTransparentBackground(enable);
504 }
505
506 bool QQuickWebViewPrivate::transparentBackground() const
507 {
508     return webPageProxy->drawsTransparentBackground();
509 }
510
511 void QQuickWebViewPrivate::loadProgressDidChange(int loadProgress)
512 {
513     Q_Q(QQuickWebView);
514
515     m_loadProgress = loadProgress;
516
517     emit q->loadProgressChanged();
518 }
519
520 void QQuickWebViewPrivate::handleMouseEvent(QMouseEvent* event)
521 {
522     switch (event->type()) {
523     case QEvent::MouseButtonPress:
524         pageView->eventHandler()->handleMousePressEvent(event);
525         break;
526     case QEvent::MouseMove:
527         pageView->eventHandler()->handleMouseMoveEvent(event);
528         break;
529     case QEvent::MouseButtonRelease:
530         pageView->eventHandler()->handleMouseReleaseEvent(event);
531         break;
532     case QEvent::MouseButtonDblClick:
533         // If a MouseButtonDblClick was received then we got a MouseButtonPress before.
534         // WebCore will build double-clicks out of press events.
535         event->accept();
536         break;
537     default:
538         ASSERT_NOT_REACHED();
539         break;
540     }
541 }
542
543 void QQuickWebViewPrivate::setNeedsDisplay()
544 {
545     Q_Q(QQuickWebView);
546     if (renderToOffscreenBuffer()) {
547         // This is used only to mantain the rendering synchronisation between the UI and
548         // the web process when running tests even if the render loop is not active.
549         QImage dummyImage(1, 1, QImage::Format_ARGB32);
550         QPainter painter(&dummyImage);
551         q->page()->d->paint(&painter);
552         return;
553     }
554     q->page()->update();
555 }
556
557 void QQuickWebViewPrivate::didRenderFrame()
558 {
559     Q_Q(QQuickWebView);
560     if (m_betweenLoadCommitAndFirstFrame) {
561         emit q->experimental()->loadVisuallyCommitted();
562         m_betweenLoadCommitAndFirstFrame = false;
563     }
564 }
565
566 void QQuickWebViewPrivate::processDidCrash()
567 {
568     Q_Q(QQuickWebView);
569
570     QUrl url(KURL(WebCore::ParsedURLString, webPageProxy->urlAtProcessExit()));
571     qWarning("WARNING: The web process experienced a crash on '%s'.", qPrintable(url.toString(QUrl::RemoveUserInfo)));
572
573     pageView->eventHandler()->resetGestureRecognizers();
574
575     // Check if loading was ongoing, when process crashed.
576     if (m_loadProgress > 0 && m_loadProgress < 100) {
577         QWebLoadRequest loadRequest(url, QQuickWebView::LoadFailedStatus, QLatin1String("The web process crashed."), QQuickWebView::InternalErrorDomain, 0);
578
579         loadProgressDidChange(100);
580         emit q->loadingChanged(&loadRequest);
581     }
582 }
583
584 void QQuickWebViewPrivate::didRelaunchProcess()
585 {
586     qWarning("WARNING: The web process has been successfully restarted.");
587
588     webPageProxy->drawingArea()->setSize(viewSize(), IntSize());
589
590     updateViewportSize();
591     updateUserScripts();
592     updateSchemeDelegates();
593 }
594
595 PassOwnPtr<DrawingAreaProxy> QQuickWebViewPrivate::createDrawingAreaProxy()
596 {
597     return DrawingAreaProxyImpl::create(webPageProxy.get());
598 }
599
600 void QQuickWebViewPrivate::handleDownloadRequest(DownloadProxy* download)
601 {
602     Q_Q(QQuickWebView);
603     // This function is responsible for hooking up a DownloadProxy to our API layer
604     // by creating a QWebDownloadItem. It will then wait for the QWebDownloadItem to be
605     // ready (filled with the ResourceResponse information) so we can pass it through to
606     // our WebViews.
607     QWebDownloadItem* downloadItem = new QWebDownloadItem();
608     downloadItem->d->downloadProxy = download;
609
610     q->connect(downloadItem->d, SIGNAL(receivedResponse(QWebDownloadItem*)), q, SLOT(_q_onReceivedResponseFromDownload(QWebDownloadItem*)));
611     QtWebContext::downloadManager()->addDownload(download, downloadItem);
612 }
613
614 void QQuickWebViewPrivate::_q_onVisibleChanged()
615 {
616     webPageProxy->viewStateDidChange(WebPageProxy::ViewIsVisible);
617 }
618
619 void QQuickWebViewPrivate::_q_onUrlChanged()
620 {
621     updateIcon();
622 }
623
624 void QQuickWebViewPrivate::_q_onIconChangedForPageURL(const QString& pageUrl)
625 {
626     if (pageUrl != QString(m_currentUrl))
627         return;
628
629     updateIcon();
630 }
631
632 /* Called either when the url changes, or when the icon for the current page changes */
633 void QQuickWebViewPrivate::updateIcon()
634 {
635     Q_Q(QQuickWebView);
636
637     QQuickView* view = qobject_cast<QQuickView*>(q->window());
638     if (!view)
639         return;
640
641     QWebIconImageProvider* provider = static_cast<QWebIconImageProvider*>(
642                 view->engine()->imageProvider(QWebIconImageProvider::identifier()));
643     if (!provider)
644         return;
645
646     WTF::String iconUrl = provider->iconURLForPageURLInContext(m_currentUrl, context.get());
647
648     if (iconUrl == m_iconUrl)
649         return;
650
651     m_iconUrl = iconUrl;
652     emit q->iconChanged();
653 }
654
655 void QQuickWebViewPrivate::_q_onReceivedResponseFromDownload(QWebDownloadItem* downloadItem)
656 {
657     // Now that our downloadItem has everything we need we can emit downloadRequested.
658     if (!downloadItem)
659         return;
660
661     Q_Q(QQuickWebView);
662     QQmlEngine::setObjectOwnership(downloadItem, QQmlEngine::JavaScriptOwnership);
663     emit q->experimental()->downloadRequested(downloadItem);
664 }
665
666 void QQuickWebViewPrivate::runJavaScriptAlert(const QString& alertText)
667 {
668     Q_Q(QQuickWebView);
669     QtDialogRunner dialogRunner(q);
670     if (!dialogRunner.initForAlert(alertText))
671         return;
672
673     dialogRunner.run();
674 }
675
676 bool QQuickWebViewPrivate::runJavaScriptConfirm(const QString& message)
677 {
678     Q_Q(QQuickWebView);
679     QtDialogRunner dialogRunner(q);
680     if (!dialogRunner.initForConfirm(message))
681         return true;
682
683     dialogRunner.run();
684
685     return dialogRunner.wasAccepted();
686 }
687
688 QString QQuickWebViewPrivate::runJavaScriptPrompt(const QString& message, const QString& defaultValue, bool& ok)
689 {
690     Q_Q(QQuickWebView);
691     QtDialogRunner dialogRunner(q);
692     if (!dialogRunner.initForPrompt(message, defaultValue)) {
693         ok = true;
694         return defaultValue;
695     }
696
697     dialogRunner.run();
698
699     ok = dialogRunner.wasAccepted();
700     return dialogRunner.result();
701 }
702
703 void QQuickWebViewPrivate::handleAuthenticationRequiredRequest(const QString& hostname, const QString& realm, const QString& prefilledUsername, QString& username, QString& password)
704 {
705     Q_Q(QQuickWebView);
706     QtDialogRunner dialogRunner(q);
707     if (!dialogRunner.initForAuthentication(hostname, realm, prefilledUsername))
708         return;
709
710     dialogRunner.run();
711
712     username = dialogRunner.username();
713     password = dialogRunner.password();
714 }
715
716 void QQuickWebViewPrivate::handleProxyAuthenticationRequiredRequest(const QString& hostname, uint16_t port, const QString& prefilledUsername, QString& username, QString& password)
717 {
718     Q_Q(QQuickWebView);
719     QtDialogRunner dialogRunner(q);
720     if (!dialogRunner.initForProxyAuthentication(hostname, port, prefilledUsername))
721         return;
722
723     dialogRunner.run();
724
725     username = dialogRunner.username();
726     password = dialogRunner.password();
727 }
728
729 bool QQuickWebViewPrivate::handleCertificateVerificationRequest(const QString& hostname)
730 {
731     Q_Q(QQuickWebView);
732
733     if (m_allowAnyHTTPSCertificateForLocalHost
734         && (hostname == QStringLiteral("127.0.0.1") || hostname == QStringLiteral("localhost")))
735         return true;
736
737     QtDialogRunner dialogRunner(q);
738     if (!dialogRunner.initForCertificateVerification(hostname))
739         return false;
740
741     dialogRunner.run();
742
743     return dialogRunner.wasAccepted();
744 }
745
746 void QQuickWebViewPrivate::chooseFiles(WKOpenPanelResultListenerRef listenerRef, const QStringList& selectedFileNames, QtWebPageUIClient::FileChooserType type)
747 {
748     Q_Q(QQuickWebView);
749
750     QtDialogRunner dialogRunner(q);
751     if (!dialogRunner.initForFilePicker(selectedFileNames, (type == QtWebPageUIClient::MultipleFilesSelection)))
752         return;
753
754     dialogRunner.run();
755
756     if (dialogRunner.wasAccepted()) {
757         QStringList selectedPaths = dialogRunner.filePaths();
758
759         Vector<RefPtr<APIObject> > wkFiles(selectedPaths.size());
760         for (unsigned i = 0; i < selectedPaths.size(); ++i)
761             wkFiles[i] = WebURL::create(QUrl::fromLocalFile(selectedPaths.at(i)).toString());            
762
763         WKOpenPanelResultListenerChooseFiles(listenerRef, toAPI(ImmutableArray::adopt(wkFiles).leakRef()));
764     } else
765         WKOpenPanelResultListenerCancel(listenerRef);
766
767 }
768
769 quint64 QQuickWebViewPrivate::exceededDatabaseQuota(const QString& databaseName, const QString& displayName, WKSecurityOriginRef securityOrigin, quint64 currentQuota, quint64 currentOriginUsage, quint64 currentDatabaseUsage, quint64 expectedUsage)
770 {
771     Q_Q(QQuickWebView);
772     QtDialogRunner dialogRunner(q);
773     if (!dialogRunner.initForDatabaseQuotaDialog(databaseName, displayName, securityOrigin, currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage))
774         return 0;
775
776     dialogRunner.run();
777
778     return dialogRunner.wasAccepted() ? dialogRunner.databaseQuota() : 0;
779 }
780
781 /* The 'WebView' attached property allows items spawned by the webView to
782    refer back to the originating webView through 'WebView.view', similar
783    to how ListView.view and GridView.view is exposed to items. */
784 QQuickWebViewAttached::QQuickWebViewAttached(QObject* object)
785     : QObject(object)
786     , m_view(0)
787 {
788 }
789
790 void QQuickWebViewAttached::setView(QQuickWebView* view)
791 {
792     if (m_view == view)
793         return;
794     m_view = view;
795     emit viewChanged();
796 }
797
798 QQuickWebViewAttached* QQuickWebView::qmlAttachedProperties(QObject* object)
799 {
800     return new QQuickWebViewAttached(object);
801 }
802
803
804
805 void QQuickWebViewPrivate::addAttachedPropertyTo(QObject* object)
806 {
807     Q_Q(QQuickWebView);
808     QQuickWebViewAttached* attached = static_cast<QQuickWebViewAttached*>(qmlAttachedPropertiesObject<QQuickWebView>(object));
809     attached->setView(q);
810 }
811
812 bool QQuickWebViewPrivate::navigatorQtObjectEnabled() const
813 {
814     return m_navigatorQtObjectEnabled;
815 }
816
817 void QQuickWebViewPrivate::setNavigatorQtObjectEnabled(bool enabled)
818 {
819     ASSERT(enabled != m_navigatorQtObjectEnabled);
820     // FIXME: Currently we have to keep this information in both processes and the setting is asynchronous.
821     m_navigatorQtObjectEnabled = enabled;
822
823     static String messageName("SetNavigatorQtObjectEnabled");
824     RefPtr<WebBoolean> webEnabled = WebBoolean::create(enabled);
825     webPageProxy->postMessageToInjectedBundle(messageName, webEnabled.get());
826 }
827
828 static WKRetainPtr<WKStringRef> readUserScript(const QUrl& url)
829 {
830     QString path;
831     if (url.isLocalFile())
832         path = url.toLocalFile();
833     else if (url.scheme() == QLatin1String("qrc"))
834         path = QStringLiteral(":") + url.path();
835     else {
836         qWarning("QQuickWebView: Couldn't open '%s' as user script because only file:/// and qrc:/// URLs are supported.", qPrintable(url.toString()));
837         return 0;
838     }
839
840     QFile file(path);
841     if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
842         qWarning("QQuickWebView: Couldn't open '%s' as user script due to error '%s'.", qPrintable(url.toString()), qPrintable(file.errorString()));
843         return 0;
844     }
845
846     QByteArray contents = file.readAll();
847     if (contents.isEmpty())
848         qWarning("QQuickWebView: Ignoring '%s' as user script because file is empty.", qPrintable(url.toString()));
849
850     return adoptWK(WKStringCreateWithUTF8CString(contents.constData()));
851 }
852
853 void QQuickWebViewPrivate::updateUserScripts()
854 {
855     // This feature works per-WebView because we keep an unique page group for
856     // each Page/WebView pair we create.
857     WKPageGroupRemoveAllUserScripts(pageGroup.get());
858
859     for (unsigned i = 0; i < userScripts.size(); ++i) {
860         const QUrl& url = userScripts.at(i);
861         if (!url.isValid()) {
862             qWarning("QQuickWebView: Couldn't open '%s' as user script because URL is invalid.", qPrintable(url.toString()));
863             continue;
864         }
865
866         WKRetainPtr<WKStringRef> contents = readUserScript(url);
867         if (!contents || WKStringIsEmpty(contents.get()))
868             continue;
869         WKPageGroupAddUserScript(pageGroup.get(), contents.get(), /*baseURL*/ 0, /*whitelistedURLPatterns*/ 0, /*blacklistedURLPatterns*/ 0, kWKInjectInTopFrameOnly, kWKInjectAtDocumentEnd);
870     }
871 }
872
873 void QQuickWebViewPrivate::updateSchemeDelegates()
874 {
875     webPageProxy->registerApplicationScheme(ASCIILiteral("qrc"));
876
877     QQmlListProperty<QQuickUrlSchemeDelegate> schemes = experimental->schemeDelegates();
878     for (int i = 0, numSchemes = experimental->schemeDelegates_Count(&schemes); i < numSchemes; ++i) {
879         QQuickUrlSchemeDelegate* scheme = experimental->schemeDelegates_At(&schemes, i);
880         webPageProxy->registerApplicationScheme(scheme->scheme());
881     }
882 }
883
884 QPointF QQuickWebViewPrivate::contentPos() const
885 {
886     Q_Q(const QQuickWebView);
887     return QPointF(q->contentX(), q->contentY());
888 }
889
890 void QQuickWebViewPrivate::setContentPos(const QPointF& pos)
891 {
892     Q_Q(QQuickWebView);
893     q->setContentX(pos.x());
894     q->setContentY(pos.y());
895 }
896
897 WebCore::IntSize QQuickWebViewPrivate::viewSize() const
898 {
899     return WebCore::IntSize(pageView->width(), pageView->height());
900 }
901
902 /*!
903     \internal
904
905     \qmlsignal WebViewExperimental::onMessageReceived(var message)
906
907     \brief Emitted when JavaScript code executing on the web page calls navigator.qt.postMessage().
908
909     \sa postMessage
910 */
911 void QQuickWebViewPrivate::didReceiveMessageFromNavigatorQtObject(const String& message)
912 {
913     QVariantMap variantMap;
914     variantMap.insert(QLatin1String("data"), QString(message));
915     variantMap.insert(QLatin1String("origin"), q_ptr->url());
916     emit q_ptr->experimental()->messageReceived(variantMap);
917 }
918
919 QQuickWebViewLegacyPrivate::QQuickWebViewLegacyPrivate(QQuickWebView* viewport)
920     : QQuickWebViewPrivate(viewport)
921 {
922 }
923
924 void QQuickWebViewLegacyPrivate::initialize(WKContextRef contextRef, WKPageGroupRef pageGroupRef)
925 {
926     QQuickWebViewPrivate::initialize(contextRef, pageGroupRef);
927
928     // Trigger setting of correct visibility flags after everything was allocated and initialized.
929     _q_onVisibleChanged();
930 }
931
932 void QQuickWebViewLegacyPrivate::updateViewportSize()
933 {
934     Q_Q(QQuickWebView);
935     QSizeF viewportSize = q->boundingRect().size();
936     if (viewportSize.isEmpty())
937         return;
938
939     pageView->setContentsSize(viewportSize);
940
941     // The fixed layout is handled by the FrameView and the drawing area doesn't behave differently
942     // whether its fixed or not. We still need to tell the drawing area which part of it
943     // has to be rendered on tiles, and in desktop mode it's all of it.
944     webPageProxy->drawingArea()->setSize(viewportSize.toSize(), IntSize());
945     // The backing store scale factor should already be set to the device pixel ratio
946     // of the underlying window, thus we set the effective scale to 1 here.
947     webPageProxy->drawingArea()->setVisibleContentsRect(FloatRect(FloatPoint(), FloatSize(viewportSize)), FloatPoint());
948 }
949
950 qreal QQuickWebViewLegacyPrivate::zoomFactor() const
951 {
952     return WKPageGetPageZoomFactor(webPage.get());
953 }
954
955 void QQuickWebViewLegacyPrivate::setZoomFactor(qreal factor)
956 {
957     WKPageSetPageZoomFactor(webPage.get(), factor);
958 }
959
960 QQuickWebViewFlickablePrivate::QQuickWebViewFlickablePrivate(QQuickWebView* viewport)
961     : QQuickWebViewPrivate(viewport)
962 {
963 }
964
965 void QQuickWebViewFlickablePrivate::initialize(WKContextRef contextRef, WKPageGroupRef pageGroupRef)
966 {
967     QQuickWebViewPrivate::initialize(contextRef, pageGroupRef);
968 }
969
970 void QQuickWebViewFlickablePrivate::onComponentComplete()
971 {
972     QQuickWebViewPrivate::onComponentComplete();
973
974     Q_Q(QQuickWebView);
975     m_pageViewportControllerClient.reset(new PageViewportControllerClientQt(q, pageView.data()));
976     m_pageViewportController.reset(new PageViewportController(webPageProxy.get(), m_pageViewportControllerClient.data()));
977     pageView->eventHandler()->setViewportController(m_pageViewportControllerClient.data());
978
979     // Trigger setting of correct visibility flags after everything was allocated and initialized.
980     _q_onVisibleChanged();
981 }
982
983 void QQuickWebViewFlickablePrivate::didChangeViewportProperties(const WebCore::ViewportAttributes& newAttributes)
984 {
985     if (m_pageViewportController)
986         m_pageViewportController->didChangeViewportAttributes(newAttributes);
987 }
988
989 void QQuickWebViewFlickablePrivate::updateViewportSize()
990 {
991     Q_Q(QQuickWebView);
992
993     if (m_pageViewportController)
994         m_pageViewportController->didChangeViewportSize(FloatSize(q->width(), q->height()));
995 }
996
997 void QQuickWebViewFlickablePrivate::pageDidRequestScroll(const QPoint& pos)
998 {
999     if (m_pageViewportController)
1000         m_pageViewportController->pageDidRequestScroll(pos);
1001 }
1002
1003 QQuickWebViewExperimental::QQuickWebViewExperimental(QQuickWebView *webView, QQuickWebViewPrivate* webViewPrivate)
1004     : QObject(webView)
1005     , q_ptr(webView)
1006     , d_ptr(webViewPrivate)
1007     , schemeParent(new QObject(this))
1008     , m_test(new QWebKitTest(webViewPrivate, this))
1009 {
1010 }
1011
1012 QQuickWebViewExperimental::~QQuickWebViewExperimental()
1013 {
1014 }
1015
1016 void QQuickWebViewExperimental::setRenderToOffscreenBuffer(bool enable)
1017 {
1018     Q_D(QQuickWebView);
1019     d->setRenderToOffscreenBuffer(enable);
1020 }
1021
1022 bool QQuickWebViewExperimental::renderToOffscreenBuffer() const
1023 {
1024     Q_D(const QQuickWebView);
1025     return d->renderToOffscreenBuffer();
1026 }
1027
1028 bool QQuickWebViewExperimental::transparentBackground() const
1029 {
1030     Q_D(const QQuickWebView);
1031     return d->transparentBackground();
1032 }
1033 void QQuickWebViewExperimental::setTransparentBackground(bool enable)
1034 {
1035     Q_D(QQuickWebView);
1036     d->setTransparentBackground(enable);
1037 }
1038
1039 bool QQuickWebViewExperimental::useDefaultContentItemSize() const
1040 {
1041     Q_D(const QQuickWebView);
1042     return d->m_useDefaultContentItemSize;
1043 }
1044
1045 void QQuickWebViewExperimental::setUseDefaultContentItemSize(bool enable)
1046 {
1047     Q_D(QQuickWebView);
1048     d->m_useDefaultContentItemSize = enable;
1049 }
1050
1051 /*!
1052     \internal
1053
1054     \qmlproperty int WebViewExperimental::preferredMinimumContentsWidth
1055     \brief Minimum contents width when not overriden by the page itself.
1056
1057     Unless the page defines how contents should be laid out, using e.g.
1058     the viewport meta tag, it is laid out given the width of the viewport
1059     (in CSS units).
1060
1061     This setting can be used to enforce a minimum width when the page
1062     does not define a width itself. This is useful for laying out pages
1063     designed for big screens, commonly knows as desktop pages, on small
1064     devices.
1065
1066     The default value is 0, but the value of 980 is recommented for small
1067     screens as it provides a good trade off between legitable pages and
1068     non-broken content.
1069  */
1070 int QQuickWebViewExperimental::preferredMinimumContentsWidth() const
1071 {
1072     Q_D(const QQuickWebView);
1073     return d->webPageProxy->pageGroup()->preferences()->layoutFallbackWidth();
1074 }
1075
1076 void QQuickWebViewExperimental::setPreferredMinimumContentsWidth(int width)
1077 {
1078     Q_D(QQuickWebView);
1079     WebPreferences* webPreferences = d->webPageProxy->pageGroup()->preferences();
1080
1081     if (width == webPreferences->layoutFallbackWidth())
1082         return;
1083
1084     webPreferences->setLayoutFallbackWidth(width);
1085     emit preferredMinimumContentsWidthChanged();
1086 }
1087
1088 void QQuickWebViewExperimental::setFlickableViewportEnabled(bool enable)
1089 {
1090     s_flickableViewportEnabled = enable;
1091 }
1092
1093 bool QQuickWebViewExperimental::flickableViewportEnabled()
1094 {
1095     return s_flickableViewportEnabled;
1096 }
1097
1098 /*!
1099     \internal
1100
1101     \qmlmethod void WebViewExperimental::postMessage(string message)
1102
1103     \brief Post a message to an onmessage function registered with the navigator.qt object
1104            by JavaScript code executing on the page.
1105
1106     \sa onMessageReceived
1107 */
1108
1109 void QQuickWebViewExperimental::postMessage(const QString& message)
1110 {
1111     Q_D(QQuickWebView);
1112     static WKStringRef messageName = WKStringCreateWithUTF8CString("MessageToNavigatorQtObject");
1113     WKRetainPtr<WKStringRef> contents = adoptWK(WKStringCreateWithQString(message));
1114     WKPagePostMessageToInjectedBundle(d->webPage.get(), messageName, contents.get());
1115 }
1116
1117 QQmlComponent* QQuickWebViewExperimental::alertDialog() const
1118 {
1119     Q_D(const QQuickWebView);
1120     return d->alertDialog;
1121 }
1122
1123 void QQuickWebViewExperimental::setAlertDialog(QQmlComponent* alertDialog)
1124 {
1125     Q_D(QQuickWebView);
1126     if (d->alertDialog == alertDialog)
1127         return;
1128     d->alertDialog = alertDialog;
1129     emit alertDialogChanged();
1130 }
1131
1132 QQmlComponent* QQuickWebViewExperimental::confirmDialog() const
1133 {
1134     Q_D(const QQuickWebView);
1135     return d->confirmDialog;
1136 }
1137
1138 void QQuickWebViewExperimental::setConfirmDialog(QQmlComponent* confirmDialog)
1139 {
1140     Q_D(QQuickWebView);
1141     if (d->confirmDialog == confirmDialog)
1142         return;
1143     d->confirmDialog = confirmDialog;
1144     emit confirmDialogChanged();
1145 }
1146
1147 QWebNavigationHistory* QQuickWebViewExperimental::navigationHistory() const
1148 {
1149     return d_ptr->navigationHistory.get();
1150 }
1151
1152 QQmlComponent* QQuickWebViewExperimental::promptDialog() const
1153 {
1154     Q_D(const QQuickWebView);
1155     return d->promptDialog;
1156 }
1157
1158 QWebPreferences* QQuickWebViewExperimental::preferences() const
1159 {
1160     QQuickWebViewPrivate* const d = d_ptr;
1161     if (!d->preferences)
1162         d->preferences = adoptPtr(QWebPreferencesPrivate::createPreferences(d));
1163     return d->preferences.get();
1164 }
1165
1166 void QQuickWebViewExperimental::setPromptDialog(QQmlComponent* promptDialog)
1167 {
1168     Q_D(QQuickWebView);
1169     if (d->promptDialog == promptDialog)
1170         return;
1171     d->promptDialog = promptDialog;
1172     emit promptDialogChanged();
1173 }
1174
1175 QQmlComponent* QQuickWebViewExperimental::authenticationDialog() const
1176 {
1177     Q_D(const QQuickWebView);
1178     return d->authenticationDialog;
1179 }
1180
1181 void QQuickWebViewExperimental::setAuthenticationDialog(QQmlComponent* authenticationDialog)
1182 {
1183     Q_D(QQuickWebView);
1184     if (d->authenticationDialog == authenticationDialog)
1185         return;
1186     d->authenticationDialog = authenticationDialog;
1187     emit authenticationDialogChanged();
1188 }
1189
1190 QQmlComponent* QQuickWebViewExperimental::proxyAuthenticationDialog() const
1191 {
1192     Q_D(const QQuickWebView);
1193     return d->proxyAuthenticationDialog;
1194 }
1195
1196 void QQuickWebViewExperimental::setProxyAuthenticationDialog(QQmlComponent* proxyAuthenticationDialog)
1197 {
1198     Q_D(QQuickWebView);
1199     if (d->proxyAuthenticationDialog == proxyAuthenticationDialog)
1200         return;
1201     d->proxyAuthenticationDialog = proxyAuthenticationDialog;
1202     emit proxyAuthenticationDialogChanged();
1203 }
1204 QQmlComponent* QQuickWebViewExperimental::certificateVerificationDialog() const
1205 {
1206     Q_D(const QQuickWebView);
1207     return d->certificateVerificationDialog;
1208 }
1209
1210 void QQuickWebViewExperimental::setCertificateVerificationDialog(QQmlComponent* certificateVerificationDialog)
1211 {
1212     Q_D(QQuickWebView);
1213     if (d->certificateVerificationDialog == certificateVerificationDialog)
1214         return;
1215     d->certificateVerificationDialog = certificateVerificationDialog;
1216     emit certificateVerificationDialogChanged();
1217 }
1218
1219 QQmlComponent* QQuickWebViewExperimental::itemSelector() const
1220 {
1221     Q_D(const QQuickWebView);
1222     return d->itemSelector;
1223 }
1224
1225 void QQuickWebViewExperimental::setItemSelector(QQmlComponent* itemSelector)
1226 {
1227     Q_D(QQuickWebView);
1228     if (d->itemSelector == itemSelector)
1229         return;
1230     d->itemSelector = itemSelector;
1231     emit itemSelectorChanged();
1232 }
1233
1234 QQmlComponent* QQuickWebViewExperimental::filePicker() const
1235 {
1236     Q_D(const QQuickWebView);
1237     return d->filePicker;
1238 }
1239
1240 void QQuickWebViewExperimental::setFilePicker(QQmlComponent* filePicker)
1241 {
1242     Q_D(QQuickWebView);
1243     if (d->filePicker == filePicker)
1244         return;
1245     d->filePicker = filePicker;
1246     emit filePickerChanged();
1247 }
1248
1249 QQmlComponent* QQuickWebViewExperimental::databaseQuotaDialog() const
1250 {
1251     Q_D(const QQuickWebView);
1252     return d->databaseQuotaDialog;
1253 }
1254
1255 void QQuickWebViewExperimental::setDatabaseQuotaDialog(QQmlComponent* databaseQuotaDialog)
1256 {
1257     Q_D(QQuickWebView);
1258     if (d->databaseQuotaDialog == databaseQuotaDialog)
1259         return;
1260     d->databaseQuotaDialog = databaseQuotaDialog;
1261     emit databaseQuotaDialogChanged();
1262 }
1263
1264 QQmlComponent* QQuickWebViewExperimental::colorChooser() const
1265 {
1266     Q_D(const QQuickWebView);
1267     return d->colorChooser;
1268 }
1269
1270 void QQuickWebViewExperimental::setColorChooser(QQmlComponent* colorChooser)
1271 {
1272     Q_D(QQuickWebView);
1273     if (d->colorChooser == colorChooser)
1274         return;
1275
1276     d->colorChooser = colorChooser;
1277     emit colorChooserChanged();
1278 }
1279
1280 QString QQuickWebViewExperimental::userAgent() const
1281 {
1282     Q_D(const QQuickWebView);
1283     WKRetainPtr<WKStringRef> ua = adoptWK(WKPageCopyCustomUserAgent(d->webPage.get()));
1284     return WKStringCopyQString(ua.get());
1285 }
1286
1287 void QQuickWebViewExperimental::setUserAgent(const QString& userAgent)
1288 {
1289     Q_D(QQuickWebView);
1290     WKRetainPtr<WKStringRef> newUserAgent = adoptWK(WKStringCreateWithQString(userAgent));
1291     WKRetainPtr<WKStringRef> currentUserAgent = adoptWK(WKPageCopyCustomUserAgent(d->webPage.get()));
1292     if (WKStringIsEqual(newUserAgent.get(), currentUserAgent.get()))
1293         return;
1294
1295     WKPageSetCustomUserAgent(d->webPage.get(), newUserAgent.get());
1296     emit userAgentChanged();
1297 }
1298
1299 /*!
1300     \internal
1301
1302     \qmlproperty int WebViewExperimental::deviceWidth
1303     \brief The device width used by the viewport calculations.
1304
1305     The value used when calculation the viewport, eg. what is used for 'device-width' when
1306     used in the viewport meta tag. If unset (zero or negative width), the width of the
1307     actual viewport is used instead.
1308 */
1309
1310 int QQuickWebViewExperimental::deviceWidth() const
1311 {
1312     Q_D(const QQuickWebView);
1313     return d->webPageProxy->pageGroup()->preferences()->deviceWidth();
1314 }
1315
1316 void QQuickWebViewExperimental::setDeviceWidth(int value)
1317 {
1318     Q_D(QQuickWebView);
1319     d->webPageProxy->pageGroup()->preferences()->setDeviceWidth(qMax(0, value));
1320     emit deviceWidthChanged();
1321 }
1322
1323 /*!
1324     \internal
1325
1326     \qmlproperty int WebViewExperimental::deviceHeight
1327     \brief The device width used by the viewport calculations.
1328
1329     The value used when calculation the viewport, eg. what is used for 'device-height' when
1330     used in the viewport meta tag. If unset (zero or negative height), the height of the
1331     actual viewport is used instead.
1332 */
1333
1334 int QQuickWebViewExperimental::deviceHeight() const
1335 {
1336     Q_D(const QQuickWebView);
1337     return d->webPageProxy->pageGroup()->preferences()->deviceHeight();
1338 }
1339
1340 void QQuickWebViewExperimental::setDeviceHeight(int value)
1341 {
1342     Q_D(QQuickWebView);
1343     d->webPageProxy->pageGroup()->preferences()->setDeviceHeight(qMax(0, value));
1344     emit deviceHeightChanged();
1345 }
1346
1347 /*!
1348     \internal
1349
1350     \qmlmethod void WebViewExperimental::evaluateJavaScript(string script [, function(result)])
1351
1352     \brief Evaluates the specified JavaScript and, if supplied, calls a function with the result.
1353 */
1354
1355 void QQuickWebViewExperimental::evaluateJavaScript(const QString& script, const QJSValue& value)
1356 {
1357     JSCallbackClosure* closure = new JSCallbackClosure;
1358
1359     closure->receiver = this;
1360     closure->value = value;
1361
1362     WKRetainPtr<WKStringRef> scriptString = adoptWK(WKStringCreateWithQString(script));
1363     WKPageRunJavaScriptInMainFrame(d_ptr->webPage.get(), scriptString.get(), closure, javaScriptCallback);
1364 }
1365
1366 void QQuickWebViewExperimental::findText(const QString& string, FindFlags options)
1367 {
1368     Q_D(QQuickWebView);
1369     if (string.isEmpty()) {
1370         WKPageHideFindUI(d->webPage.get());
1371         return;
1372     }
1373
1374     WKFindOptions wkOptions = kWKFindOptionsCaseInsensitive;
1375     if (options & FindCaseSensitively)
1376         wkOptions = wkOptions & ~kWKFindOptionsCaseInsensitive;
1377     if (options & FindBackward)
1378         wkOptions |= kWKFindOptionsBackwards;
1379     if (options & FindWrapsAroundDocument)
1380         wkOptions |= kWKFindOptionsWrapAround;
1381     if (options & FindHighlightAllOccurrences)
1382         wkOptions |= kWKFindOptionsShowHighlight;
1383
1384     WKRetainPtr<WKStringRef> str = adoptWK(WKStringCreateWithQString(string));
1385
1386     WKPageFindString(d->webPage.get(), str.get(), wkOptions, std::numeric_limits<unsigned>::max() - 1);
1387 }
1388
1389 QList<QUrl> QQuickWebViewExperimental::userScripts() const
1390 {
1391     Q_D(const QQuickWebView);
1392     return d->userScripts;
1393 }
1394
1395 void QQuickWebViewExperimental::setUserScripts(const QList<QUrl>& userScripts)
1396 {
1397     Q_D(QQuickWebView);
1398     if (d->userScripts == userScripts)
1399         return;
1400     d->userScripts = userScripts;
1401     d->updateUserScripts();
1402     emit userScriptsChanged();
1403 }
1404
1405 QUrl QQuickWebViewExperimental::remoteInspectorUrl() const
1406 {
1407 #if ENABLE(INSPECTOR_SERVER)
1408     return QUrl(WebInspectorServer::shared().inspectorUrlForPageID(d_ptr->webPageProxy->inspector()->remoteInspectionPageID()));
1409 #else
1410     return QUrl();
1411 #endif
1412 }
1413
1414 QQuickUrlSchemeDelegate* QQuickWebViewExperimental::schemeDelegates_At(QQmlListProperty<QQuickUrlSchemeDelegate>* property, int index)
1415 {
1416     const QObjectList children = property->object->children();
1417     if (index < children.count())
1418         return static_cast<QQuickUrlSchemeDelegate*>(children.at(index));
1419     return 0;
1420 }
1421
1422 void QQuickWebViewExperimental::schemeDelegates_Append(QQmlListProperty<QQuickUrlSchemeDelegate>* property, QQuickUrlSchemeDelegate *scheme)
1423 {
1424     if (!scheme->scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive)) {
1425         qWarning("WARNING: The qrc scheme is reserved to be handled internally. The handler will be ignored.");
1426         delete scheme;
1427         return;
1428     }
1429
1430     QObject* schemeParent = property->object;
1431     scheme->setParent(schemeParent);
1432     QQuickWebViewExperimental* webViewExperimental = qobject_cast<QQuickWebViewExperimental*>(property->object->parent());
1433     if (!webViewExperimental)
1434         return;
1435     scheme->reply()->setWebViewExperimental(webViewExperimental);
1436     QQuickWebViewPrivate* d = webViewExperimental->d_func();
1437     d->webPageProxy->registerApplicationScheme(scheme->scheme());
1438 }
1439
1440 int QQuickWebViewExperimental::schemeDelegates_Count(QQmlListProperty<QQuickUrlSchemeDelegate>* property)
1441 {
1442     return property->object->children().count();
1443 }
1444
1445 void QQuickWebViewExperimental::schemeDelegates_Clear(QQmlListProperty<QQuickUrlSchemeDelegate>* property)
1446 {
1447     const QObjectList children = property->object->children();
1448     for (int index = 0; index < children.count(); index++) {
1449         QObject* child = children.at(index);
1450         child->setParent(0);
1451         delete child;
1452     }
1453 }
1454
1455 QQmlListProperty<QQuickUrlSchemeDelegate> QQuickWebViewExperimental::schemeDelegates()
1456 {
1457     return QQmlListProperty<QQuickUrlSchemeDelegate>(schemeParent, 0,
1458             QQuickWebViewExperimental::schemeDelegates_Append,
1459             QQuickWebViewExperimental::schemeDelegates_Count,
1460             QQuickWebViewExperimental::schemeDelegates_At,
1461             QQuickWebViewExperimental::schemeDelegates_Clear);
1462 }
1463
1464 void QQuickWebViewExperimental::invokeApplicationSchemeHandler(PassRefPtr<QtRefCountedNetworkRequestData> request)
1465 {
1466     RefPtr<QtRefCountedNetworkRequestData> req = request;
1467     if (req->data().m_scheme.startsWith("qrc", false)) {
1468         QQuickQrcSchemeDelegate qrcDelegate(QUrl(QString(req->data().m_urlString)));
1469         qrcDelegate.request()->setNetworkRequestData(req);
1470         qrcDelegate.reply()->setNetworkRequestData(req);
1471         qrcDelegate.reply()->setWebViewExperimental(this);
1472         qrcDelegate.readResourceAndSend();
1473         return;
1474     }
1475
1476     const QObjectList children = schemeParent->children();
1477     for (int index = 0; index < children.count(); index++) {
1478         QQuickUrlSchemeDelegate* delegate = qobject_cast<QQuickUrlSchemeDelegate*>(children.at(index));
1479         if (!delegate)
1480             continue;
1481         if (!delegate->scheme().compare(QString(req->data().m_scheme), Qt::CaseInsensitive)) {
1482             delegate->request()->setNetworkRequestData(req);
1483             delegate->reply()->setNetworkRequestData(req);
1484             emit delegate->receivedRequest();
1485             return;
1486         }
1487     }
1488 }
1489
1490 void QQuickWebViewExperimental::sendApplicationSchemeReply(QQuickNetworkReply* reply)
1491 {
1492     d_ptr->webPageProxy->sendApplicationSchemeReply(reply);
1493 }
1494
1495 void QQuickWebViewExperimental::goForwardTo(int index)
1496 {
1497     d_ptr->navigationHistory->d->goForwardTo(index);
1498 }
1499
1500 void QQuickWebViewExperimental::goBackTo(int index)
1501 {
1502     d_ptr->navigationHistory->d->goBackTo(index);
1503 }
1504
1505 QWebKitTest* QQuickWebViewExperimental::test()
1506 {
1507     return m_test;
1508 }
1509
1510 QQuickWebPage* QQuickWebViewExperimental::page()
1511 {
1512     return q_ptr->page();
1513 }
1514
1515 /*!
1516     \page index.html
1517     \title QtWebKit: QML WebView version 3.0
1518
1519     The WebView API allows QML applications to render regions of dynamic
1520     web content. A \e{WebView} component may share the screen with other
1521     QML components or encompass the full screen as specified within the
1522     QML application.
1523
1524     QML WebView version 3.0 is incompatible with previous QML \l
1525     {QtWebKit1::WebView} {WebView} API versions.  It allows an
1526     application to load pages into the WebView, either by URL or with
1527     an HTML string, and navigate within session history.  By default,
1528     links to different pages load within the same WebView, but applications
1529     may intercept requests to delegate links to other functions.
1530
1531     This sample QML application loads a web page, responds to session
1532     history context, and intercepts requests for external links:
1533
1534     \code
1535     import QtQuick 2.0
1536     import QtWebKit 3.0
1537
1538     Page {
1539         WebView {
1540             id: webview
1541             url: "http://qt-project.org"
1542             width: parent.width
1543             height: parent.height
1544             onNavigationRequested: {
1545                 // detect URL scheme prefix, most likely an external link
1546                 var schemaRE = /^\w+:/;
1547                 if (schemaRE.test(request.url)) {
1548                     request.action = WebView.AcceptRequest;
1549                 } else {
1550                     request.action = WebView.IgnoreRequest;
1551                     // delegate request.url here
1552                 }
1553             }
1554         }
1555     }
1556     \endcode
1557
1558     \section1 Examples
1559
1560     There are several Qt WebKit examples located in the
1561     \l{Qt WebKit Examples} page.
1562
1563 */
1564
1565
1566 /*!
1567     \qmltype WebView
1568     \instantiates QQuickWebView
1569     \inqmlmodule QtWebKit 3.0
1570     \brief A WebView renders web content within a QML application
1571 */
1572
1573 QQuickWebView::QQuickWebView(QQuickItem* parent)
1574     : QQuickFlickable(parent)
1575     , d_ptr(createPrivateObject(this))
1576 {
1577     Q_D(QQuickWebView);
1578     d->initialize();
1579 }
1580
1581 QQuickWebView::QQuickWebView(WKContextRef contextRef, WKPageGroupRef pageGroupRef, QQuickItem* parent)
1582     : QQuickFlickable(parent)
1583     , d_ptr(createPrivateObject(this))
1584 {
1585     Q_D(QQuickWebView);
1586     d->initialize(contextRef, pageGroupRef);
1587 }
1588
1589 QQuickWebView::~QQuickWebView()
1590 {
1591 }
1592
1593 QQuickWebPage* QQuickWebView::page()
1594 {
1595     Q_D(QQuickWebView);
1596     return d->pageView.data();
1597 }
1598
1599 /*!
1600     \qmlmethod void WebView::goBack()
1601
1602     Go backward within the browser's session history, if possible.
1603     (Equivalent to the \c{window.history.back()} DOM method.)
1604
1605     \sa WebView::canGoBack
1606 */
1607 void QQuickWebView::goBack()
1608 {
1609     Q_D(QQuickWebView);
1610     WKPageGoBack(d->webPage.get());
1611 }
1612
1613 /*!
1614     \qmlmethod void WebView::goForward()
1615
1616     Go forward within the browser's session history, if possible.
1617     (Equivalent to the \c{window.history.forward()} DOM method.)
1618 */
1619 void QQuickWebView::goForward()
1620 {
1621     Q_D(QQuickWebView);
1622     WKPageGoForward(d->webPage.get());
1623 }
1624
1625 /*!
1626     \qmlmethod void WebView::stop()
1627
1628     Stop loading the current page.
1629 */
1630 void QQuickWebView::stop()
1631 {
1632     Q_D(QQuickWebView);
1633     WKPageStopLoading(d->webPage.get());
1634 }
1635
1636 /*!
1637     \qmlmethod void WebView::reload()
1638
1639     Reload the current page. (Equivalent to the
1640     \c{window.location.reload()} DOM method.)
1641 */
1642 void QQuickWebView::reload()
1643 {
1644     Q_D(QQuickWebView);
1645
1646     WebFrameProxy* mainFrame = d->webPageProxy->mainFrame();
1647     if (mainFrame && !mainFrame->unreachableURL().isEmpty() && mainFrame->url() != blankURL()) {
1648         // We are aware of the unreachable url on the UI process side, but since we haven't
1649         // loaded alternative/subsitute data for it (an error page eg.) WebCore doesn't know
1650         // about the unreachable url yet. If we just do a reload at this point WebCore will try to
1651         // reload the currently committed url instead of the unrachable url. To work around this
1652         // we override the reload here by doing a manual load.
1653         d->webPageProxy->loadURL(mainFrame->unreachableURL());
1654         // FIXME: We should make WebCore aware of the unreachable url regardless of substitute-loads
1655         return;
1656     }
1657
1658     WKPageReloadFromOrigin(d->webPage.get());
1659 }
1660
1661 /*!
1662     \qmlproperty url WebView::url
1663
1664     The location of the currently displaying HTML page. This writable
1665     property offers the main interface to load a page into a web view.
1666     It functions the same as the \c{window.location} DOM property.
1667
1668     \sa WebView::loadHtml()
1669 */
1670 QUrl QQuickWebView::url() const
1671 {
1672     Q_D(const QQuickWebView);
1673
1674     // FIXME: Enable once we are sure this should not trigger
1675     // Q_ASSERT(d->m_currentUrl == d->webPageProxy->activeURL());
1676
1677     return QUrl(d->m_currentUrl);
1678 }
1679
1680 void QQuickWebView::setUrl(const QUrl& url)
1681 {
1682     Q_D(QQuickWebView);
1683
1684     if (url.isEmpty())
1685         return;
1686
1687     WKRetainPtr<WKURLRef> u = adoptWK(WKURLCreateWithQUrl(url));
1688     WKPageLoadURL(d->webPage.get(), u.get());
1689     emitUrlChangeIfNeeded();
1690 }
1691
1692 // Make sure we don't emit urlChanged unless it actually changed
1693 void QQuickWebView::emitUrlChangeIfNeeded()
1694 {
1695     Q_D(QQuickWebView);
1696
1697     WTF::String activeUrl = d->webPageProxy->activeURL();
1698     if (activeUrl != d->m_currentUrl) {
1699         d->m_currentUrl = activeUrl;
1700         emit urlChanged();
1701     }
1702 }
1703
1704 /*!
1705     \qmlproperty url WebView::icon
1706
1707     The location of the currently displaying Web site icon, also known as favicon
1708     or shortcut icon. This read-only URL corresponds to the image used within a
1709     mobile browser application to represent a bookmarked page on the device's home
1710     screen.
1711
1712     This example uses the \c{icon} property to build an \c{Image} element:
1713
1714     \code
1715     Image {
1716         id: appIcon
1717         source: webView.icon != "" ? webView.icon : "fallbackFavIcon.png";
1718         ...
1719     }
1720     \endcode
1721 */
1722 QUrl QQuickWebView::icon() const
1723 {
1724     Q_D(const QQuickWebView);
1725     return QUrl(d->m_iconUrl);
1726 }
1727
1728 /*!
1729     \qmlproperty int WebView::loadProgress
1730
1731     The amount of the page that has been loaded, expressed as an integer
1732     percentage in the range from \c{0} to \c{100}.
1733 */
1734 int QQuickWebView::loadProgress() const
1735 {
1736     Q_D(const QQuickWebView);
1737     return d->loadProgress();
1738 }
1739
1740 /*!
1741     \qmlproperty bool WebView::canGoBack
1742
1743     Returns \c{true} if there are prior session history entries, \c{false}
1744     otherwise.
1745 */
1746 bool QQuickWebView::canGoBack() const
1747 {
1748     Q_D(const QQuickWebView);
1749     return WKPageCanGoBack(d->webPage.get());
1750 }
1751
1752 /*!
1753     \qmlproperty bool WebView::canGoForward
1754
1755     Returns \c{true} if there are subsequent session history entries,
1756     \c{false} otherwise.
1757 */
1758 bool QQuickWebView::canGoForward() const
1759 {
1760     Q_D(const QQuickWebView);
1761     return WKPageCanGoForward(d->webPage.get());
1762 }
1763
1764 /*!
1765     \qmlproperty bool WebView::loading
1766
1767     Returns \c{true} if the HTML page is currently loading, \c{false} otherwise.
1768 */
1769 bool QQuickWebView::loading() const
1770 {
1771     Q_D(const QQuickWebView);
1772     WKFrameRef mainFrame = WKPageGetMainFrame(d->webPage.get());
1773     return mainFrame && !(kWKFrameLoadStateFinished == WKFrameGetFrameLoadState(mainFrame));
1774 }
1775
1776 /*!
1777     \internal
1778  */
1779
1780 QPointF QQuickWebView::mapToWebContent(const QPointF& pointInViewCoordinates) const
1781 {
1782     Q_D(const QQuickWebView);
1783     return d->pageView->transformFromItem().map(pointInViewCoordinates);
1784 }
1785
1786 /*!
1787     \internal
1788  */
1789
1790 QRectF QQuickWebView::mapRectToWebContent(const QRectF& rectInViewCoordinates) const
1791 {
1792     Q_D(const QQuickWebView);
1793     return d->pageView->transformFromItem().mapRect(rectInViewCoordinates);
1794 }
1795
1796 /*!
1797     \internal
1798  */
1799
1800 QPointF QQuickWebView::mapFromWebContent(const QPointF& pointInCSSCoordinates) const
1801 {
1802     Q_D(const QQuickWebView);
1803     return d->pageView->transformToItem().map(pointInCSSCoordinates);
1804 }
1805
1806 /*!
1807     \internal
1808  */
1809 QRectF QQuickWebView::mapRectFromWebContent(const QRectF& rectInCSSCoordinates) const
1810 {
1811     Q_D(const QQuickWebView);
1812     return d->pageView->transformToItem().mapRect(rectInCSSCoordinates);
1813 }
1814
1815 /*!
1816     \qmlproperty string WebView::title
1817
1818     The title of the currently displaying HTML page, a read-only value
1819     that reflects the contents of the \c{<title>} tag.
1820 */
1821 QString QQuickWebView::title() const
1822 {
1823     Q_D(const QQuickWebView);
1824     WKRetainPtr<WKStringRef> t = adoptWK(WKPageCopyTitle(d->webPage.get()));
1825     return WKStringCopyQString(t.get());
1826 }
1827
1828 QVariant QQuickWebView::inputMethodQuery(Qt::InputMethodQuery property) const
1829 {
1830     Q_D(const QQuickWebView);
1831     const EditorState& state = d->webPageProxy->editorState();
1832
1833     switch(property) {
1834     case Qt::ImCursorRectangle:
1835         return QRectF(state.cursorRect);
1836     case Qt::ImFont:
1837         return QVariant();
1838     case Qt::ImCursorPosition:
1839         return QVariant(static_cast<int>(state.cursorPosition));
1840     case Qt::ImAnchorPosition:
1841         return QVariant(static_cast<int>(state.anchorPosition));
1842     case Qt::ImSurroundingText:
1843         return QString(state.surroundingText);
1844     case Qt::ImCurrentSelection:
1845         return QString(state.selectedText);
1846     case Qt::ImMaximumTextLength:
1847         return QVariant(); // No limit.
1848     case Qt::ImHints:
1849         return int(Qt::InputMethodHints(state.inputMethodHints));
1850     default:
1851         // Rely on the base implementation for ImEnabled, ImHints and ImPreferredLanguage.
1852         return QQuickFlickable::inputMethodQuery(property);
1853     }
1854 }
1855
1856 /*!
1857     internal
1858
1859     The experimental module consisting on experimental API which will break
1860     from version to version.
1861 */
1862 QQuickWebViewExperimental* QQuickWebView::experimental() const
1863 {
1864     Q_D(const QQuickWebView);
1865     return d->experimental;
1866 }
1867
1868 /*!
1869     \internal
1870 */
1871 void QQuickWebView::platformInitialize()
1872 {
1873     JSC::initializeThreading();
1874     WTF::initializeMainThread();
1875 }
1876
1877 bool QQuickWebView::childMouseEventFilter(QQuickItem* item, QEvent* event)
1878 {
1879     if (!isVisible() || !isEnabled())
1880         return false;
1881
1882     // This function is used by MultiPointTouchArea and PinchArea to filter
1883     // touch events, thus to hinder the canvas from sending synthesized
1884     // mouse events to the Flickable implementation we need to reimplement
1885     // childMouseEventFilter to ignore touch and mouse events.
1886
1887     switch (event->type()) {
1888     case QEvent::MouseButtonPress:
1889     case QEvent::MouseMove:
1890     case QEvent::MouseButtonRelease:
1891     case QEvent::TouchBegin:
1892     case QEvent::TouchUpdate:
1893     case QEvent::TouchEnd:
1894         // Force all mouse and touch events through the default propagation path.
1895         return false;
1896     default:
1897         ASSERT(event->type() == QEvent::UngrabMouse);
1898         break;
1899     }
1900
1901     return QQuickFlickable::childMouseEventFilter(item, event);
1902 }
1903
1904 void QQuickWebView::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry)
1905 {
1906     Q_D(QQuickWebView);
1907     QQuickFlickable::geometryChanged(newGeometry, oldGeometry);
1908     if (newGeometry.size() != oldGeometry.size())
1909         d->updateViewportSize();
1910 }
1911
1912 void QQuickWebView::componentComplete()
1913 {
1914     Q_D(QQuickWebView);
1915     QQuickFlickable::componentComplete();
1916
1917     d->onComponentComplete();
1918     d->updateViewportSize();
1919 }
1920
1921 void QQuickWebView::keyPressEvent(QKeyEvent* event)
1922 {
1923     Q_D(QQuickWebView);
1924     d->pageView->eventHandler()->handleKeyPressEvent(event);
1925 }
1926
1927 void QQuickWebView::keyReleaseEvent(QKeyEvent* event)
1928 {
1929     Q_D(QQuickWebView);
1930     d->pageView->eventHandler()->handleKeyReleaseEvent(event);
1931 }
1932
1933 void QQuickWebView::inputMethodEvent(QInputMethodEvent* event)
1934 {
1935     Q_D(QQuickWebView);
1936     d->pageView->eventHandler()->handleInputMethodEvent(event);
1937 }
1938
1939 void QQuickWebView::focusInEvent(QFocusEvent* event)
1940 {
1941     Q_D(QQuickWebView);
1942     d->pageView->eventHandler()->handleFocusInEvent(event);
1943 }
1944
1945 void QQuickWebView::itemChange(ItemChange change, const ItemChangeData &value)
1946 {
1947     Q_D(QQuickWebView);
1948     if (change == ItemActiveFocusHasChanged) {
1949         bool focus = value.boolValue;
1950         if (!focus)
1951             d->pageView->eventHandler()->handleFocusLost();
1952     }
1953     QQuickFlickable::itemChange(change, value);
1954 }
1955
1956 void QQuickWebView::touchEvent(QTouchEvent* event)
1957 {
1958     Q_D(QQuickWebView);
1959
1960     bool lockingDisabled = flickableDirection() != AutoFlickDirection
1961                            || event->touchPoints().size() != 1
1962                            || width() >= contentWidth()
1963                            || height() >= contentHeight();
1964
1965     if (!lockingDisabled)
1966         d->axisLocker.update(event);
1967     else
1968         d->axisLocker.reset();
1969
1970     forceActiveFocus();
1971     d->pageView->eventHandler()->handleTouchEvent(event);
1972 }
1973
1974 void QQuickWebView::mousePressEvent(QMouseEvent* event)
1975 {
1976     Q_D(QQuickWebView);
1977     forceActiveFocus();
1978     d->handleMouseEvent(event);
1979 }
1980
1981 void QQuickWebView::mouseMoveEvent(QMouseEvent* event)
1982 {
1983     Q_D(QQuickWebView);
1984     d->handleMouseEvent(event);
1985 }
1986
1987 void QQuickWebView::mouseReleaseEvent(QMouseEvent* event)
1988 {
1989     Q_D(QQuickWebView);
1990     d->handleMouseEvent(event);
1991 }
1992
1993 void QQuickWebView::mouseDoubleClickEvent(QMouseEvent* event)
1994 {
1995     Q_D(QQuickWebView);
1996     forceActiveFocus();
1997     d->handleMouseEvent(event);
1998 }
1999
2000 void QQuickWebView::wheelEvent(QWheelEvent* event)
2001 {
2002     Q_D(QQuickWebView);
2003     d->pageView->eventHandler()->handleWheelEvent(event);
2004 }
2005
2006 void QQuickWebView::hoverEnterEvent(QHoverEvent* event)
2007 {
2008     Q_D(QQuickWebView);
2009     // Map HoverEnter to Move, for WebKit the distinction doesn't matter.
2010     d->pageView->eventHandler()->handleHoverMoveEvent(event);
2011 }
2012
2013 void QQuickWebView::hoverMoveEvent(QHoverEvent* event)
2014 {
2015     Q_D(QQuickWebView);
2016     d->pageView->eventHandler()->handleHoverMoveEvent(event);
2017 }
2018
2019 void QQuickWebView::hoverLeaveEvent(QHoverEvent* event)
2020 {
2021     Q_D(QQuickWebView);
2022     d->pageView->eventHandler()->handleHoverLeaveEvent(event);
2023 }
2024
2025 void QQuickWebView::dragMoveEvent(QDragMoveEvent* event)
2026 {
2027     Q_D(QQuickWebView);
2028     d->pageView->eventHandler()->handleDragMoveEvent(event);
2029 }
2030
2031 void QQuickWebView::dragEnterEvent(QDragEnterEvent* event)
2032 {
2033     Q_D(QQuickWebView);
2034     d->pageView->eventHandler()->handleDragEnterEvent(event);
2035 }
2036
2037 void QQuickWebView::dragLeaveEvent(QDragLeaveEvent* event)
2038 {
2039     Q_D(QQuickWebView);
2040     d->pageView->eventHandler()->handleDragLeaveEvent(event);
2041 }
2042
2043 void QQuickWebView::dropEvent(QDropEvent* event)
2044 {
2045     Q_D(QQuickWebView);
2046     d->pageView->eventHandler()->handleDropEvent(event);
2047 }
2048
2049 bool QQuickWebView::event(QEvent* ev)
2050 {
2051     // Re-implemented for possible future use without breaking binary compatibility.
2052     return QQuickFlickable::event(ev);
2053 }
2054
2055 WKPageRef QQuickWebView::pageRef() const
2056 {
2057     Q_D(const QQuickWebView);
2058     return d->webPage.get();
2059 }
2060
2061 QPointF QQuickWebView::contentPos() const
2062 {
2063     Q_D(const QQuickWebView);
2064     return d->contentPos();
2065 }
2066
2067 void QQuickWebView::setContentPos(const QPointF& pos)
2068 {
2069     Q_D(QQuickWebView);
2070
2071     if (pos == contentPos())
2072         return;
2073
2074     d->setContentPos(pos);
2075 }
2076
2077 void QQuickWebView::handleFlickableMousePress(const QPointF& position, qint64 eventTimestampMillis)
2078 {
2079     Q_D(QQuickWebView);
2080     d->axisLocker.setReferencePosition(position);
2081     QMouseEvent mouseEvent(QEvent::MouseButtonPress, position, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
2082     mouseEvent.setTimestamp(eventTimestampMillis);
2083     QQuickFlickable::mousePressEvent(&mouseEvent);
2084 }
2085
2086 void QQuickWebView::handleFlickableMouseMove(const QPointF& position, qint64 eventTimestampMillis)
2087 {
2088     Q_D(QQuickWebView);
2089     QMouseEvent mouseEvent(QEvent::MouseMove, d->axisLocker.adjust(position), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
2090     mouseEvent.setTimestamp(eventTimestampMillis);
2091     QQuickFlickable::mouseMoveEvent(&mouseEvent);
2092 }
2093
2094 void QQuickWebView::handleFlickableMouseRelease(const QPointF& position, qint64 eventTimestampMillis)
2095 {
2096     Q_D(QQuickWebView);
2097     QMouseEvent mouseEvent(QEvent::MouseButtonRelease, d->axisLocker.adjust(position), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
2098     d->axisLocker.reset();
2099     mouseEvent.setTimestamp(eventTimestampMillis);
2100     QQuickFlickable::mouseReleaseEvent(&mouseEvent);
2101 }
2102
2103 /*!
2104     \qmlmethod void WebView::loadHtml(string html, url baseUrl, url unreachableUrl)
2105     \brief Loads the specified \a html as the content of the web view.
2106
2107     (This method offers a lower-level alternative to the \c{url} property,
2108     which references HTML pages via URL.)
2109
2110     External objects such as stylesheets or images referenced in the HTML
2111     document are located relative to \a baseUrl. For example if provided \a html
2112     was originally retrieved from \c http://www.example.com/documents/overview.html
2113     and that was the base url, then an image referenced with the relative url \c diagram.png
2114     would be looked for at \c{http://www.example.com/documents/diagram.png}.
2115
2116     If an \a unreachableUrl is passed it is used as the url for the loaded
2117     content. This is typically used to display error pages for a failed
2118     load.
2119
2120     \sa WebView::url
2121 */
2122 void QQuickWebView::loadHtml(const QString& html, const QUrl& baseUrl, const QUrl& unreachableUrl)
2123 {
2124     Q_D(QQuickWebView);
2125     WKRetainPtr<WKStringRef> htmlRef = adoptWK(WKStringCreateWithQString(html));
2126     WKRetainPtr<WKURLRef> baseUrlRef = adoptWK(WKURLCreateWithQUrl(baseUrl));
2127     WKRetainPtr<WKURLRef> unreachableUrlRef = adoptWK(WKURLCreateWithQUrl(unreachableUrl));
2128
2129     if (unreachableUrl.isValid())
2130         WKPageLoadAlternateHTMLString(d->webPage.get(), htmlRef.get(), baseUrlRef.get(), unreachableUrlRef.get());
2131     else
2132         WKPageLoadHTMLString(d->webPage.get(), htmlRef.get(), baseUrlRef.get());
2133 }
2134
2135 qreal QQuickWebView::zoomFactor() const
2136 {
2137     Q_D(const QQuickWebView);
2138     return d->zoomFactor();
2139 }
2140
2141 void QQuickWebView::setZoomFactor(qreal factor)
2142 {
2143
2144     Q_D(QQuickWebView);
2145     d->setZoomFactor(factor);
2146 }
2147
2148 void QQuickWebView::runJavaScriptInMainFrame(const QString &script, QObject *receiver, const char *method)
2149 {
2150     Q_D(QQuickWebView);
2151
2152     JSCallbackClosure* closure = new JSCallbackClosure;
2153     closure->receiver = receiver;
2154     closure->method = method;
2155
2156     WKRetainPtr<WKStringRef> scriptString = adoptWK(WKStringCreateWithQString(script));
2157     WKPageRunJavaScriptInMainFrame(d->webPage.get(), scriptString.get(), closure, javaScriptCallback);
2158 }
2159
2160 bool QQuickWebView::allowAnyHTTPSCertificateForLocalHost() const
2161 {
2162     Q_D(const QQuickWebView);
2163     return d->m_allowAnyHTTPSCertificateForLocalHost;
2164 }
2165
2166 void QQuickWebView::setAllowAnyHTTPSCertificateForLocalHost(bool allow)
2167 {
2168     Q_D(QQuickWebView);
2169     d->m_allowAnyHTTPSCertificateForLocalHost = allow;
2170 }
2171
2172 void QQuickWebViewPrivate::didFindString(WKPageRef, WKStringRef, unsigned matchCount, const void* clientInfo)
2173 {
2174     QQuickWebView* q = toQQuickWebViewPrivate(clientInfo)->q_ptr;
2175     emit q->experimental()->textFound(matchCount);
2176 }
2177
2178 void QQuickWebViewPrivate::didFailToFindString(WKPageRef page, WKStringRef string, const void* clientInfo)
2179 {
2180     QQuickWebViewPrivate::didFindString(page, string, 0, clientInfo);
2181 }
2182
2183 /*!
2184     \qmlsignal WebView::onLoadingChanged(loadRequest)
2185
2186     Occurs when any page load begins, ends, or fails. Various read-only
2187     parameters are available on the \a loadRequest:
2188
2189     \list
2190
2191     \li \c{url}: the location of the resource that is loading.
2192
2193     \li \c{status}: Reflects one of three load states:
2194        \c{LoadStartedStatus}, \c{LoadSucceededStatus}, or
2195        \c{LoadFailedStatus}. See \c{WebView::LoadStatus}.
2196
2197     \li \c{errorString}: description of load error.
2198
2199     \li \c{errorCode}: HTTP error code.
2200
2201     \li \c{errorDomain}: high-level error types, one of
2202     \c{NetworkErrorDomain}, \c{HttpErrorDomain}, \c{InternalErrorDomain},
2203     \c{DownloadErrorDomain}, or \c{NoErrorDomain}.  See
2204     \l{WebView::ErrorDomain}.
2205
2206     \endlist
2207
2208     \sa WebView::loading
2209 */
2210
2211 /*!
2212     \qmlsignal WebView::onLinkHovered(hoveredUrl, hoveredTitle)
2213
2214     Within a mouse-driven interface, this signal is emitted when a mouse
2215     pointer passes over a link, corresponding to the \c{mouseover} DOM
2216     event.  (May also occur in touch interfaces for \c{mouseover} events
2217     that are not cancelled with \c{preventDefault()}.)  The \a{hoveredUrl}
2218     provides the link's location, and the \a{hoveredTitle} is any avalable
2219     link text.
2220 */
2221
2222 /*!
2223     \qmlsignal WebView::onNavigationRequested(request)
2224
2225     Occurs for various kinds of navigation.  If the application listens
2226     for this signal, it must set the \c{request.action} to either of the
2227     following \l{WebView::NavigationRequestAction} enum values:
2228
2229     \list
2230
2231     \li \c{AcceptRequest}: Allow navigation to external pages within the
2232     web view. This represents the default behavior when no listener is
2233     active.
2234
2235     \li \c{IgnoreRequest}: Suppress navigation to new pages within the web
2236     view.  (The listener may then delegate navigation externally to
2237     the browser application.)
2238
2239     \endlist
2240
2241     The \a{request} also provides the following read-only values:
2242
2243     \list
2244
2245     \li \c{url}: The location of the requested page.
2246
2247     \li \c{navigationType}: contextual information, one of
2248     \c{LinkClickedNavigation}, \c{BackForwardNavigation},
2249     \c{ReloadNavigation}, \c{FormSubmittedNavigation},
2250     \c{FormResubmittedNavigation}, or \c{OtherNavigation} enum values.
2251     See \l{WebView::NavigationType}.
2252
2253     \li \c{keyboardModifiers}: potential states for \l{Qt::KeyboardModifier}.
2254
2255     \li \c{mouseButton}: potential states for \l{Qt::MouseButton}.
2256
2257     \endlist
2258 */
2259
2260 /*!
2261     \qmlproperty enumeration WebView::ErrorDomain
2262
2263     Details various high-level error types.
2264
2265     \table
2266
2267     \header
2268     \li Constant
2269     \li Description
2270
2271     \row
2272     \li InternalErrorDomain
2273     \li Content fails to be interpreted by QtWebKit.
2274
2275     \row
2276     \li NetworkErrorDomain
2277     \li Error results from faulty network connection.
2278
2279     \row
2280     \li HttpErrorDomain
2281     \li Error is produced by server.
2282
2283     \row
2284     \li DownloadErrorDomain
2285     \li Error in saving file.
2286
2287     \row
2288     \li NoErrorDomain
2289     \li Unspecified fallback error.
2290
2291     \endtable
2292 */
2293
2294 /*!
2295     \qmlproperty enumeration WebView::NavigationType
2296
2297     Distinguishes context for various navigation actions.
2298
2299     \table
2300
2301     \header
2302     \li Constant
2303     \li Description
2304
2305     \row
2306     \li LinkClickedNavigation
2307     \li Navigation via link.
2308
2309     \row
2310     \li FormSubmittedNavigation
2311     \li Form data is posted.
2312
2313     \row
2314     \li BackForwardNavigation
2315     \li Navigation back and forth within session history.
2316
2317     \row
2318     \li ReloadNavigation
2319     \li The current page is reloaded.
2320
2321     \row
2322     \li FormResubmittedNavigation
2323     \li Form data is re-posted.
2324
2325     \row
2326     \li OtherNavigation
2327     \li Unspecified fallback method of navigation.
2328
2329     \endtable
2330 */
2331
2332 /*!
2333     \qmlproperty enumeration WebView::LoadStatus
2334
2335     Reflects a page's load status.
2336
2337     \table
2338
2339     \header
2340     \li Constant
2341     \li Description
2342
2343     \row
2344     \li LoadStartedStatus
2345     \li Page is currently loading.
2346
2347     \row
2348     \li LoadSucceededStatus
2349     \li Page has successfully loaded, and is not currently loading.
2350
2351     \row
2352     \li LoadFailedStatus
2353     \li Page has failed to load, and is not currently loading.
2354
2355     \endtable
2356 */
2357
2358 /*!
2359     \qmlproperty enumeration WebView::NavigationRequestAction
2360
2361     Specifies a policy when navigating a link to an external page.
2362
2363     \table
2364
2365     \header
2366     \li Constant
2367     \li Description
2368
2369     \row
2370     \li AcceptRequest
2371     \li Allow navigation to external pages within the web view.
2372
2373     \row
2374     \li IgnoreRequest
2375     \li Suppress navigation to new pages within the web view.
2376
2377     \endtable
2378 */
2379
2380 #include "moc_qquickwebview_p.cpp"