[Qt][WK2] Crash on window resize if WebProcess is closed/crashed
[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     if (DrawingAreaProxy *drawingArea = webPageProxy->drawingArea()) {
589         drawingArea->setSize(viewSize(), IntSize());
590
591         updateViewportSize();
592         updateUserScripts();
593         updateSchemeDelegates();
594     }
595 }
596
597 PassOwnPtr<DrawingAreaProxy> QQuickWebViewPrivate::createDrawingAreaProxy()
598 {
599     return DrawingAreaProxyImpl::create(webPageProxy.get());
600 }
601
602 void QQuickWebViewPrivate::handleDownloadRequest(DownloadProxy* download)
603 {
604     Q_Q(QQuickWebView);
605     // This function is responsible for hooking up a DownloadProxy to our API layer
606     // by creating a QWebDownloadItem. It will then wait for the QWebDownloadItem to be
607     // ready (filled with the ResourceResponse information) so we can pass it through to
608     // our WebViews.
609     QWebDownloadItem* downloadItem = new QWebDownloadItem();
610     downloadItem->d->downloadProxy = download;
611
612     q->connect(downloadItem->d, SIGNAL(receivedResponse(QWebDownloadItem*)), q, SLOT(_q_onReceivedResponseFromDownload(QWebDownloadItem*)));
613     QtWebContext::downloadManager()->addDownload(download, downloadItem);
614 }
615
616 void QQuickWebViewPrivate::_q_onVisibleChanged()
617 {
618     webPageProxy->viewStateDidChange(WebPageProxy::ViewIsVisible);
619 }
620
621 void QQuickWebViewPrivate::_q_onUrlChanged()
622 {
623     updateIcon();
624 }
625
626 void QQuickWebViewPrivate::_q_onIconChangedForPageURL(const QString& pageUrl)
627 {
628     if (pageUrl != QString(m_currentUrl))
629         return;
630
631     updateIcon();
632 }
633
634 /* Called either when the url changes, or when the icon for the current page changes */
635 void QQuickWebViewPrivate::updateIcon()
636 {
637     Q_Q(QQuickWebView);
638
639     QQuickView* view = qobject_cast<QQuickView*>(q->window());
640     if (!view)
641         return;
642
643     QWebIconImageProvider* provider = static_cast<QWebIconImageProvider*>(
644                 view->engine()->imageProvider(QWebIconImageProvider::identifier()));
645     if (!provider)
646         return;
647
648     WTF::String iconUrl = provider->iconURLForPageURLInContext(m_currentUrl, context.get());
649
650     if (iconUrl == m_iconUrl)
651         return;
652
653     m_iconUrl = iconUrl;
654     emit q->iconChanged();
655 }
656
657 void QQuickWebViewPrivate::_q_onReceivedResponseFromDownload(QWebDownloadItem* downloadItem)
658 {
659     // Now that our downloadItem has everything we need we can emit downloadRequested.
660     if (!downloadItem)
661         return;
662
663     Q_Q(QQuickWebView);
664     QQmlEngine::setObjectOwnership(downloadItem, QQmlEngine::JavaScriptOwnership);
665     emit q->experimental()->downloadRequested(downloadItem);
666 }
667
668 void QQuickWebViewPrivate::runJavaScriptAlert(const QString& alertText)
669 {
670     Q_Q(QQuickWebView);
671     QtDialogRunner dialogRunner(q);
672     if (!dialogRunner.initForAlert(alertText))
673         return;
674
675     dialogRunner.run();
676 }
677
678 bool QQuickWebViewPrivate::runJavaScriptConfirm(const QString& message)
679 {
680     Q_Q(QQuickWebView);
681     QtDialogRunner dialogRunner(q);
682     if (!dialogRunner.initForConfirm(message))
683         return true;
684
685     dialogRunner.run();
686
687     return dialogRunner.wasAccepted();
688 }
689
690 QString QQuickWebViewPrivate::runJavaScriptPrompt(const QString& message, const QString& defaultValue, bool& ok)
691 {
692     Q_Q(QQuickWebView);
693     QtDialogRunner dialogRunner(q);
694     if (!dialogRunner.initForPrompt(message, defaultValue)) {
695         ok = true;
696         return defaultValue;
697     }
698
699     dialogRunner.run();
700
701     ok = dialogRunner.wasAccepted();
702     return dialogRunner.result();
703 }
704
705 void QQuickWebViewPrivate::handleAuthenticationRequiredRequest(const QString& hostname, const QString& realm, const QString& prefilledUsername, QString& username, QString& password)
706 {
707     Q_Q(QQuickWebView);
708     QtDialogRunner dialogRunner(q);
709     if (!dialogRunner.initForAuthentication(hostname, realm, prefilledUsername))
710         return;
711
712     dialogRunner.run();
713
714     username = dialogRunner.username();
715     password = dialogRunner.password();
716 }
717
718 void QQuickWebViewPrivate::handleProxyAuthenticationRequiredRequest(const QString& hostname, uint16_t port, const QString& prefilledUsername, QString& username, QString& password)
719 {
720     Q_Q(QQuickWebView);
721     QtDialogRunner dialogRunner(q);
722     if (!dialogRunner.initForProxyAuthentication(hostname, port, prefilledUsername))
723         return;
724
725     dialogRunner.run();
726
727     username = dialogRunner.username();
728     password = dialogRunner.password();
729 }
730
731 bool QQuickWebViewPrivate::handleCertificateVerificationRequest(const QString& hostname)
732 {
733     Q_Q(QQuickWebView);
734
735     if (m_allowAnyHTTPSCertificateForLocalHost
736         && (hostname == QStringLiteral("127.0.0.1") || hostname == QStringLiteral("localhost")))
737         return true;
738
739     QtDialogRunner dialogRunner(q);
740     if (!dialogRunner.initForCertificateVerification(hostname))
741         return false;
742
743     dialogRunner.run();
744
745     return dialogRunner.wasAccepted();
746 }
747
748 void QQuickWebViewPrivate::chooseFiles(WKOpenPanelResultListenerRef listenerRef, const QStringList& selectedFileNames, QtWebPageUIClient::FileChooserType type)
749 {
750     Q_Q(QQuickWebView);
751
752     QtDialogRunner dialogRunner(q);
753     if (!dialogRunner.initForFilePicker(selectedFileNames, (type == QtWebPageUIClient::MultipleFilesSelection)))
754         return;
755
756     dialogRunner.run();
757
758     if (dialogRunner.wasAccepted()) {
759         QStringList selectedPaths = dialogRunner.filePaths();
760
761         Vector<RefPtr<APIObject> > wkFiles(selectedPaths.size());
762         for (unsigned i = 0; i < selectedPaths.size(); ++i)
763             wkFiles[i] = WebURL::create(QUrl::fromLocalFile(selectedPaths.at(i)).toString());            
764
765         WKOpenPanelResultListenerChooseFiles(listenerRef, toAPI(ImmutableArray::adopt(wkFiles).leakRef()));
766     } else
767         WKOpenPanelResultListenerCancel(listenerRef);
768
769 }
770
771 quint64 QQuickWebViewPrivate::exceededDatabaseQuota(const QString& databaseName, const QString& displayName, WKSecurityOriginRef securityOrigin, quint64 currentQuota, quint64 currentOriginUsage, quint64 currentDatabaseUsage, quint64 expectedUsage)
772 {
773     Q_Q(QQuickWebView);
774     QtDialogRunner dialogRunner(q);
775     if (!dialogRunner.initForDatabaseQuotaDialog(databaseName, displayName, securityOrigin, currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage))
776         return 0;
777
778     dialogRunner.run();
779
780     return dialogRunner.wasAccepted() ? dialogRunner.databaseQuota() : 0;
781 }
782
783 /* The 'WebView' attached property allows items spawned by the webView to
784    refer back to the originating webView through 'WebView.view', similar
785    to how ListView.view and GridView.view is exposed to items. */
786 QQuickWebViewAttached::QQuickWebViewAttached(QObject* object)
787     : QObject(object)
788     , m_view(0)
789 {
790 }
791
792 void QQuickWebViewAttached::setView(QQuickWebView* view)
793 {
794     if (m_view == view)
795         return;
796     m_view = view;
797     emit viewChanged();
798 }
799
800 QQuickWebViewAttached* QQuickWebView::qmlAttachedProperties(QObject* object)
801 {
802     return new QQuickWebViewAttached(object);
803 }
804
805
806
807 void QQuickWebViewPrivate::addAttachedPropertyTo(QObject* object)
808 {
809     Q_Q(QQuickWebView);
810     QQuickWebViewAttached* attached = static_cast<QQuickWebViewAttached*>(qmlAttachedPropertiesObject<QQuickWebView>(object));
811     attached->setView(q);
812 }
813
814 bool QQuickWebViewPrivate::navigatorQtObjectEnabled() const
815 {
816     return m_navigatorQtObjectEnabled;
817 }
818
819 void QQuickWebViewPrivate::setNavigatorQtObjectEnabled(bool enabled)
820 {
821     ASSERT(enabled != m_navigatorQtObjectEnabled);
822     // FIXME: Currently we have to keep this information in both processes and the setting is asynchronous.
823     m_navigatorQtObjectEnabled = enabled;
824
825     static String messageName("SetNavigatorQtObjectEnabled");
826     RefPtr<WebBoolean> webEnabled = WebBoolean::create(enabled);
827     webPageProxy->postMessageToInjectedBundle(messageName, webEnabled.get());
828 }
829
830 static WKRetainPtr<WKStringRef> readUserScript(const QUrl& url)
831 {
832     QString path;
833     if (url.isLocalFile())
834         path = url.toLocalFile();
835     else if (url.scheme() == QLatin1String("qrc"))
836         path = QStringLiteral(":") + url.path();
837     else {
838         qWarning("QQuickWebView: Couldn't open '%s' as user script because only file:/// and qrc:/// URLs are supported.", qPrintable(url.toString()));
839         return 0;
840     }
841
842     QFile file(path);
843     if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
844         qWarning("QQuickWebView: Couldn't open '%s' as user script due to error '%s'.", qPrintable(url.toString()), qPrintable(file.errorString()));
845         return 0;
846     }
847
848     QByteArray contents = file.readAll();
849     if (contents.isEmpty())
850         qWarning("QQuickWebView: Ignoring '%s' as user script because file is empty.", qPrintable(url.toString()));
851
852     return adoptWK(WKStringCreateWithUTF8CString(contents.constData()));
853 }
854
855 void QQuickWebViewPrivate::updateUserScripts()
856 {
857     // This feature works per-WebView because we keep an unique page group for
858     // each Page/WebView pair we create.
859     WKPageGroupRemoveAllUserScripts(pageGroup.get());
860
861     for (unsigned i = 0; i < userScripts.size(); ++i) {
862         const QUrl& url = userScripts.at(i);
863         if (!url.isValid()) {
864             qWarning("QQuickWebView: Couldn't open '%s' as user script because URL is invalid.", qPrintable(url.toString()));
865             continue;
866         }
867
868         WKRetainPtr<WKStringRef> contents = readUserScript(url);
869         if (!contents || WKStringIsEmpty(contents.get()))
870             continue;
871         WKPageGroupAddUserScript(pageGroup.get(), contents.get(), /*baseURL*/ 0, /*whitelistedURLPatterns*/ 0, /*blacklistedURLPatterns*/ 0, kWKInjectInTopFrameOnly, kWKInjectAtDocumentEnd);
872     }
873 }
874
875 void QQuickWebViewPrivate::updateSchemeDelegates()
876 {
877     webPageProxy->registerApplicationScheme(ASCIILiteral("qrc"));
878
879     QQmlListProperty<QQuickUrlSchemeDelegate> schemes = experimental->schemeDelegates();
880     for (int i = 0, numSchemes = experimental->schemeDelegates_Count(&schemes); i < numSchemes; ++i) {
881         QQuickUrlSchemeDelegate* scheme = experimental->schemeDelegates_At(&schemes, i);
882         webPageProxy->registerApplicationScheme(scheme->scheme());
883     }
884 }
885
886 QPointF QQuickWebViewPrivate::contentPos() const
887 {
888     Q_Q(const QQuickWebView);
889     return QPointF(q->contentX(), q->contentY());
890 }
891
892 void QQuickWebViewPrivate::setContentPos(const QPointF& pos)
893 {
894     Q_Q(QQuickWebView);
895     q->setContentX(pos.x());
896     q->setContentY(pos.y());
897 }
898
899 WebCore::IntSize QQuickWebViewPrivate::viewSize() const
900 {
901     return WebCore::IntSize(pageView->width(), pageView->height());
902 }
903
904 /*!
905     \internal
906
907     \qmlsignal WebViewExperimental::onMessageReceived(var message)
908
909     \brief Emitted when JavaScript code executing on the web page calls navigator.qt.postMessage().
910
911     \sa postMessage
912 */
913 void QQuickWebViewPrivate::didReceiveMessageFromNavigatorQtObject(const String& message)
914 {
915     QVariantMap variantMap;
916     variantMap.insert(QLatin1String("data"), QString(message));
917     variantMap.insert(QLatin1String("origin"), q_ptr->url());
918     emit q_ptr->experimental()->messageReceived(variantMap);
919 }
920
921 QQuickWebViewLegacyPrivate::QQuickWebViewLegacyPrivate(QQuickWebView* viewport)
922     : QQuickWebViewPrivate(viewport)
923 {
924 }
925
926 void QQuickWebViewLegacyPrivate::initialize(WKContextRef contextRef, WKPageGroupRef pageGroupRef)
927 {
928     QQuickWebViewPrivate::initialize(contextRef, pageGroupRef);
929
930     // Trigger setting of correct visibility flags after everything was allocated and initialized.
931     _q_onVisibleChanged();
932 }
933
934 void QQuickWebViewLegacyPrivate::updateViewportSize()
935 {
936     Q_Q(QQuickWebView);
937     QSizeF viewportSize = q->boundingRect().size();
938     if (viewportSize.isEmpty())
939         return;
940
941     pageView->setContentsSize(viewportSize);
942
943     if (DrawingAreaProxy *drawingArea = webPageProxy->drawingArea()) {
944         // The fixed layout is handled by the FrameView and the drawing area doesn't behave differently
945         // whether its fixed or not. We still need to tell the drawing area which part of it
946         // has to be rendered on tiles, and in desktop mode it's all of it.
947         drawingArea->setSize(viewportSize.toSize(), IntSize());
948         // The backing store scale factor should already be set to the device pixel ratio
949         // of the underlying window, thus we set the effective scale to 1 here.
950         drawingArea->setVisibleContentsRect(FloatRect(FloatPoint(), FloatSize(viewportSize)), FloatPoint());
951     }
952 }
953
954 qreal QQuickWebViewLegacyPrivate::zoomFactor() const
955 {
956     return WKPageGetPageZoomFactor(webPage.get());
957 }
958
959 void QQuickWebViewLegacyPrivate::setZoomFactor(qreal factor)
960 {
961     WKPageSetPageZoomFactor(webPage.get(), factor);
962 }
963
964 QQuickWebViewFlickablePrivate::QQuickWebViewFlickablePrivate(QQuickWebView* viewport)
965     : QQuickWebViewPrivate(viewport)
966 {
967 }
968
969 void QQuickWebViewFlickablePrivate::initialize(WKContextRef contextRef, WKPageGroupRef pageGroupRef)
970 {
971     QQuickWebViewPrivate::initialize(contextRef, pageGroupRef);
972 }
973
974 void QQuickWebViewFlickablePrivate::onComponentComplete()
975 {
976     QQuickWebViewPrivate::onComponentComplete();
977
978     Q_Q(QQuickWebView);
979     m_pageViewportControllerClient.reset(new PageViewportControllerClientQt(q, pageView.data()));
980     m_pageViewportController.reset(new PageViewportController(webPageProxy.get(), m_pageViewportControllerClient.data()));
981     pageView->eventHandler()->setViewportController(m_pageViewportControllerClient.data());
982
983     // Trigger setting of correct visibility flags after everything was allocated and initialized.
984     _q_onVisibleChanged();
985 }
986
987 void QQuickWebViewFlickablePrivate::didChangeViewportProperties(const WebCore::ViewportAttributes& newAttributes)
988 {
989     if (m_pageViewportController)
990         m_pageViewportController->didChangeViewportAttributes(newAttributes);
991 }
992
993 void QQuickWebViewFlickablePrivate::updateViewportSize()
994 {
995     Q_Q(QQuickWebView);
996
997     if (m_pageViewportController)
998         m_pageViewportController->didChangeViewportSize(FloatSize(q->width(), q->height()));
999 }
1000
1001 void QQuickWebViewFlickablePrivate::pageDidRequestScroll(const QPoint& pos)
1002 {
1003     if (m_pageViewportController)
1004         m_pageViewportController->pageDidRequestScroll(pos);
1005 }
1006
1007 QQuickWebViewExperimental::QQuickWebViewExperimental(QQuickWebView *webView, QQuickWebViewPrivate* webViewPrivate)
1008     : QObject(webView)
1009     , q_ptr(webView)
1010     , d_ptr(webViewPrivate)
1011     , schemeParent(new QObject(this))
1012     , m_test(new QWebKitTest(webViewPrivate, this))
1013 {
1014 }
1015
1016 QQuickWebViewExperimental::~QQuickWebViewExperimental()
1017 {
1018 }
1019
1020 void QQuickWebViewExperimental::setRenderToOffscreenBuffer(bool enable)
1021 {
1022     Q_D(QQuickWebView);
1023     d->setRenderToOffscreenBuffer(enable);
1024 }
1025
1026 bool QQuickWebViewExperimental::renderToOffscreenBuffer() const
1027 {
1028     Q_D(const QQuickWebView);
1029     return d->renderToOffscreenBuffer();
1030 }
1031
1032 bool QQuickWebViewExperimental::transparentBackground() const
1033 {
1034     Q_D(const QQuickWebView);
1035     return d->transparentBackground();
1036 }
1037 void QQuickWebViewExperimental::setTransparentBackground(bool enable)
1038 {
1039     Q_D(QQuickWebView);
1040     d->setTransparentBackground(enable);
1041 }
1042
1043 bool QQuickWebViewExperimental::useDefaultContentItemSize() const
1044 {
1045     Q_D(const QQuickWebView);
1046     return d->m_useDefaultContentItemSize;
1047 }
1048
1049 void QQuickWebViewExperimental::setUseDefaultContentItemSize(bool enable)
1050 {
1051     Q_D(QQuickWebView);
1052     d->m_useDefaultContentItemSize = enable;
1053 }
1054
1055 /*!
1056     \internal
1057
1058     \qmlproperty int WebViewExperimental::preferredMinimumContentsWidth
1059     \brief Minimum contents width when not overriden by the page itself.
1060
1061     Unless the page defines how contents should be laid out, using e.g.
1062     the viewport meta tag, it is laid out given the width of the viewport
1063     (in CSS units).
1064
1065     This setting can be used to enforce a minimum width when the page
1066     does not define a width itself. This is useful for laying out pages
1067     designed for big screens, commonly knows as desktop pages, on small
1068     devices.
1069
1070     The default value is 0, but the value of 980 is recommented for small
1071     screens as it provides a good trade off between legitable pages and
1072     non-broken content.
1073  */
1074 int QQuickWebViewExperimental::preferredMinimumContentsWidth() const
1075 {
1076     Q_D(const QQuickWebView);
1077     return d->webPageProxy->pageGroup()->preferences()->layoutFallbackWidth();
1078 }
1079
1080 void QQuickWebViewExperimental::setPreferredMinimumContentsWidth(int width)
1081 {
1082     Q_D(QQuickWebView);
1083     WebPreferences* webPreferences = d->webPageProxy->pageGroup()->preferences();
1084
1085     if (width == webPreferences->layoutFallbackWidth())
1086         return;
1087
1088     webPreferences->setLayoutFallbackWidth(width);
1089     emit preferredMinimumContentsWidthChanged();
1090 }
1091
1092 void QQuickWebViewExperimental::setFlickableViewportEnabled(bool enable)
1093 {
1094     s_flickableViewportEnabled = enable;
1095 }
1096
1097 bool QQuickWebViewExperimental::flickableViewportEnabled()
1098 {
1099     return s_flickableViewportEnabled;
1100 }
1101
1102 /*!
1103     \internal
1104
1105     \qmlmethod void WebViewExperimental::postMessage(string message)
1106
1107     \brief Post a message to an onmessage function registered with the navigator.qt object
1108            by JavaScript code executing on the page.
1109
1110     \sa onMessageReceived
1111 */
1112
1113 void QQuickWebViewExperimental::postMessage(const QString& message)
1114 {
1115     Q_D(QQuickWebView);
1116     static WKStringRef messageName = WKStringCreateWithUTF8CString("MessageToNavigatorQtObject");
1117     WKRetainPtr<WKStringRef> contents = adoptWK(WKStringCreateWithQString(message));
1118     WKPagePostMessageToInjectedBundle(d->webPage.get(), messageName, contents.get());
1119 }
1120
1121 QQmlComponent* QQuickWebViewExperimental::alertDialog() const
1122 {
1123     Q_D(const QQuickWebView);
1124     return d->alertDialog;
1125 }
1126
1127 void QQuickWebViewExperimental::setAlertDialog(QQmlComponent* alertDialog)
1128 {
1129     Q_D(QQuickWebView);
1130     if (d->alertDialog == alertDialog)
1131         return;
1132     d->alertDialog = alertDialog;
1133     emit alertDialogChanged();
1134 }
1135
1136 QQmlComponent* QQuickWebViewExperimental::confirmDialog() const
1137 {
1138     Q_D(const QQuickWebView);
1139     return d->confirmDialog;
1140 }
1141
1142 void QQuickWebViewExperimental::setConfirmDialog(QQmlComponent* confirmDialog)
1143 {
1144     Q_D(QQuickWebView);
1145     if (d->confirmDialog == confirmDialog)
1146         return;
1147     d->confirmDialog = confirmDialog;
1148     emit confirmDialogChanged();
1149 }
1150
1151 QWebNavigationHistory* QQuickWebViewExperimental::navigationHistory() const
1152 {
1153     return d_ptr->navigationHistory.get();
1154 }
1155
1156 QQmlComponent* QQuickWebViewExperimental::promptDialog() const
1157 {
1158     Q_D(const QQuickWebView);
1159     return d->promptDialog;
1160 }
1161
1162 QWebPreferences* QQuickWebViewExperimental::preferences() const
1163 {
1164     QQuickWebViewPrivate* const d = d_ptr;
1165     if (!d->preferences)
1166         d->preferences = adoptPtr(QWebPreferencesPrivate::createPreferences(d));
1167     return d->preferences.get();
1168 }
1169
1170 void QQuickWebViewExperimental::setPromptDialog(QQmlComponent* promptDialog)
1171 {
1172     Q_D(QQuickWebView);
1173     if (d->promptDialog == promptDialog)
1174         return;
1175     d->promptDialog = promptDialog;
1176     emit promptDialogChanged();
1177 }
1178
1179 QQmlComponent* QQuickWebViewExperimental::authenticationDialog() const
1180 {
1181     Q_D(const QQuickWebView);
1182     return d->authenticationDialog;
1183 }
1184
1185 void QQuickWebViewExperimental::setAuthenticationDialog(QQmlComponent* authenticationDialog)
1186 {
1187     Q_D(QQuickWebView);
1188     if (d->authenticationDialog == authenticationDialog)
1189         return;
1190     d->authenticationDialog = authenticationDialog;
1191     emit authenticationDialogChanged();
1192 }
1193
1194 QQmlComponent* QQuickWebViewExperimental::proxyAuthenticationDialog() const
1195 {
1196     Q_D(const QQuickWebView);
1197     return d->proxyAuthenticationDialog;
1198 }
1199
1200 void QQuickWebViewExperimental::setProxyAuthenticationDialog(QQmlComponent* proxyAuthenticationDialog)
1201 {
1202     Q_D(QQuickWebView);
1203     if (d->proxyAuthenticationDialog == proxyAuthenticationDialog)
1204         return;
1205     d->proxyAuthenticationDialog = proxyAuthenticationDialog;
1206     emit proxyAuthenticationDialogChanged();
1207 }
1208 QQmlComponent* QQuickWebViewExperimental::certificateVerificationDialog() const
1209 {
1210     Q_D(const QQuickWebView);
1211     return d->certificateVerificationDialog;
1212 }
1213
1214 void QQuickWebViewExperimental::setCertificateVerificationDialog(QQmlComponent* certificateVerificationDialog)
1215 {
1216     Q_D(QQuickWebView);
1217     if (d->certificateVerificationDialog == certificateVerificationDialog)
1218         return;
1219     d->certificateVerificationDialog = certificateVerificationDialog;
1220     emit certificateVerificationDialogChanged();
1221 }
1222
1223 QQmlComponent* QQuickWebViewExperimental::itemSelector() const
1224 {
1225     Q_D(const QQuickWebView);
1226     return d->itemSelector;
1227 }
1228
1229 void QQuickWebViewExperimental::setItemSelector(QQmlComponent* itemSelector)
1230 {
1231     Q_D(QQuickWebView);
1232     if (d->itemSelector == itemSelector)
1233         return;
1234     d->itemSelector = itemSelector;
1235     emit itemSelectorChanged();
1236 }
1237
1238 QQmlComponent* QQuickWebViewExperimental::filePicker() const
1239 {
1240     Q_D(const QQuickWebView);
1241     return d->filePicker;
1242 }
1243
1244 void QQuickWebViewExperimental::setFilePicker(QQmlComponent* filePicker)
1245 {
1246     Q_D(QQuickWebView);
1247     if (d->filePicker == filePicker)
1248         return;
1249     d->filePicker = filePicker;
1250     emit filePickerChanged();
1251 }
1252
1253 QQmlComponent* QQuickWebViewExperimental::databaseQuotaDialog() const
1254 {
1255     Q_D(const QQuickWebView);
1256     return d->databaseQuotaDialog;
1257 }
1258
1259 void QQuickWebViewExperimental::setDatabaseQuotaDialog(QQmlComponent* databaseQuotaDialog)
1260 {
1261     Q_D(QQuickWebView);
1262     if (d->databaseQuotaDialog == databaseQuotaDialog)
1263         return;
1264     d->databaseQuotaDialog = databaseQuotaDialog;
1265     emit databaseQuotaDialogChanged();
1266 }
1267
1268 QQmlComponent* QQuickWebViewExperimental::colorChooser() const
1269 {
1270     Q_D(const QQuickWebView);
1271     return d->colorChooser;
1272 }
1273
1274 void QQuickWebViewExperimental::setColorChooser(QQmlComponent* colorChooser)
1275 {
1276     Q_D(QQuickWebView);
1277     if (d->colorChooser == colorChooser)
1278         return;
1279
1280     d->colorChooser = colorChooser;
1281     emit colorChooserChanged();
1282 }
1283
1284 QString QQuickWebViewExperimental::userAgent() const
1285 {
1286     Q_D(const QQuickWebView);
1287     WKRetainPtr<WKStringRef> ua = adoptWK(WKPageCopyCustomUserAgent(d->webPage.get()));
1288     return WKStringCopyQString(ua.get());
1289 }
1290
1291 void QQuickWebViewExperimental::setUserAgent(const QString& userAgent)
1292 {
1293     Q_D(QQuickWebView);
1294     WKRetainPtr<WKStringRef> newUserAgent = adoptWK(WKStringCreateWithQString(userAgent));
1295     WKRetainPtr<WKStringRef> currentUserAgent = adoptWK(WKPageCopyCustomUserAgent(d->webPage.get()));
1296     if (WKStringIsEqual(newUserAgent.get(), currentUserAgent.get()))
1297         return;
1298
1299     WKPageSetCustomUserAgent(d->webPage.get(), newUserAgent.get());
1300     emit userAgentChanged();
1301 }
1302
1303 /*!
1304     \internal
1305
1306     \qmlproperty int WebViewExperimental::deviceWidth
1307     \brief The device width used by the viewport calculations.
1308
1309     The value used when calculation the viewport, eg. what is used for 'device-width' when
1310     used in the viewport meta tag. If unset (zero or negative width), the width of the
1311     actual viewport is used instead.
1312 */
1313
1314 int QQuickWebViewExperimental::deviceWidth() const
1315 {
1316     Q_D(const QQuickWebView);
1317     return d->webPageProxy->pageGroup()->preferences()->deviceWidth();
1318 }
1319
1320 void QQuickWebViewExperimental::setDeviceWidth(int value)
1321 {
1322     Q_D(QQuickWebView);
1323     d->webPageProxy->pageGroup()->preferences()->setDeviceWidth(qMax(0, value));
1324     emit deviceWidthChanged();
1325 }
1326
1327 /*!
1328     \internal
1329
1330     \qmlproperty int WebViewExperimental::deviceHeight
1331     \brief The device width used by the viewport calculations.
1332
1333     The value used when calculation the viewport, eg. what is used for 'device-height' when
1334     used in the viewport meta tag. If unset (zero or negative height), the height of the
1335     actual viewport is used instead.
1336 */
1337
1338 int QQuickWebViewExperimental::deviceHeight() const
1339 {
1340     Q_D(const QQuickWebView);
1341     return d->webPageProxy->pageGroup()->preferences()->deviceHeight();
1342 }
1343
1344 void QQuickWebViewExperimental::setDeviceHeight(int value)
1345 {
1346     Q_D(QQuickWebView);
1347     d->webPageProxy->pageGroup()->preferences()->setDeviceHeight(qMax(0, value));
1348     emit deviceHeightChanged();
1349 }
1350
1351 /*!
1352     \internal
1353
1354     \qmlmethod void WebViewExperimental::evaluateJavaScript(string script [, function(result)])
1355
1356     \brief Evaluates the specified JavaScript and, if supplied, calls a function with the result.
1357 */
1358
1359 void QQuickWebViewExperimental::evaluateJavaScript(const QString& script, const QJSValue& value)
1360 {
1361     JSCallbackClosure* closure = new JSCallbackClosure;
1362
1363     closure->receiver = this;
1364     closure->value = value;
1365
1366     WKRetainPtr<WKStringRef> scriptString = adoptWK(WKStringCreateWithQString(script));
1367     WKPageRunJavaScriptInMainFrame(d_ptr->webPage.get(), scriptString.get(), closure, javaScriptCallback);
1368 }
1369
1370 void QQuickWebViewExperimental::findText(const QString& string, FindFlags options)
1371 {
1372     Q_D(QQuickWebView);
1373     if (string.isEmpty()) {
1374         WKPageHideFindUI(d->webPage.get());
1375         return;
1376     }
1377
1378     WKFindOptions wkOptions = kWKFindOptionsCaseInsensitive;
1379     if (options & FindCaseSensitively)
1380         wkOptions = wkOptions & ~kWKFindOptionsCaseInsensitive;
1381     if (options & FindBackward)
1382         wkOptions |= kWKFindOptionsBackwards;
1383     if (options & FindWrapsAroundDocument)
1384         wkOptions |= kWKFindOptionsWrapAround;
1385     if (options & FindHighlightAllOccurrences)
1386         wkOptions |= kWKFindOptionsShowHighlight;
1387
1388     WKRetainPtr<WKStringRef> str = adoptWK(WKStringCreateWithQString(string));
1389
1390     WKPageFindString(d->webPage.get(), str.get(), wkOptions, std::numeric_limits<unsigned>::max() - 1);
1391 }
1392
1393 QList<QUrl> QQuickWebViewExperimental::userScripts() const
1394 {
1395     Q_D(const QQuickWebView);
1396     return d->userScripts;
1397 }
1398
1399 void QQuickWebViewExperimental::setUserScripts(const QList<QUrl>& userScripts)
1400 {
1401     Q_D(QQuickWebView);
1402     if (d->userScripts == userScripts)
1403         return;
1404     d->userScripts = userScripts;
1405     d->updateUserScripts();
1406     emit userScriptsChanged();
1407 }
1408
1409 QUrl QQuickWebViewExperimental::remoteInspectorUrl() const
1410 {
1411 #if ENABLE(INSPECTOR_SERVER)
1412     return QUrl(WebInspectorServer::shared().inspectorUrlForPageID(d_ptr->webPageProxy->inspector()->remoteInspectionPageID()));
1413 #else
1414     return QUrl();
1415 #endif
1416 }
1417
1418 QQuickUrlSchemeDelegate* QQuickWebViewExperimental::schemeDelegates_At(QQmlListProperty<QQuickUrlSchemeDelegate>* property, int index)
1419 {
1420     const QObjectList children = property->object->children();
1421     if (index < children.count())
1422         return static_cast<QQuickUrlSchemeDelegate*>(children.at(index));
1423     return 0;
1424 }
1425
1426 void QQuickWebViewExperimental::schemeDelegates_Append(QQmlListProperty<QQuickUrlSchemeDelegate>* property, QQuickUrlSchemeDelegate *scheme)
1427 {
1428     if (!scheme->scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive)) {
1429         qWarning("WARNING: The qrc scheme is reserved to be handled internally. The handler will be ignored.");
1430         delete scheme;
1431         return;
1432     }
1433
1434     QObject* schemeParent = property->object;
1435     scheme->setParent(schemeParent);
1436     QQuickWebViewExperimental* webViewExperimental = qobject_cast<QQuickWebViewExperimental*>(property->object->parent());
1437     if (!webViewExperimental)
1438         return;
1439     scheme->reply()->setWebViewExperimental(webViewExperimental);
1440     QQuickWebViewPrivate* d = webViewExperimental->d_func();
1441     d->webPageProxy->registerApplicationScheme(scheme->scheme());
1442 }
1443
1444 int QQuickWebViewExperimental::schemeDelegates_Count(QQmlListProperty<QQuickUrlSchemeDelegate>* property)
1445 {
1446     return property->object->children().count();
1447 }
1448
1449 void QQuickWebViewExperimental::schemeDelegates_Clear(QQmlListProperty<QQuickUrlSchemeDelegate>* property)
1450 {
1451     const QObjectList children = property->object->children();
1452     for (int index = 0; index < children.count(); index++) {
1453         QObject* child = children.at(index);
1454         child->setParent(0);
1455         delete child;
1456     }
1457 }
1458
1459 QQmlListProperty<QQuickUrlSchemeDelegate> QQuickWebViewExperimental::schemeDelegates()
1460 {
1461     return QQmlListProperty<QQuickUrlSchemeDelegate>(schemeParent, 0,
1462             QQuickWebViewExperimental::schemeDelegates_Append,
1463             QQuickWebViewExperimental::schemeDelegates_Count,
1464             QQuickWebViewExperimental::schemeDelegates_At,
1465             QQuickWebViewExperimental::schemeDelegates_Clear);
1466 }
1467
1468 void QQuickWebViewExperimental::invokeApplicationSchemeHandler(PassRefPtr<QtRefCountedNetworkRequestData> request)
1469 {
1470     RefPtr<QtRefCountedNetworkRequestData> req = request;
1471     if (req->data().m_scheme.startsWith("qrc", false)) {
1472         QQuickQrcSchemeDelegate qrcDelegate(QUrl(QString(req->data().m_urlString)));
1473         qrcDelegate.request()->setNetworkRequestData(req);
1474         qrcDelegate.reply()->setNetworkRequestData(req);
1475         qrcDelegate.reply()->setWebViewExperimental(this);
1476         qrcDelegate.readResourceAndSend();
1477         return;
1478     }
1479
1480     const QObjectList children = schemeParent->children();
1481     for (int index = 0; index < children.count(); index++) {
1482         QQuickUrlSchemeDelegate* delegate = qobject_cast<QQuickUrlSchemeDelegate*>(children.at(index));
1483         if (!delegate)
1484             continue;
1485         if (!delegate->scheme().compare(QString(req->data().m_scheme), Qt::CaseInsensitive)) {
1486             delegate->request()->setNetworkRequestData(req);
1487             delegate->reply()->setNetworkRequestData(req);
1488             emit delegate->receivedRequest();
1489             return;
1490         }
1491     }
1492 }
1493
1494 void QQuickWebViewExperimental::sendApplicationSchemeReply(QQuickNetworkReply* reply)
1495 {
1496     d_ptr->webPageProxy->sendApplicationSchemeReply(reply);
1497 }
1498
1499 void QQuickWebViewExperimental::goForwardTo(int index)
1500 {
1501     d_ptr->navigationHistory->d->goForwardTo(index);
1502 }
1503
1504 void QQuickWebViewExperimental::goBackTo(int index)
1505 {
1506     d_ptr->navigationHistory->d->goBackTo(index);
1507 }
1508
1509 QWebKitTest* QQuickWebViewExperimental::test()
1510 {
1511     return m_test;
1512 }
1513
1514 QQuickWebPage* QQuickWebViewExperimental::page()
1515 {
1516     return q_ptr->page();
1517 }
1518
1519 /*!
1520     \page index.html
1521     \title QtWebKit: QML WebView version 3.0
1522
1523     The WebView API allows QML applications to render regions of dynamic
1524     web content. A \e{WebView} component may share the screen with other
1525     QML components or encompass the full screen as specified within the
1526     QML application.
1527
1528     QML WebView version 3.0 is incompatible with previous QML \l
1529     {QtWebKit1::WebView} {WebView} API versions.  It allows an
1530     application to load pages into the WebView, either by URL or with
1531     an HTML string, and navigate within session history.  By default,
1532     links to different pages load within the same WebView, but applications
1533     may intercept requests to delegate links to other functions.
1534
1535     This sample QML application loads a web page, responds to session
1536     history context, and intercepts requests for external links:
1537
1538     \code
1539     import QtQuick 2.0
1540     import QtWebKit 3.0
1541
1542     Page {
1543         WebView {
1544             id: webview
1545             url: "http://qt-project.org"
1546             width: parent.width
1547             height: parent.height
1548             onNavigationRequested: {
1549                 // detect URL scheme prefix, most likely an external link
1550                 var schemaRE = /^\w+:/;
1551                 if (schemaRE.test(request.url)) {
1552                     request.action = WebView.AcceptRequest;
1553                 } else {
1554                     request.action = WebView.IgnoreRequest;
1555                     // delegate request.url here
1556                 }
1557             }
1558         }
1559     }
1560     \endcode
1561
1562     \section1 Examples
1563
1564     There are several Qt WebKit examples located in the
1565     \l{Qt WebKit Examples} page.
1566
1567 */
1568
1569
1570 /*!
1571     \qmltype WebView
1572     \instantiates QQuickWebView
1573     \inqmlmodule QtWebKit 3.0
1574     \brief A WebView renders web content within a QML application
1575 */
1576
1577 QQuickWebView::QQuickWebView(QQuickItem* parent)
1578     : QQuickFlickable(parent)
1579     , d_ptr(createPrivateObject(this))
1580 {
1581     Q_D(QQuickWebView);
1582     d->initialize();
1583 }
1584
1585 QQuickWebView::QQuickWebView(WKContextRef contextRef, WKPageGroupRef pageGroupRef, QQuickItem* parent)
1586     : QQuickFlickable(parent)
1587     , d_ptr(createPrivateObject(this))
1588 {
1589     Q_D(QQuickWebView);
1590     d->initialize(contextRef, pageGroupRef);
1591 }
1592
1593 QQuickWebView::~QQuickWebView()
1594 {
1595 }
1596
1597 QQuickWebPage* QQuickWebView::page()
1598 {
1599     Q_D(QQuickWebView);
1600     return d->pageView.data();
1601 }
1602
1603 /*!
1604     \qmlmethod void WebView::goBack()
1605
1606     Go backward within the browser's session history, if possible.
1607     (Equivalent to the \c{window.history.back()} DOM method.)
1608
1609     \sa WebView::canGoBack
1610 */
1611 void QQuickWebView::goBack()
1612 {
1613     Q_D(QQuickWebView);
1614     WKPageGoBack(d->webPage.get());
1615 }
1616
1617 /*!
1618     \qmlmethod void WebView::goForward()
1619
1620     Go forward within the browser's session history, if possible.
1621     (Equivalent to the \c{window.history.forward()} DOM method.)
1622 */
1623 void QQuickWebView::goForward()
1624 {
1625     Q_D(QQuickWebView);
1626     WKPageGoForward(d->webPage.get());
1627 }
1628
1629 /*!
1630     \qmlmethod void WebView::stop()
1631
1632     Stop loading the current page.
1633 */
1634 void QQuickWebView::stop()
1635 {
1636     Q_D(QQuickWebView);
1637     WKPageStopLoading(d->webPage.get());
1638 }
1639
1640 /*!
1641     \qmlmethod void WebView::reload()
1642
1643     Reload the current page. (Equivalent to the
1644     \c{window.location.reload()} DOM method.)
1645 */
1646 void QQuickWebView::reload()
1647 {
1648     Q_D(QQuickWebView);
1649
1650     WebFrameProxy* mainFrame = d->webPageProxy->mainFrame();
1651     if (mainFrame && !mainFrame->unreachableURL().isEmpty() && mainFrame->url() != blankURL()) {
1652         // We are aware of the unreachable url on the UI process side, but since we haven't
1653         // loaded alternative/subsitute data for it (an error page eg.) WebCore doesn't know
1654         // about the unreachable url yet. If we just do a reload at this point WebCore will try to
1655         // reload the currently committed url instead of the unrachable url. To work around this
1656         // we override the reload here by doing a manual load.
1657         d->webPageProxy->loadURL(mainFrame->unreachableURL());
1658         // FIXME: We should make WebCore aware of the unreachable url regardless of substitute-loads
1659         return;
1660     }
1661
1662     WKPageReloadFromOrigin(d->webPage.get());
1663 }
1664
1665 /*!
1666     \qmlproperty url WebView::url
1667
1668     The location of the currently displaying HTML page. This writable
1669     property offers the main interface to load a page into a web view.
1670     It functions the same as the \c{window.location} DOM property.
1671
1672     \sa WebView::loadHtml()
1673 */
1674 QUrl QQuickWebView::url() const
1675 {
1676     Q_D(const QQuickWebView);
1677
1678     // FIXME: Enable once we are sure this should not trigger
1679     // Q_ASSERT(d->m_currentUrl == d->webPageProxy->activeURL());
1680
1681     return QUrl(d->m_currentUrl);
1682 }
1683
1684 void QQuickWebView::setUrl(const QUrl& url)
1685 {
1686     Q_D(QQuickWebView);
1687
1688     if (url.isEmpty())
1689         return;
1690
1691     WKRetainPtr<WKURLRef> u = adoptWK(WKURLCreateWithQUrl(url));
1692     WKPageLoadURL(d->webPage.get(), u.get());
1693     emitUrlChangeIfNeeded();
1694 }
1695
1696 // Make sure we don't emit urlChanged unless it actually changed
1697 void QQuickWebView::emitUrlChangeIfNeeded()
1698 {
1699     Q_D(QQuickWebView);
1700
1701     WTF::String activeUrl = d->webPageProxy->activeURL();
1702     if (activeUrl != d->m_currentUrl) {
1703         d->m_currentUrl = activeUrl;
1704         emit urlChanged();
1705     }
1706 }
1707
1708 /*!
1709     \qmlproperty url WebView::icon
1710
1711     The location of the currently displaying Web site icon, also known as favicon
1712     or shortcut icon. This read-only URL corresponds to the image used within a
1713     mobile browser application to represent a bookmarked page on the device's home
1714     screen.
1715
1716     This example uses the \c{icon} property to build an \c{Image} element:
1717
1718     \code
1719     Image {
1720         id: appIcon
1721         source: webView.icon != "" ? webView.icon : "fallbackFavIcon.png";
1722         ...
1723     }
1724     \endcode
1725 */
1726 QUrl QQuickWebView::icon() const
1727 {
1728     Q_D(const QQuickWebView);
1729     return QUrl(d->m_iconUrl);
1730 }
1731
1732 /*!
1733     \qmlproperty int WebView::loadProgress
1734
1735     The amount of the page that has been loaded, expressed as an integer
1736     percentage in the range from \c{0} to \c{100}.
1737 */
1738 int QQuickWebView::loadProgress() const
1739 {
1740     Q_D(const QQuickWebView);
1741     return d->loadProgress();
1742 }
1743
1744 /*!
1745     \qmlproperty bool WebView::canGoBack
1746
1747     Returns \c{true} if there are prior session history entries, \c{false}
1748     otherwise.
1749 */
1750 bool QQuickWebView::canGoBack() const
1751 {
1752     Q_D(const QQuickWebView);
1753     return WKPageCanGoBack(d->webPage.get());
1754 }
1755
1756 /*!
1757     \qmlproperty bool WebView::canGoForward
1758
1759     Returns \c{true} if there are subsequent session history entries,
1760     \c{false} otherwise.
1761 */
1762 bool QQuickWebView::canGoForward() const
1763 {
1764     Q_D(const QQuickWebView);
1765     return WKPageCanGoForward(d->webPage.get());
1766 }
1767
1768 /*!
1769     \qmlproperty bool WebView::loading
1770
1771     Returns \c{true} if the HTML page is currently loading, \c{false} otherwise.
1772 */
1773 bool QQuickWebView::loading() const
1774 {
1775     Q_D(const QQuickWebView);
1776     WKFrameRef mainFrame = WKPageGetMainFrame(d->webPage.get());
1777     return mainFrame && !(kWKFrameLoadStateFinished == WKFrameGetFrameLoadState(mainFrame));
1778 }
1779
1780 /*!
1781     \internal
1782  */
1783
1784 QPointF QQuickWebView::mapToWebContent(const QPointF& pointInViewCoordinates) const
1785 {
1786     Q_D(const QQuickWebView);
1787     return d->pageView->transformFromItem().map(pointInViewCoordinates);
1788 }
1789
1790 /*!
1791     \internal
1792  */
1793
1794 QRectF QQuickWebView::mapRectToWebContent(const QRectF& rectInViewCoordinates) const
1795 {
1796     Q_D(const QQuickWebView);
1797     return d->pageView->transformFromItem().mapRect(rectInViewCoordinates);
1798 }
1799
1800 /*!
1801     \internal
1802  */
1803
1804 QPointF QQuickWebView::mapFromWebContent(const QPointF& pointInCSSCoordinates) const
1805 {
1806     Q_D(const QQuickWebView);
1807     return d->pageView->transformToItem().map(pointInCSSCoordinates);
1808 }
1809
1810 /*!
1811     \internal
1812  */
1813 QRectF QQuickWebView::mapRectFromWebContent(const QRectF& rectInCSSCoordinates) const
1814 {
1815     Q_D(const QQuickWebView);
1816     return d->pageView->transformToItem().mapRect(rectInCSSCoordinates);
1817 }
1818
1819 /*!
1820     \qmlproperty string WebView::title
1821
1822     The title of the currently displaying HTML page, a read-only value
1823     that reflects the contents of the \c{<title>} tag.
1824 */
1825 QString QQuickWebView::title() const
1826 {
1827     Q_D(const QQuickWebView);
1828     WKRetainPtr<WKStringRef> t = adoptWK(WKPageCopyTitle(d->webPage.get()));
1829     return WKStringCopyQString(t.get());
1830 }
1831
1832 QVariant QQuickWebView::inputMethodQuery(Qt::InputMethodQuery property) const
1833 {
1834     Q_D(const QQuickWebView);
1835     const EditorState& state = d->webPageProxy->editorState();
1836
1837     switch(property) {
1838     case Qt::ImCursorRectangle:
1839         return QRectF(state.cursorRect);
1840     case Qt::ImFont:
1841         return QVariant();
1842     case Qt::ImCursorPosition:
1843         return QVariant(static_cast<int>(state.cursorPosition));
1844     case Qt::ImAnchorPosition:
1845         return QVariant(static_cast<int>(state.anchorPosition));
1846     case Qt::ImSurroundingText:
1847         return QString(state.surroundingText);
1848     case Qt::ImCurrentSelection:
1849         return QString(state.selectedText);
1850     case Qt::ImMaximumTextLength:
1851         return QVariant(); // No limit.
1852     case Qt::ImHints:
1853         return int(Qt::InputMethodHints(state.inputMethodHints));
1854     default:
1855         // Rely on the base implementation for ImEnabled, ImHints and ImPreferredLanguage.
1856         return QQuickFlickable::inputMethodQuery(property);
1857     }
1858 }
1859
1860 /*!
1861     internal
1862
1863     The experimental module consisting on experimental API which will break
1864     from version to version.
1865 */
1866 QQuickWebViewExperimental* QQuickWebView::experimental() const
1867 {
1868     Q_D(const QQuickWebView);
1869     return d->experimental;
1870 }
1871
1872 /*!
1873     \internal
1874 */
1875 void QQuickWebView::platformInitialize()
1876 {
1877     JSC::initializeThreading();
1878     WTF::initializeMainThread();
1879 }
1880
1881 bool QQuickWebView::childMouseEventFilter(QQuickItem* item, QEvent* event)
1882 {
1883     if (!isVisible() || !isEnabled())
1884         return false;
1885
1886     // This function is used by MultiPointTouchArea and PinchArea to filter
1887     // touch events, thus to hinder the canvas from sending synthesized
1888     // mouse events to the Flickable implementation we need to reimplement
1889     // childMouseEventFilter to ignore touch and mouse events.
1890
1891     switch (event->type()) {
1892     case QEvent::MouseButtonPress:
1893     case QEvent::MouseMove:
1894     case QEvent::MouseButtonRelease:
1895     case QEvent::TouchBegin:
1896     case QEvent::TouchUpdate:
1897     case QEvent::TouchEnd:
1898         // Force all mouse and touch events through the default propagation path.
1899         return false;
1900     default:
1901         ASSERT(event->type() == QEvent::UngrabMouse);
1902         break;
1903     }
1904
1905     return QQuickFlickable::childMouseEventFilter(item, event);
1906 }
1907
1908 void QQuickWebView::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry)
1909 {
1910     Q_D(QQuickWebView);
1911     QQuickFlickable::geometryChanged(newGeometry, oldGeometry);
1912     if (newGeometry.size() != oldGeometry.size())
1913         d->updateViewportSize();
1914 }
1915
1916 void QQuickWebView::componentComplete()
1917 {
1918     Q_D(QQuickWebView);
1919     QQuickFlickable::componentComplete();
1920
1921     d->onComponentComplete();
1922     d->updateViewportSize();
1923 }
1924
1925 void QQuickWebView::keyPressEvent(QKeyEvent* event)
1926 {
1927     Q_D(QQuickWebView);
1928     d->pageView->eventHandler()->handleKeyPressEvent(event);
1929 }
1930
1931 void QQuickWebView::keyReleaseEvent(QKeyEvent* event)
1932 {
1933     Q_D(QQuickWebView);
1934     d->pageView->eventHandler()->handleKeyReleaseEvent(event);
1935 }
1936
1937 void QQuickWebView::inputMethodEvent(QInputMethodEvent* event)
1938 {
1939     Q_D(QQuickWebView);
1940     d->pageView->eventHandler()->handleInputMethodEvent(event);
1941 }
1942
1943 void QQuickWebView::focusInEvent(QFocusEvent* event)
1944 {
1945     Q_D(QQuickWebView);
1946     d->pageView->eventHandler()->handleFocusInEvent(event);
1947 }
1948
1949 void QQuickWebView::itemChange(ItemChange change, const ItemChangeData &value)
1950 {
1951     Q_D(QQuickWebView);
1952     if (change == ItemActiveFocusHasChanged) {
1953         bool focus = value.boolValue;
1954         if (!focus)
1955             d->pageView->eventHandler()->handleFocusLost();
1956     }
1957     QQuickFlickable::itemChange(change, value);
1958 }
1959
1960 void QQuickWebView::touchEvent(QTouchEvent* event)
1961 {
1962     Q_D(QQuickWebView);
1963
1964     bool lockingDisabled = flickableDirection() != AutoFlickDirection
1965                            || event->touchPoints().size() != 1
1966                            || width() >= contentWidth()
1967                            || height() >= contentHeight();
1968
1969     if (!lockingDisabled)
1970         d->axisLocker.update(event);
1971     else
1972         d->axisLocker.reset();
1973
1974     forceActiveFocus();
1975     d->pageView->eventHandler()->handleTouchEvent(event);
1976 }
1977
1978 void QQuickWebView::mousePressEvent(QMouseEvent* event)
1979 {
1980     Q_D(QQuickWebView);
1981     forceActiveFocus();
1982     d->handleMouseEvent(event);
1983 }
1984
1985 void QQuickWebView::mouseMoveEvent(QMouseEvent* event)
1986 {
1987     Q_D(QQuickWebView);
1988     d->handleMouseEvent(event);
1989 }
1990
1991 void QQuickWebView::mouseReleaseEvent(QMouseEvent* event)
1992 {
1993     Q_D(QQuickWebView);
1994     d->handleMouseEvent(event);
1995 }
1996
1997 void QQuickWebView::mouseDoubleClickEvent(QMouseEvent* event)
1998 {
1999     Q_D(QQuickWebView);
2000     forceActiveFocus();
2001     d->handleMouseEvent(event);
2002 }
2003
2004 void QQuickWebView::wheelEvent(QWheelEvent* event)
2005 {
2006     Q_D(QQuickWebView);
2007     d->pageView->eventHandler()->handleWheelEvent(event);
2008 }
2009
2010 void QQuickWebView::hoverEnterEvent(QHoverEvent* event)
2011 {
2012     Q_D(QQuickWebView);
2013     // Map HoverEnter to Move, for WebKit the distinction doesn't matter.
2014     d->pageView->eventHandler()->handleHoverMoveEvent(event);
2015 }
2016
2017 void QQuickWebView::hoverMoveEvent(QHoverEvent* event)
2018 {
2019     Q_D(QQuickWebView);
2020     d->pageView->eventHandler()->handleHoverMoveEvent(event);
2021 }
2022
2023 void QQuickWebView::hoverLeaveEvent(QHoverEvent* event)
2024 {
2025     Q_D(QQuickWebView);
2026     d->pageView->eventHandler()->handleHoverLeaveEvent(event);
2027 }
2028
2029 void QQuickWebView::dragMoveEvent(QDragMoveEvent* event)
2030 {
2031     Q_D(QQuickWebView);
2032     d->pageView->eventHandler()->handleDragMoveEvent(event);
2033 }
2034
2035 void QQuickWebView::dragEnterEvent(QDragEnterEvent* event)
2036 {
2037     Q_D(QQuickWebView);
2038     d->pageView->eventHandler()->handleDragEnterEvent(event);
2039 }
2040
2041 void QQuickWebView::dragLeaveEvent(QDragLeaveEvent* event)
2042 {
2043     Q_D(QQuickWebView);
2044     d->pageView->eventHandler()->handleDragLeaveEvent(event);
2045 }
2046
2047 void QQuickWebView::dropEvent(QDropEvent* event)
2048 {
2049     Q_D(QQuickWebView);
2050     d->pageView->eventHandler()->handleDropEvent(event);
2051 }
2052
2053 bool QQuickWebView::event(QEvent* ev)
2054 {
2055     // Re-implemented for possible future use without breaking binary compatibility.
2056     return QQuickFlickable::event(ev);
2057 }
2058
2059 WKPageRef QQuickWebView::pageRef() const
2060 {
2061     Q_D(const QQuickWebView);
2062     return d->webPage.get();
2063 }
2064
2065 QPointF QQuickWebView::contentPos() const
2066 {
2067     Q_D(const QQuickWebView);
2068     return d->contentPos();
2069 }
2070
2071 void QQuickWebView::setContentPos(const QPointF& pos)
2072 {
2073     Q_D(QQuickWebView);
2074
2075     if (pos == contentPos())
2076         return;
2077
2078     d->setContentPos(pos);
2079 }
2080
2081 void QQuickWebView::handleFlickableMousePress(const QPointF& position, qint64 eventTimestampMillis)
2082 {
2083     Q_D(QQuickWebView);
2084     d->axisLocker.setReferencePosition(position);
2085     QMouseEvent mouseEvent(QEvent::MouseButtonPress, position, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
2086     mouseEvent.setTimestamp(eventTimestampMillis);
2087     QQuickFlickable::mousePressEvent(&mouseEvent);
2088 }
2089
2090 void QQuickWebView::handleFlickableMouseMove(const QPointF& position, qint64 eventTimestampMillis)
2091 {
2092     Q_D(QQuickWebView);
2093     QMouseEvent mouseEvent(QEvent::MouseMove, d->axisLocker.adjust(position), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
2094     mouseEvent.setTimestamp(eventTimestampMillis);
2095     QQuickFlickable::mouseMoveEvent(&mouseEvent);
2096 }
2097
2098 void QQuickWebView::handleFlickableMouseRelease(const QPointF& position, qint64 eventTimestampMillis)
2099 {
2100     Q_D(QQuickWebView);
2101     QMouseEvent mouseEvent(QEvent::MouseButtonRelease, d->axisLocker.adjust(position), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
2102     d->axisLocker.reset();
2103     mouseEvent.setTimestamp(eventTimestampMillis);
2104     QQuickFlickable::mouseReleaseEvent(&mouseEvent);
2105 }
2106
2107 /*!
2108     \qmlmethod void WebView::loadHtml(string html, url baseUrl, url unreachableUrl)
2109     \brief Loads the specified \a html as the content of the web view.
2110
2111     (This method offers a lower-level alternative to the \c{url} property,
2112     which references HTML pages via URL.)
2113
2114     External objects such as stylesheets or images referenced in the HTML
2115     document are located relative to \a baseUrl. For example if provided \a html
2116     was originally retrieved from \c http://www.example.com/documents/overview.html
2117     and that was the base url, then an image referenced with the relative url \c diagram.png
2118     would be looked for at \c{http://www.example.com/documents/diagram.png}.
2119
2120     If an \a unreachableUrl is passed it is used as the url for the loaded
2121     content. This is typically used to display error pages for a failed
2122     load.
2123
2124     \sa WebView::url
2125 */
2126 void QQuickWebView::loadHtml(const QString& html, const QUrl& baseUrl, const QUrl& unreachableUrl)
2127 {
2128     Q_D(QQuickWebView);
2129     WKRetainPtr<WKStringRef> htmlRef = adoptWK(WKStringCreateWithQString(html));
2130     WKRetainPtr<WKURLRef> baseUrlRef = adoptWK(WKURLCreateWithQUrl(baseUrl));
2131     WKRetainPtr<WKURLRef> unreachableUrlRef = adoptWK(WKURLCreateWithQUrl(unreachableUrl));
2132
2133     if (unreachableUrl.isValid())
2134         WKPageLoadAlternateHTMLString(d->webPage.get(), htmlRef.get(), baseUrlRef.get(), unreachableUrlRef.get());
2135     else
2136         WKPageLoadHTMLString(d->webPage.get(), htmlRef.get(), baseUrlRef.get());
2137 }
2138
2139 qreal QQuickWebView::zoomFactor() const
2140 {
2141     Q_D(const QQuickWebView);
2142     return d->zoomFactor();
2143 }
2144
2145 void QQuickWebView::setZoomFactor(qreal factor)
2146 {
2147
2148     Q_D(QQuickWebView);
2149     d->setZoomFactor(factor);
2150 }
2151
2152 void QQuickWebView::runJavaScriptInMainFrame(const QString &script, QObject *receiver, const char *method)
2153 {
2154     Q_D(QQuickWebView);
2155
2156     JSCallbackClosure* closure = new JSCallbackClosure;
2157     closure->receiver = receiver;
2158     closure->method = method;
2159
2160     WKRetainPtr<WKStringRef> scriptString = adoptWK(WKStringCreateWithQString(script));
2161     WKPageRunJavaScriptInMainFrame(d->webPage.get(), scriptString.get(), closure, javaScriptCallback);
2162 }
2163
2164 bool QQuickWebView::allowAnyHTTPSCertificateForLocalHost() const
2165 {
2166     Q_D(const QQuickWebView);
2167     return d->m_allowAnyHTTPSCertificateForLocalHost;
2168 }
2169
2170 void QQuickWebView::setAllowAnyHTTPSCertificateForLocalHost(bool allow)
2171 {
2172     Q_D(QQuickWebView);
2173     d->m_allowAnyHTTPSCertificateForLocalHost = allow;
2174 }
2175
2176 void QQuickWebViewPrivate::didFindString(WKPageRef, WKStringRef, unsigned matchCount, const void* clientInfo)
2177 {
2178     QQuickWebView* q = toQQuickWebViewPrivate(clientInfo)->q_ptr;
2179     emit q->experimental()->textFound(matchCount);
2180 }
2181
2182 void QQuickWebViewPrivate::didFailToFindString(WKPageRef page, WKStringRef string, const void* clientInfo)
2183 {
2184     QQuickWebViewPrivate::didFindString(page, string, 0, clientInfo);
2185 }
2186
2187 /*!
2188     \qmlsignal WebView::onLoadingChanged(loadRequest)
2189
2190     Occurs when any page load begins, ends, or fails. Various read-only
2191     parameters are available on the \a loadRequest:
2192
2193     \list
2194
2195     \li \c{url}: the location of the resource that is loading.
2196
2197     \li \c{status}: Reflects one of three load states:
2198        \c{LoadStartedStatus}, \c{LoadSucceededStatus}, or
2199        \c{LoadFailedStatus}. See \c{WebView::LoadStatus}.
2200
2201     \li \c{errorString}: description of load error.
2202
2203     \li \c{errorCode}: HTTP error code.
2204
2205     \li \c{errorDomain}: high-level error types, one of
2206     \c{NetworkErrorDomain}, \c{HttpErrorDomain}, \c{InternalErrorDomain},
2207     \c{DownloadErrorDomain}, or \c{NoErrorDomain}.  See
2208     \l{WebView::ErrorDomain}.
2209
2210     \endlist
2211
2212     \sa WebView::loading
2213 */
2214
2215 /*!
2216     \qmlsignal WebView::onLinkHovered(hoveredUrl, hoveredTitle)
2217
2218     Within a mouse-driven interface, this signal is emitted when a mouse
2219     pointer passes over a link, corresponding to the \c{mouseover} DOM
2220     event.  (May also occur in touch interfaces for \c{mouseover} events
2221     that are not cancelled with \c{preventDefault()}.)  The \a{hoveredUrl}
2222     provides the link's location, and the \a{hoveredTitle} is any avalable
2223     link text.
2224 */
2225
2226 /*!
2227     \qmlsignal WebView::onNavigationRequested(request)
2228
2229     Occurs for various kinds of navigation.  If the application listens
2230     for this signal, it must set the \c{request.action} to either of the
2231     following \l{WebView::NavigationRequestAction} enum values:
2232
2233     \list
2234
2235     \li \c{AcceptRequest}: Allow navigation to external pages within the
2236     web view. This represents the default behavior when no listener is
2237     active.
2238
2239     \li \c{IgnoreRequest}: Suppress navigation to new pages within the web
2240     view.  (The listener may then delegate navigation externally to
2241     the browser application.)
2242
2243     \endlist
2244
2245     The \a{request} also provides the following read-only values:
2246
2247     \list
2248
2249     \li \c{url}: The location of the requested page.
2250
2251     \li \c{navigationType}: contextual information, one of
2252     \c{LinkClickedNavigation}, \c{BackForwardNavigation},
2253     \c{ReloadNavigation}, \c{FormSubmittedNavigation},
2254     \c{FormResubmittedNavigation}, or \c{OtherNavigation} enum values.
2255     See \l{WebView::NavigationType}.
2256
2257     \li \c{keyboardModifiers}: potential states for \l{Qt::KeyboardModifier}.
2258
2259     \li \c{mouseButton}: potential states for \l{Qt::MouseButton}.
2260
2261     \endlist
2262 */
2263
2264 /*!
2265     \qmlproperty enumeration WebView::ErrorDomain
2266
2267     Details various high-level error types.
2268
2269     \table
2270
2271     \header
2272     \li Constant
2273     \li Description
2274
2275     \row
2276     \li InternalErrorDomain
2277     \li Content fails to be interpreted by QtWebKit.
2278
2279     \row
2280     \li NetworkErrorDomain
2281     \li Error results from faulty network connection.
2282
2283     \row
2284     \li HttpErrorDomain
2285     \li Error is produced by server.
2286
2287     \row
2288     \li DownloadErrorDomain
2289     \li Error in saving file.
2290
2291     \row
2292     \li NoErrorDomain
2293     \li Unspecified fallback error.
2294
2295     \endtable
2296 */
2297
2298 /*!
2299     \qmlproperty enumeration WebView::NavigationType
2300
2301     Distinguishes context for various navigation actions.
2302
2303     \table
2304
2305     \header
2306     \li Constant
2307     \li Description
2308
2309     \row
2310     \li LinkClickedNavigation
2311     \li Navigation via link.
2312
2313     \row
2314     \li FormSubmittedNavigation
2315     \li Form data is posted.
2316
2317     \row
2318     \li BackForwardNavigation
2319     \li Navigation back and forth within session history.
2320
2321     \row
2322     \li ReloadNavigation
2323     \li The current page is reloaded.
2324
2325     \row
2326     \li FormResubmittedNavigation
2327     \li Form data is re-posted.
2328
2329     \row
2330     \li OtherNavigation
2331     \li Unspecified fallback method of navigation.
2332
2333     \endtable
2334 */
2335
2336 /*!
2337     \qmlproperty enumeration WebView::LoadStatus
2338
2339     Reflects a page's load status.
2340
2341     \table
2342
2343     \header
2344     \li Constant
2345     \li Description
2346
2347     \row
2348     \li LoadStartedStatus
2349     \li Page is currently loading.
2350
2351     \row
2352     \li LoadSucceededStatus
2353     \li Page has successfully loaded, and is not currently loading.
2354
2355     \row
2356     \li LoadFailedStatus
2357     \li Page has failed to load, and is not currently loading.
2358
2359     \endtable
2360 */
2361
2362 /*!
2363     \qmlproperty enumeration WebView::NavigationRequestAction
2364
2365     Specifies a policy when navigating a link to an external page.
2366
2367     \table
2368
2369     \header
2370     \li Constant
2371     \li Description
2372
2373     \row
2374     \li AcceptRequest
2375     \li Allow navigation to external pages within the web view.
2376
2377     \row
2378     \li IgnoreRequest
2379     \li Suppress navigation to new pages within the web view.
2380
2381     \endtable
2382 */
2383
2384 #include "moc_qquickwebview_p.cpp"