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