diff options
Diffstat (limited to 'Source/WebKit2/UIProcess/API/qt/qquickwebview.cpp')
-rw-r--r-- | Source/WebKit2/UIProcess/API/qt/qquickwebview.cpp | 315 |
1 files changed, 231 insertions, 84 deletions
diff --git a/Source/WebKit2/UIProcess/API/qt/qquickwebview.cpp b/Source/WebKit2/UIProcess/API/qt/qquickwebview.cpp index b1b465526..167c50f6a 100644 --- a/Source/WebKit2/UIProcess/API/qt/qquickwebview.cpp +++ b/Source/WebKit2/UIProcess/API/qt/qquickwebview.cpp @@ -27,6 +27,7 @@ #include "QtDownloadManager.h" #include "QtViewportInteractionEngine.h" #include "QtWebContext.h" +#include "QtWebError.h" #include "QtWebIconDatabaseClient.h" #include "QtWebPageEventHandler.h" #include "QtWebPageLoadClient.h" @@ -52,10 +53,14 @@ #include "qwebviewportinfo_p.h" #include <JavaScriptCore/InitializeThreading.h> +#include <JavaScriptCore/JSBase.h> +#include <JavaScriptCore/JSRetainPtr.h> #include <QDateTime> +#include <QtQml/QJSValue> +#include <WKOpenPanelResultListener.h> +#include <WKSerializedScriptValue.h> #include <WebCore/IntPoint.h> #include <WebCore/IntRect.h> -#include <WKOpenPanelResultListener.h> #include <wtf/Assertions.h> #include <wtf/MainThread.h> #include <wtf/text/WTFString.h> @@ -68,6 +73,105 @@ static const int kAxisLockSampleCount = 5; static const qreal kAxisLockVelocityThreshold = 300; static const qreal kAxisLockVelocityDirectionThreshold = 50; +struct JSCallbackClosure { + QPointer<QObject> receiver; + QByteArray method; + QJSValue value; +}; + +static inline QString toQString(JSStringRef string) +{ + return QString(reinterpret_cast<const QChar*>(JSStringGetCharactersPtr(string)), JSStringGetLength(string)); +} + +static inline QJSValue toQJSValue(JSStringRef string) +{ + return QJSValue(toQString(string)); +} + +static QJSValue buildQJSValue(QJSEngine* engine, JSGlobalContextRef context, JSValueRef value, int depth) +{ + QJSValue var; + JSValueRef exception = 0; + + if (depth > 10) + return var; + + switch (JSValueGetType(context, value)) { + case kJSTypeBoolean: + var = QJSValue(JSValueToBoolean(context, value)); + break; + case kJSTypeNumber: + { + double number = JSValueToNumber(context, value, &exception); + if (!exception) + var = QJSValue(number); + } + break; + case kJSTypeString: + { + JSRetainPtr<JSStringRef> string = JSValueToStringCopy(context, value, &exception); + if (!exception) + var = toQJSValue(string.get()); + } + break; + case kJSTypeObject: + { + JSObjectRef obj = JSValueToObject(context, value, &exception); + + JSPropertyNameArrayRef names = JSObjectCopyPropertyNames(context, obj); + size_t length = JSPropertyNameArrayGetCount(names); + + var = engine->newObject(); + + for (size_t i = 0; i < length; ++i) { + JSRetainPtr<JSStringRef> name = JSPropertyNameArrayGetNameAtIndex(names, i); + JSValueRef property = JSObjectGetProperty(context, obj, name.get(), &exception); + + if (!exception) { + QJSValue value = buildQJSValue(engine, context, property, depth + 1); + var.setProperty(toQString(name.get()), value); + } + } + } + break; + } + return var; +} + +static void javaScriptCallback(WKSerializedScriptValueRef valueRef, WKErrorRef, void* data) +{ + JSCallbackClosure* closure = reinterpret_cast<JSCallbackClosure*>(data); + + if (closure->method.size()) + QMetaObject::invokeMethod(closure->receiver, closure->method); + else { + QJSValue function = closure->value; + + // If a callable function is supplied, we build a JavaScript value accessible + // in the QML engine, and calls the function with that. + if (function.isCallable()) { + QJSValue var; + if (valueRef) { + // FIXME: Slow but OK for now. + JSGlobalContextRef context = JSGlobalContextCreate(0); + + JSValueRef exception = 0; + JSValueRef value = WKSerializedScriptValueDeserialize(valueRef, context, &exception); + var = buildQJSValue(function.engine(), context, value, /* depth */ 0); + + JSGlobalContextRelease(context); + } + + QList<QJSValue> args; + args.append(var); + function.call(args); + } + } + + delete closure; +} + static QQuickWebViewPrivate* createPrivateObject(QQuickWebView* publicObject) { if (s_flickableViewportEnabled) @@ -162,6 +266,7 @@ QQuickWebViewPrivate::QQuickWebViewPrivate(QQuickWebView* viewport) , m_navigatorQtObjectEnabled(false) , m_renderToOffscreenBuffer(false) , m_dialogActive(false) + , m_loadProgress(0) { viewport->setClip(true); viewport->setPixelAligned(true); @@ -230,20 +335,72 @@ QPointF QQuickWebViewPrivate::pageItemPos() \qmlsignal WebView::loadingChanged(WebLoadRequest request) */ +void QQuickWebViewPrivate::provisionalLoadDidStart(const QUrl& url) +{ + Q_Q(QQuickWebView); + + QWebLoadRequest loadRequest(url, QQuickWebView::LoadStartedStatus); + emit q->loadingChanged(&loadRequest); +} + +void QQuickWebViewPrivate::loadDidCommit() +{ + Q_Q(QQuickWebView); + ASSERT(q->loading()); + + emit q->navigationHistoryChanged(); + emit q->urlChanged(); + emit q->titleChanged(); +} + +void QQuickWebViewPrivate::didSameDocumentNavigation() +{ + Q_Q(QQuickWebView); + + emit q->navigationHistoryChanged(); + emit q->urlChanged(); +} + +void QQuickWebViewPrivate::titleDidChange() +{ + Q_Q(QQuickWebView); + + emit q->titleChanged(); +} + +void QQuickWebViewPrivate::loadProgressDidChange(int loadProgress) +{ + Q_Q(QQuickWebView); + + if (!loadProgress) + setIcon(QUrl()); + + m_loadProgress = loadProgress; + + emit q->loadProgressChanged(); +} + +void QQuickWebViewPrivate::backForwardListDidChange() +{ + navigationHistory->d->reset(); +} + void QQuickWebViewPrivate::loadDidSucceed() { Q_Q(QQuickWebView); ASSERT(!q->loading()); + QWebLoadRequest loadRequest(q->url(), QQuickWebView::LoadSucceededStatus); emit q->loadingChanged(&loadRequest); } -void QQuickWebViewPrivate::onComponentComplete() +void QQuickWebViewPrivate::loadDidFail(const QtWebError& error) { - if (m_deferedUrlToLoad.isEmpty()) - return; + Q_Q(QQuickWebView); + ASSERT(!q->loading()); - q_ptr->setUrl(m_deferedUrlToLoad); + QWebLoadRequest loadRequest(error.url(), QQuickWebView::LoadFailedStatus, error.description(), static_cast<QQuickWebView::ErrorDomain>(error.type()), error.errorCode()); + emit q->loadingChanged(&loadRequest); } void QQuickWebViewPrivate::setNeedsDisplay() @@ -269,18 +426,22 @@ void QQuickWebViewPrivate::_q_onIconChangedForPageURL(const QUrl& pageURL, const setIcon(iconURL); } -void QQuickWebViewPrivate::didChangeBackForwardList() -{ - navigationHistory->d->reset(); -} - void QQuickWebViewPrivate::processDidCrash() { - pageView->eventHandler()->resetGestureRecognizers(); - pageLoadClient->completeLoadWhenProcessDidCrashIfNeeded(); + Q_Q(QQuickWebView); QUrl url(KURL(WebCore::ParsedURLString, webPageProxy->urlAtProcessExit())); qWarning("WARNING: The web process experienced a crash on '%s'.", qPrintable(url.toString(QUrl::RemoveUserInfo))); + + pageView->eventHandler()->resetGestureRecognizers(); + + // Check if loading was ongoing, when process crashed. + if (m_loadProgress > 0 && m_loadProgress < 100) { + QWebLoadRequest loadRequest(url, QQuickWebView::LoadFailedStatus, QLatin1String("The web process crashed."), QQuickWebView::InternalErrorDomain, 0); + + loadProgressDidChange(100); + emit q->loadingChanged(&loadRequest); + } } void QQuickWebViewPrivate::didRelaunchProcess() @@ -328,7 +489,7 @@ void QQuickWebViewPrivate::_q_onReceivedResponseFromDownload(QWebDownloadItem* d return; Q_Q(QQuickWebView); - QDeclarativeEngine::setObjectOwnership(downloadItem, QDeclarativeEngine::JavaScriptOwnership); + QQmlEngine::setObjectOwnership(downloadItem, QQmlEngine::JavaScriptOwnership); emit q->experimental()->downloadRequested(downloadItem); } @@ -626,7 +787,6 @@ void QQuickWebViewLegacyPrivate::setZoomFactor(qreal factor) QQuickWebViewFlickablePrivate::QQuickWebViewFlickablePrivate(QQuickWebView* viewport) : QQuickWebViewPrivate(viewport) , pageIsSuspended(true) - , loadSuccessDispatchIsPending(false) { // Disable mouse events on the flickable web view so we do not // select text during pan gestures on platforms which send both @@ -689,44 +849,16 @@ void QQuickWebViewFlickablePrivate::onComponentComplete() _q_resume(); - if (loadSuccessDispatchIsPending) { - QQuickWebViewPrivate::loadDidSucceed(); - loadSuccessDispatchIsPending = false; - } - // Trigger setting of correct visibility flags after everything was allocated and initialized. _q_onVisibleChanged(); - - QQuickWebViewPrivate::onComponentComplete(); -} - -void QQuickWebViewFlickablePrivate::loadDidSucceed() -{ - if (interactionEngine) - QQuickWebViewPrivate::loadDidSucceed(); - else - loadSuccessDispatchIsPending = true; -} - -void QQuickWebViewFlickablePrivate::loadDidCommit() -{ - // Due to entering provisional load before committing, we - // might actually be suspended here. -} - -void QQuickWebViewFlickablePrivate::didFinishFirstNonEmptyLayout() -{ } void QQuickWebViewFlickablePrivate::didChangeViewportProperties(const WebCore::ViewportAttributes& newAttributes) { Q_Q(QQuickWebView); - QSize viewportSize = q->boundingRect().size().toSize(); - // FIXME: Revise these when implementing fit-to-width. WebCore::ViewportAttributes attr = newAttributes; - WebCore::restrictMinimumScaleFactorToViewportSize(attr, viewportSize); WebCore::restrictScaleFactorToInitialScaleIfNotUserScalable(attr); // FIXME: Resetting here can reset more than needed. For instance it will end deferrers. @@ -814,8 +946,20 @@ void QQuickWebViewFlickablePrivate::pageDidRequestScroll(const QPoint& pos) void QQuickWebViewFlickablePrivate::didChangeContentsSize(const QSize& newSize) { Q_Q(QQuickWebView); + QSize viewportSize = q->boundingRect().size().toSize(); + pageView->setContentsSize(newSize); q->experimental()->viewportInfo()->didUpdateContentsSize(); + + float minimumScale = WebCore::computeMinimumScaleFactorForContentContained(attributes, viewportSize, newSize); + + if (!qFuzzyCompare(minimumScale, attributes.minimumScale)) { + interactionEngine->setCSSScaleBounds(minimumScale, attributes.maximumScale); + q->experimental()->viewportInfo()->didUpdateViewportConstraints(); + + if (!interactionEngine->hadUserInteraction() && !pageIsSuspended) + interactionEngine->setCSSScale(minimumScale); + } } /*! @@ -955,13 +1099,13 @@ void QQuickWebViewExperimental::postMessage(const QString& message) d->context->postMessageToNavigatorQtObject(d->webPageProxy.get(), message); } -QDeclarativeComponent* QQuickWebViewExperimental::alertDialog() const +QQmlComponent* QQuickWebViewExperimental::alertDialog() const { Q_D(const QQuickWebView); return d->alertDialog; } -void QQuickWebViewExperimental::setAlertDialog(QDeclarativeComponent* alertDialog) +void QQuickWebViewExperimental::setAlertDialog(QQmlComponent* alertDialog) { Q_D(QQuickWebView); if (d->alertDialog == alertDialog) @@ -970,13 +1114,13 @@ void QQuickWebViewExperimental::setAlertDialog(QDeclarativeComponent* alertDialo emit alertDialogChanged(); } -QDeclarativeComponent* QQuickWebViewExperimental::confirmDialog() const +QQmlComponent* QQuickWebViewExperimental::confirmDialog() const { Q_D(const QQuickWebView); return d->confirmDialog; } -void QQuickWebViewExperimental::setConfirmDialog(QDeclarativeComponent* confirmDialog) +void QQuickWebViewExperimental::setConfirmDialog(QQmlComponent* confirmDialog) { Q_D(QQuickWebView); if (d->confirmDialog == confirmDialog) @@ -990,7 +1134,7 @@ QWebNavigationHistory* QQuickWebViewExperimental::navigationHistory() const return d_ptr->navigationHistory.get(); } -QDeclarativeComponent* QQuickWebViewExperimental::promptDialog() const +QQmlComponent* QQuickWebViewExperimental::promptDialog() const { Q_D(const QQuickWebView); return d->promptDialog; @@ -1004,7 +1148,7 @@ QWebPreferences* QQuickWebViewExperimental::preferences() const return d->preferences.get(); } -void QQuickWebViewExperimental::setPromptDialog(QDeclarativeComponent* promptDialog) +void QQuickWebViewExperimental::setPromptDialog(QQmlComponent* promptDialog) { Q_D(QQuickWebView); if (d->promptDialog == promptDialog) @@ -1013,13 +1157,13 @@ void QQuickWebViewExperimental::setPromptDialog(QDeclarativeComponent* promptDia emit promptDialogChanged(); } -QDeclarativeComponent* QQuickWebViewExperimental::authenticationDialog() const +QQmlComponent* QQuickWebViewExperimental::authenticationDialog() const { Q_D(const QQuickWebView); return d->authenticationDialog; } -void QQuickWebViewExperimental::setAuthenticationDialog(QDeclarativeComponent* authenticationDialog) +void QQuickWebViewExperimental::setAuthenticationDialog(QQmlComponent* authenticationDialog) { Q_D(QQuickWebView); if (d->authenticationDialog == authenticationDialog) @@ -1028,13 +1172,13 @@ void QQuickWebViewExperimental::setAuthenticationDialog(QDeclarativeComponent* a emit authenticationDialogChanged(); } -QDeclarativeComponent* QQuickWebViewExperimental::proxyAuthenticationDialog() const +QQmlComponent* QQuickWebViewExperimental::proxyAuthenticationDialog() const { Q_D(const QQuickWebView); return d->proxyAuthenticationDialog; } -void QQuickWebViewExperimental::setProxyAuthenticationDialog(QDeclarativeComponent* proxyAuthenticationDialog) +void QQuickWebViewExperimental::setProxyAuthenticationDialog(QQmlComponent* proxyAuthenticationDialog) { Q_D(QQuickWebView); if (d->proxyAuthenticationDialog == proxyAuthenticationDialog) @@ -1042,13 +1186,13 @@ void QQuickWebViewExperimental::setProxyAuthenticationDialog(QDeclarativeCompone d->proxyAuthenticationDialog = proxyAuthenticationDialog; emit proxyAuthenticationDialogChanged(); } -QDeclarativeComponent* QQuickWebViewExperimental::certificateVerificationDialog() const +QQmlComponent* QQuickWebViewExperimental::certificateVerificationDialog() const { Q_D(const QQuickWebView); return d->certificateVerificationDialog; } -void QQuickWebViewExperimental::setCertificateVerificationDialog(QDeclarativeComponent* certificateVerificationDialog) +void QQuickWebViewExperimental::setCertificateVerificationDialog(QQmlComponent* certificateVerificationDialog) { Q_D(QQuickWebView); if (d->certificateVerificationDialog == certificateVerificationDialog) @@ -1057,13 +1201,13 @@ void QQuickWebViewExperimental::setCertificateVerificationDialog(QDeclarativeCom emit certificateVerificationDialogChanged(); } -QDeclarativeComponent* QQuickWebViewExperimental::itemSelector() const +QQmlComponent* QQuickWebViewExperimental::itemSelector() const { Q_D(const QQuickWebView); return d->itemSelector; } -void QQuickWebViewExperimental::setItemSelector(QDeclarativeComponent* itemSelector) +void QQuickWebViewExperimental::setItemSelector(QQmlComponent* itemSelector) { Q_D(QQuickWebView); if (d->itemSelector == itemSelector) @@ -1072,13 +1216,13 @@ void QQuickWebViewExperimental::setItemSelector(QDeclarativeComponent* itemSelec emit itemSelectorChanged(); } -QDeclarativeComponent* QQuickWebViewExperimental::filePicker() const +QQmlComponent* QQuickWebViewExperimental::filePicker() const { Q_D(const QQuickWebView); return d->filePicker; } -void QQuickWebViewExperimental::setFilePicker(QDeclarativeComponent* filePicker) +void QQuickWebViewExperimental::setFilePicker(QQmlComponent* filePicker) { Q_D(QQuickWebView); if (d->filePicker == filePicker) @@ -1087,13 +1231,13 @@ void QQuickWebViewExperimental::setFilePicker(QDeclarativeComponent* filePicker) emit filePickerChanged(); } -QDeclarativeComponent* QQuickWebViewExperimental::databaseQuotaDialog() const +QQmlComponent* QQuickWebViewExperimental::databaseQuotaDialog() const { Q_D(const QQuickWebView); return d->databaseQuotaDialog; } -void QQuickWebViewExperimental::setDatabaseQuotaDialog(QDeclarativeComponent* databaseQuotaDialog) +void QQuickWebViewExperimental::setDatabaseQuotaDialog(QQmlComponent* databaseQuotaDialog) { Q_D(QQuickWebView); if (d->databaseQuotaDialog == databaseQuotaDialog) @@ -1171,7 +1315,25 @@ void QQuickWebViewExperimental::setDevicePixelRatio(double devicePixelRatio) emit devicePixelRatioChanged(); } -QQuickUrlSchemeDelegate* QQuickWebViewExperimental::schemeDelegates_At(QDeclarativeListProperty<QQuickUrlSchemeDelegate>* property, int index) +/*! + \internal + + \qmlmethod void WebViewExperimental::evaluateJavaScript(string script [, function(result)]) + + \brief Evaluates the specified JavaScript and, if supplied, calls a function with the result. +*/ + +void QQuickWebViewExperimental::evaluateJavaScript(const QString& script, const QJSValue& value) +{ + JSCallbackClosure* closure = new JSCallbackClosure; + + closure->receiver = this; + closure->value = value; + + d_ptr->webPageProxy.get()->runJavaScriptInMainFrame(script, ScriptValueCallback::create(closure, javaScriptCallback)); +} + +QQuickUrlSchemeDelegate* QQuickWebViewExperimental::schemeDelegates_At(QQmlListProperty<QQuickUrlSchemeDelegate>* property, int index) { const QObjectList children = property->object->children(); if (index < children.count()) @@ -1179,7 +1341,7 @@ QQuickUrlSchemeDelegate* QQuickWebViewExperimental::schemeDelegates_At(QDeclarat return 0; } -void QQuickWebViewExperimental::schemeDelegates_Append(QDeclarativeListProperty<QQuickUrlSchemeDelegate>* property, QQuickUrlSchemeDelegate *scheme) +void QQuickWebViewExperimental::schemeDelegates_Append(QQmlListProperty<QQuickUrlSchemeDelegate>* property, QQuickUrlSchemeDelegate *scheme) { QObject* schemeParent = property->object; scheme->setParent(schemeParent); @@ -1191,12 +1353,12 @@ void QQuickWebViewExperimental::schemeDelegates_Append(QDeclarativeListProperty< d->webPageProxy->registerApplicationScheme(scheme->scheme()); } -int QQuickWebViewExperimental::schemeDelegates_Count(QDeclarativeListProperty<QQuickUrlSchemeDelegate>* property) +int QQuickWebViewExperimental::schemeDelegates_Count(QQmlListProperty<QQuickUrlSchemeDelegate>* property) { return property->object->children().count(); } -void QQuickWebViewExperimental::schemeDelegates_Clear(QDeclarativeListProperty<QQuickUrlSchemeDelegate>* property) +void QQuickWebViewExperimental::schemeDelegates_Clear(QQmlListProperty<QQuickUrlSchemeDelegate>* property) { const QObjectList children = property->object->children(); for (int index = 0; index < children.count(); index++) { @@ -1206,9 +1368,9 @@ void QQuickWebViewExperimental::schemeDelegates_Clear(QDeclarativeListProperty<Q } } -QDeclarativeListProperty<QQuickUrlSchemeDelegate> QQuickWebViewExperimental::schemeDelegates() +QQmlListProperty<QQuickUrlSchemeDelegate> QQuickWebViewExperimental::schemeDelegates() { - return QDeclarativeListProperty<QQuickUrlSchemeDelegate>(schemeParent, 0, + return QQmlListProperty<QQuickUrlSchemeDelegate>(schemeParent, 0, QQuickWebViewExperimental::schemeDelegates_Append, QQuickWebViewExperimental::schemeDelegates_Count, QQuickWebViewExperimental::schemeDelegates_At, @@ -1336,11 +1498,6 @@ void QQuickWebView::setUrl(const QUrl& url) if (url.isEmpty()) return; - if (!isComponentComplete()) { - d->m_deferedUrlToLoad = url; - return; - } - d->webPageProxy->loadURL(url.toString()); } @@ -1360,7 +1517,7 @@ QUrl QQuickWebView::icon() const int QQuickWebView::loadProgress() const { Q_D(const QQuickWebView); - return d->pageLoadClient->loadProgress(); + return d->loadProgress(); } bool QQuickWebView::canGoBack() const @@ -1725,24 +1882,14 @@ void QQuickWebView::setZoomFactor(qreal factor) d->setZoomFactor(factor); } -struct JSCallbackClosure { - QPointer<QObject> receiver; - QByteArray method; -}; - -static void javaScriptCallback(WKSerializedScriptValueRef, WKErrorRef, void* context) -{ - JSCallbackClosure* closure = reinterpret_cast<JSCallbackClosure*>(context); - QMetaObject::invokeMethod(closure->receiver, closure->method); - delete closure; -} - void QQuickWebView::runJavaScriptInMainFrame(const QString &script, QObject *receiver, const char *method) { Q_D(QQuickWebView); + JSCallbackClosure* closure = new JSCallbackClosure; closure->receiver = receiver; closure->method = method; + d->webPageProxy.get()->runJavaScriptInMainFrame(script, ScriptValueCallback::create(closure, javaScriptCallback)); } |