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