summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dependencies.yaml8
-rw-r--r--examples/webenginequick/quicknanobrowser/BrowserWindow.qml5
-rw-r--r--examples/webenginequick/quicknanobrowser/doc/src/quicknanobrowser.qdoc9
-rw-r--r--examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc8
-rw-r--r--examples/webenginewidgets/simplebrowser/webpage.cpp7
-rw-r--r--src/core/api/qwebenginecertificateerror.cpp13
-rw-r--r--src/core/api/qwebenginecertificateerror.h2
-rw-r--r--src/core/api/qwebengineframe.cpp74
-rw-r--r--src/core/api/qwebengineframe.h10
-rw-r--r--src/core/api/qwebenginepage.cpp55
-rw-r--r--src/core/api/qwebenginepage.h3
-rw-r--r--src/core/api/qwebenginepage_p.h5
-rw-r--r--src/core/certificate_error_controller.cpp9
-rw-r--r--src/core/certificate_error_controller.h4
-rw-r--r--src/core/compositor/native_skia_output_device_direct3d11.cpp1
-rw-r--r--src/core/compositor/native_skia_output_device_vulkan.cpp1
-rw-r--r--src/core/content_browser_client_qt.cpp4
-rw-r--r--src/core/doc/src/qtwebengine-overview.qdoc9
-rw-r--r--src/core/doc/src/qwebengine-licensing.qdoc53
-rw-r--r--src/core/doc/src/qwebenginepage_lgpl.qdoc13
-rw-r--r--src/core/ozone/surface_factory_qt.cpp4
-rw-r--r--src/core/web_contents_adapter.cpp79
-rw-r--r--src/core/web_contents_adapter.h18
-rw-r--r--src/core/web_contents_adapter_client.h4
-rw-r--r--src/pdfquick/qquickpdfpageimage.cpp16
-rw-r--r--src/webenginequick/api/qquickwebengineview.cpp39
-rw-r--r--src/webenginequick/api/qquickwebengineview_p_p.h6
-rw-r--r--src/webenginequick/doc/src/webengineframe.qdoc34
-rw-r--r--src/webenginequick/doc/src/webengineview_lgpl.qdoc17
-rw-r--r--tests/auto/core/certificateerror/tst_certificateerror.cpp16
-rw-r--r--tests/auto/core/qwebengineframe/tst_qwebengineframe.cpp14
-rw-r--r--tests/auto/quick/publicapi/tst_publicapi.cpp5
-rw-r--r--tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp4
-rw-r--r--tests/manual/quick/pdf/withdoc.qml6
34 files changed, 431 insertions, 124 deletions
diff --git a/dependencies.yaml b/dependencies.yaml
index 0c1d011bf..a6dd5cb7e 100644
--- a/dependencies.yaml
+++ b/dependencies.yaml
@@ -1,13 +1,13 @@
dependencies:
../qtdeclarative:
- ref: c63bb2bad5b4e741ed8a1e16d8f1f916c9baf61d
+ ref: 7bdeea2c309150c8b49558b135232926d6a89c50
required: true
../qtpositioning:
- ref: 152d0039c7ad2898e8e5b122420f59049536143b
+ ref: d09694ea15c235cec07dc5e7c0073c6f4b13f5ea
required: false
../qttools:
- ref: 0d80d76bf14905204a248655cd88fe6cfd5706db
+ ref: b22644dd731bd2c2312d31d08a80fd637f0c1e3a
required: false
../qtwebchannel:
- ref: 2a194a801a86d3d9342b47ccba9a1105aadf70d6
+ ref: b9d1a08e490fc6831a26d0c45ecf56cef11968a0
required: false
diff --git a/examples/webenginequick/quicknanobrowser/BrowserWindow.qml b/examples/webenginequick/quicknanobrowser/BrowserWindow.qml
index 3b911262b..e2cb71fb3 100644
--- a/examples/webenginequick/quicknanobrowser/BrowserWindow.qml
+++ b/examples/webenginequick/quicknanobrowser/BrowserWindow.qml
@@ -563,6 +563,11 @@ ApplicationWindow {
settings.imageAnimationPolicy: appSettings.imageAnimationPolicy
onCertificateError: function(error) {
+ if (!error.isMainFrame) {
+ error.rejectCertificate();
+ return;
+ }
+
error.defer();
sslDialog.enqueue(error);
}
diff --git a/examples/webenginequick/quicknanobrowser/doc/src/quicknanobrowser.qdoc b/examples/webenginequick/quicknanobrowser/doc/src/quicknanobrowser.qdoc
index 1dc209c2e..1e00402ff 100644
--- a/examples/webenginequick/quicknanobrowser/doc/src/quicknanobrowser.qdoc
+++ b/examples/webenginequick/quicknanobrowser/doc/src/quicknanobrowser.qdoc
@@ -75,13 +75,16 @@
\section1 Handling Certificate Errors
- If the certificate of the site being loaded triggers a certificate error, we call the
- \l{WebEngineCertificateError::}{defer()} QML method to pause the URL request and wait for user
- input:
+ In case of a certificate error, we check whether it came from the main frame, or from a
+ resource inside the page. Resource errors automatically trigger a certificate rejection,
+ since a user won't have enough context to make a decision.
+ For all other cases, we call the \l{WebEngineCertificateError::}{defer()} QML method to pause
+ the URL request and wait for user input:
\quotefromfile webenginequick/quicknanobrowser/BrowserWindow.qml
\skipto onCertificateError
\printuntil }
+ \printuntil }
We use the Dialog type to prompt users to continue or cancel the loading of the web page.
If users select \uicontrol Yes, we call the
diff --git a/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc b/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc
index 211535204..a312da3ad 100644
--- a/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc
+++ b/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc
@@ -223,13 +223,17 @@
The \c handleProxyAuthenticationRequired signal handler implements the very same
steps for the authentication of HTTP proxies.
- In case of SSL errors, we just need to return a boolean value indicating
- whether the certificate should be ignored.
+ In case of SSL errors, we check whether they come from the main frame, or
+ from a resource inside the page. Resource errors automatically trigger a
+ certificate rejection, since a user won't have enough context to make a
+ decision. For all other cases, we trigger a dialog where the user can
+ allow or reject the certificate.
\quotefromfile webenginewidgets/simplebrowser/webpage.cpp
\skipto WebPage::handleCertificateError(
\printuntil }
\printuntil }
+ \printuntil }
\section1 Opening a Web Page
diff --git a/examples/webenginewidgets/simplebrowser/webpage.cpp b/examples/webenginewidgets/simplebrowser/webpage.cpp
index 807cdf0ff..6fc9aeaf9 100644
--- a/examples/webenginewidgets/simplebrowser/webpage.cpp
+++ b/examples/webenginewidgets/simplebrowser/webpage.cpp
@@ -19,6 +19,13 @@ WebPage::WebPage(QWebEngineProfile *profile, QObject *parent)
void WebPage::handleCertificateError(QWebEngineCertificateError error)
{
+ // Automatically block certificate errors from page resources without prompting the user.
+ // This mirrors the behavior found in other major browsers.
+ if (!error.isMainFrame()) {
+ error.rejectCertificate();
+ return;
+ }
+
error.defer();
QTimer::singleShot(0, this,
[this, error]() mutable { emit createCertificateErrorDialog(error); });
diff --git a/src/core/api/qwebenginecertificateerror.cpp b/src/core/api/qwebenginecertificateerror.cpp
index 90d8a542d..85c5d5127 100644
--- a/src/core/api/qwebenginecertificateerror.cpp
+++ b/src/core/api/qwebenginecertificateerror.cpp
@@ -88,6 +88,19 @@ QUrl QWebEngineCertificateError::url() const
}
/*!
+ \property QWebEngineCertificateError::isMainFrame
+ \since 6.8
+
+ Returns whether the certificate error comes from the main frame. If false,
+ the error comes from a sub-resource and most likely needs to be rejected without
+ user input.
+*/
+bool QWebEngineCertificateError::isMainFrame() const
+{
+ return d->isMainFrame();
+}
+
+/*!
Returns the type of the error.
\sa description(), isOverridable()
diff --git a/src/core/api/qwebenginecertificateerror.h b/src/core/api/qwebenginecertificateerror.h
index c4a3585f4..3eef3dcca 100644
--- a/src/core/api/qwebenginecertificateerror.h
+++ b/src/core/api/qwebenginecertificateerror.h
@@ -24,6 +24,7 @@ class Q_WEBENGINECORE_EXPORT QWebEngineCertificateError
Q_PROPERTY(Type type READ type CONSTANT FINAL)
Q_PROPERTY(QString description READ description CONSTANT FINAL)
Q_PROPERTY(bool overridable READ isOverridable CONSTANT FINAL)
+ Q_PROPERTY(bool isMainFrame READ isMainFrame CONSTANT FINAL REVISION(6, 8))
public:
QWebEngineCertificateError(const QWebEngineCertificateError &other);
@@ -57,6 +58,7 @@ public:
QUrl url() const;
bool isOverridable() const;
QString description() const;
+ bool isMainFrame() const;
Q_INVOKABLE void defer();
Q_INVOKABLE void rejectCertificate();
diff --git a/src/core/api/qwebengineframe.cpp b/src/core/api/qwebengineframe.cpp
index edd89d663..1eedc4b92 100644
--- a/src/core/api/qwebengineframe.cpp
+++ b/src/core/api/qwebengineframe.cpp
@@ -3,6 +3,9 @@
#include "qwebengineframe.h"
+#include "qwebenginescript.h"
+#include <QtQml/qqmlengine.h>
+
#include "web_contents_adapter_client.h"
#include "web_contents_adapter.h"
@@ -101,6 +104,77 @@ QSizeF QWebEngineFrame::size() const
return m_adapterClient->webContentsAdapter()->frameSize(m_id);
}
+/*! \fn void QWebEngineFrame::runJavaScript(const QString &script, const std::function<void(const QVariant &)> &callback)
+ \fn void QWebEngineFrame::runJavaScript(const QString &script, quint32 worldId)
+ \fn void QWebEngineFrame::runJavaScript(const QString &script, quint32 worldId, const
+ std::function<void(const QVariant &)> &callback)
+
+ Runs the JavaScript code contained in \a script on this frame, without checking
+ whether the DOM of the page has been constructed.
+ To avoid conflicts with other scripts executed on the page, the world in
+ which the script is run is specified by \a worldId. The world ID values are
+ the same as provided by QWebEngineScript::ScriptWorldId, and between \c 0
+ and \c 256. If you leave out the \c world ID, the script is run in the
+ \c MainWorld.
+ When the script has been executed, \a callback is called with the result of the last
+ executed statement. \c callback can be any of a function pointer, a functor or a lambda,
+ and it is expected to take a QVariant parameter. For example:
+ \code
+ page.runJavaScript("document.title", [](const QVariant &v) { qDebug() << v.toString(); });
+ \endcode
+ Only plain data can be returned from JavaScript as the result value.
+ Supported data types include all of the JSON data types as well as, for
+ example, \c{Date} and \c{ArrayBuffer}. Unsupported data types include, for
+ example, \c{Function} and \c{Promise}.
+ \warning Do not execute lengthy routines in the callback function, because it might block the
+ rendering of the web engine page.
+ \warning We guarantee that the \a callback is always called, but it might be
+ done during page destruction. When QWebEnginePage is deleted, the callback is triggered with an
+ invalid value and it is not safe to use the corresponding QWebEnginePage or QWebEngineView
+ instance inside it.
+ \sa QWebEngineScript::ScriptWorldId, QWebEnginePage::runJavaScript, {Script Injection}
+ */
+void QWebEngineFrame::runJavaScript(const QString &script,
+ const std::function<void(const QVariant &)> &callback)
+{
+ runJavaScript(script, QWebEngineScript::MainWorld, callback);
+}
+
+void QWebEngineFrame::runJavaScript(const QString &script, quint32 worldId,
+ const std::function<void(const QVariant &)> &callback)
+{
+ m_adapterClient->runJavaScript(script, worldId, m_id, callback);
+}
+
+void QWebEngineFrame::runJavaScript(const QString &script, quint32 worldId)
+{
+ runJavaScript(script, worldId, std::function<void(const QVariant &)>{});
+}
+
+void QWebEngineFrame::runJavaScript(const QString &script, const QJSValue &callback)
+{
+ runJavaScript(script, QWebEngineScript::MainWorld, callback);
+}
+
+void QWebEngineFrame::runJavaScript(const QString &script, quint32 worldId,
+ const QJSValue &callback)
+{
+ std::function<void(const QVariant &)> wrappedCallback;
+ if (!callback.isUndefined()) {
+ const QObject *holdingObject = m_adapterClient->holdingQObject();
+ wrappedCallback = [holdingObject, callback](const QVariant &result) {
+ if (auto engine = qmlEngine(holdingObject)) {
+ QJSValueList args;
+ args.append(engine->toScriptValue(result));
+ callback.call(args);
+ } else {
+ qWarning("No QML engine found to execute runJavaScript() callback");
+ }
+ };
+ }
+ runJavaScript(script, worldId, wrappedCallback);
+}
+
/*! \fn bool QWebEngineFrame::operator==(const QWebEngineFrame &left, const QWebEngineFrame &right) noexcept
Returns \c{true} if \a left and \a right represent the same frame in the same web page,
diff --git a/src/core/api/qwebengineframe.h b/src/core/api/qwebengineframe.h
index e58961848..988d50d8e 100644
--- a/src/core/api/qwebengineframe.h
+++ b/src/core/api/qwebengineframe.h
@@ -6,6 +6,7 @@
#include <QtWebEngineCore/qtwebenginecoreglobal.h>
#include <QtQml/qqmlregistration.h>
+#include <QtQml/qjsvalue.h>
#include <QtCore/qcompare.h>
#include <QtCore/QList>
#include <QtCore/QSizeF>
@@ -39,6 +40,15 @@ public:
QUrl url() const;
QSizeF size() const;
+ void runJavaScript(const QString &script,
+ const std::function<void(const QVariant &)> &callback);
+ void runJavaScript(const QString &script, quint32 worldId,
+ const std::function<void(const QVariant &)> &callback);
+ Q_INVOKABLE void runJavaScript(const QString &script, quint32 worldId = 0);
+ Q_INVOKABLE void runJavaScript(const QString &script, const QJSValue &callback);
+ Q_INVOKABLE void runJavaScript(const QString &script, quint32 worldId,
+ const QJSValue &callback);
+
friend inline bool comparesEqual(const QWebEngineFrame &lhs,
const QWebEngineFrame &rhs) noexcept
{
diff --git a/src/core/api/qwebenginepage.cpp b/src/core/api/qwebenginepage.cpp
index c2a737d72..439214235 100644
--- a/src/core/api/qwebenginepage.cpp
+++ b/src/core/api/qwebenginepage.cpp
@@ -199,6 +199,12 @@ void QWebEnginePagePrivate::iconChanged(const QUrl &url)
Q_EMIT q->iconChanged(iconUrl.isEmpty() ? QIcon() : adapter->icon());
}
+void QWebEnginePagePrivate::zoomFactorChanged(qreal factor)
+{
+ Q_Q(QWebEnginePage);
+ Q_EMIT q->zoomFactorChanged(factor);
+}
+
void QWebEnginePagePrivate::loadProgressChanged(int progress)
{
Q_Q(QWebEnginePage);
@@ -489,10 +495,16 @@ void QWebEnginePagePrivate::windowCloseRejected()
// Do nothing for now.
}
-void QWebEnginePagePrivate::didRunJavaScript(quint64 requestId, const QVariant& result)
+void QWebEnginePagePrivate::runJavaScript(const QString &script, quint32 worldId, quint64 frameId,
+ const std::function<void(const QVariant &)> &callback)
{
- if (auto callback = m_variantCallbacks.take(requestId))
- callback(result);
+ ensureInitialized();
+ if (adapter->lifecycleState() == WebContentsAdapter::LifecycleState::Discarded) {
+ qWarning("runJavaScript: disabled in Discarded state");
+ if (callback)
+ callback(QVariant());
+ } else
+ adapter->runJavaScript(script, worldId, frameId, callback);
}
void QWebEnginePagePrivate::didFetchDocumentMarkup(quint64 requestId, const QString& result)
@@ -971,11 +983,9 @@ QWebEnginePage::~QWebEnginePage()
setDevToolsPage(nullptr);
emit _q_aboutToDelete();
- for (auto varFun : std::as_const(d_ptr->m_variantCallbacks))
- varFun(QVariant());
+ d_ptr->adapter->clearJavaScriptCallbacks();
for (auto strFun : std::as_const(d_ptr->m_stringCallbacks))
strFun(QString());
- d_ptr->m_variantCallbacks.clear();
d_ptr->m_stringCallbacks.clear();
}
}
@@ -2020,7 +2030,7 @@ void QWebEnginePage::setZoomFactor(qreal factor)
Q_D(QWebEnginePage);
d->defaultZoomFactor = factor;
- if (d->adapter->isInitialized()) {
+ if (d->adapter->isInitialized() && !qFuzzyCompare(factor, zoomFactor())) {
d->adapter->setZoomFactor(factor);
// MEMO: should reset if factor was not applied due to being invalid
d->defaultZoomFactor = zoomFactor();
@@ -2029,40 +2039,13 @@ void QWebEnginePage::setZoomFactor(qreal factor)
void QWebEnginePage::runJavaScript(const QString& scriptSource, const std::function<void(const QVariant &)> &resultCallback)
{
- Q_D(QWebEnginePage);
- d->ensureInitialized();
- if (d->adapter->lifecycleState() == WebContentsAdapter::LifecycleState::Discarded) {
- qWarning("runJavaScript: disabled in Discarded state");
- if (resultCallback)
- resultCallback(QVariant());
- return;
- }
- quint64 requestId = d->adapter->runJavaScriptCallbackResult(scriptSource, QWebEngineScript::MainWorld);
- if (requestId)
- d->m_variantCallbacks.insert(requestId, resultCallback);
- else if (resultCallback)
- resultCallback(QVariant());
+ runJavaScript(scriptSource, QWebEngineScript::MainWorld, resultCallback);
}
void QWebEnginePage::runJavaScript(const QString& scriptSource, quint32 worldId, const std::function<void(const QVariant &)> &resultCallback)
{
Q_D(QWebEnginePage);
- d->ensureInitialized();
- if (d->adapter->lifecycleState() == WebContentsAdapter::LifecycleState::Discarded) {
- qWarning("runJavaScript: disabled in Discarded state");
- if (resultCallback)
- resultCallback(QVariant());
- return;
- }
- if (resultCallback) {
- quint64 requestId = d->adapter->runJavaScriptCallbackResult(scriptSource, worldId);
- if (requestId)
- d->m_variantCallbacks.insert(requestId, resultCallback);
- else
- resultCallback(QVariant());
- } else {
- d->adapter->runJavaScript(scriptSource, worldId);
- }
+ d->runJavaScript(scriptSource, worldId, WebContentsAdapter::kUseMainFrameId, resultCallback);
}
/*!
diff --git a/src/core/api/qwebenginepage.h b/src/core/api/qwebenginepage.h
index e5a4e9551..13c582931 100644
--- a/src/core/api/qwebenginepage.h
+++ b/src/core/api/qwebenginepage.h
@@ -51,7 +51,7 @@ class Q_WEBENGINECORE_EXPORT QWebEnginePage : public QObject
Q_PROPERTY(QString selectedText READ selectedText)
Q_PROPERTY(bool hasSelection READ hasSelection)
Q_PROPERTY(QUrl requestedUrl READ requestedUrl)
- Q_PROPERTY(qreal zoomFactor READ zoomFactor WRITE setZoomFactor)
+ Q_PROPERTY(qreal zoomFactor READ zoomFactor WRITE setZoomFactor NOTIFY zoomFactorChanged)
Q_PROPERTY(QString title READ title NOTIFY titleChanged)
Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged)
Q_PROPERTY(QUrl iconUrl READ iconUrl NOTIFY iconUrlChanged)
@@ -344,6 +344,7 @@ Q_SIGNALS:
void iconUrlChanged(const QUrl &url);
void iconChanged(const QIcon &icon);
+ void zoomFactorChanged(qreal factor);
void scrollPositionChanged(const QPointF &position);
void contentsSizeChanged(const QSizeF &size);
void audioMutedChanged(bool muted);
diff --git a/src/core/api/qwebenginepage_p.h b/src/core/api/qwebenginepage_p.h
index 31ace7e9d..f0e179ea8 100644
--- a/src/core/api/qwebenginepage_p.h
+++ b/src/core/api/qwebenginepage_p.h
@@ -102,6 +102,7 @@ public:
void titleChanged(const QString &) override;
void urlChanged() override;
void iconChanged(const QUrl &) override;
+ void zoomFactorChanged(qreal factor) override;
void loadProgressChanged(int progress) override;
void didUpdateTargetURL(const QUrl &) override;
void selectionChanged() override;
@@ -130,7 +131,8 @@ public:
void javascriptDialog(QSharedPointer<QtWebEngineCore::JavaScriptDialogController>) override;
void runFileChooser(QSharedPointer<QtWebEngineCore::FilePickerController>) override;
void showColorDialog(QSharedPointer<QtWebEngineCore::ColorChooserController>) override;
- void didRunJavaScript(quint64 requestId, const QVariant &result) override;
+ void runJavaScript(const QString &script, quint32 worldId, quint64 frameId,
+ const std::function<void(const QVariant &)> &callback) override;
void didFetchDocumentMarkup(quint64 requestId, const QString &result) override;
void didFetchDocumentInnerText(quint64 requestId, const QString &result) override;
void didPrintPage(quint64 requestId, QSharedPointer<QByteArray> result) override;
@@ -214,7 +216,6 @@ public:
QPrinter *currentPrinter = nullptr;
#endif
- mutable QMap<quint64, std::function<void(const QVariant &)>> m_variantCallbacks;
mutable QMap<quint64, std::function<void(const QString &)>> m_stringCallbacks;
QMap<quint64, std::function<void(const QByteArray &)>> m_pdfResultCallbacks;
mutable QAction *actions[QWebEnginePage::WebActionCount];
diff --git a/src/core/certificate_error_controller.cpp b/src/core/certificate_error_controller.cpp
index 014d74500..51f9f3edb 100644
--- a/src/core/certificate_error_controller.cpp
+++ b/src/core/certificate_error_controller.cpp
@@ -77,10 +77,12 @@ static int IsCertErrorFatal(int cert_error)
CertificateErrorController::CertificateErrorController(
int cert_error, const net::SSLInfo &ssl_info, const GURL &request_url,
- bool strict_enforcement, base::OnceCallback<void(content::CertificateRequestResultType)> cb)
+ bool main_frame, bool strict_enforcement,
+ base::OnceCallback<void(content::CertificateRequestResultType)> cb)
: m_certError(QWebEngineCertificateError::Type(cert_error))
, m_requestUrl(toQt(request_url))
, m_overridable(!IsCertErrorFatal(cert_error) && !strict_enforcement)
+ , m_mainFrame(main_frame)
{
// MEMO set callback anyway even for non overridable error since chromium halts load until it's called
// callback will be executed either explicitly by use code or implicitly when error goes out of scope
@@ -204,4 +206,9 @@ QList<QSslCertificate> CertificateErrorController::certificateChain() const
return m_certificateChain;
}
+bool CertificateErrorController::isMainFrame() const
+{
+ return m_mainFrame;
+}
+
}
diff --git a/src/core/certificate_error_controller.h b/src/core/certificate_error_controller.h
index cbcb60f8a..b0d38fd57 100644
--- a/src/core/certificate_error_controller.h
+++ b/src/core/certificate_error_controller.h
@@ -37,7 +37,7 @@ class Q_WEBENGINECORE_EXPORT CertificateErrorController {
public:
CertificateErrorController(
int cert_error, const net::SSLInfo &ssl_info, const GURL &request_url,
- bool strict_enforcement,
+ bool main_frame, bool strict_enforcement,
base::OnceCallback<void(content::CertificateRequestResultType)> callback);
~CertificateErrorController();
@@ -47,6 +47,7 @@ public:
QString errorString() const;
QDateTime validExpiry() const;
QList<QSslCertificate> certificateChain() const;
+ bool isMainFrame() const;
bool deferred() const;
void defer();
@@ -65,6 +66,7 @@ public:
bool m_overridable;
base::OnceCallback<void(content::CertificateRequestResultType)> m_callback;
QList<QSslCertificate> m_certificateChain;
+ bool m_mainFrame;
bool m_answered = false, m_deferred = false;
diff --git a/src/core/compositor/native_skia_output_device_direct3d11.cpp b/src/core/compositor/native_skia_output_device_direct3d11.cpp
index 352fa9f92..2f1ed5f61 100644
--- a/src/core/compositor/native_skia_output_device_direct3d11.cpp
+++ b/src/core/compositor/native_skia_output_device_direct3d11.cpp
@@ -56,6 +56,7 @@ QSGTexture *NativeSkiaOutputDeviceDirect3D11::texture(QQuickWindow *win, uint32_
status = resource->CreateSharedHandle(NULL, DXGI_SHARED_RESOURCE_READ, NULL, &sharedHandle);
Q_ASSERT(status == S_OK);
Q_ASSERT(sharedHandle);
+ resource->Release();
// Pass texture between two D3D devices:
ID3D11Device1 *device = static_cast<ID3D11Device1 *>(
diff --git a/src/core/compositor/native_skia_output_device_vulkan.cpp b/src/core/compositor/native_skia_output_device_vulkan.cpp
index c2ad7a382..f51eba985 100644
--- a/src/core/compositor/native_skia_output_device_vulkan.cpp
+++ b/src/core/compositor/native_skia_output_device_vulkan.cpp
@@ -187,6 +187,7 @@ QSGTexture *NativeSkiaOutputDeviceVulkan::texture(QQuickWindow *win, uint32_t te
Q_ASSERT(status == S_OK);
status = resource->CreateSharedHandle(NULL, DXGI_SHARED_RESOURCE_READ, NULL, &sharedHandle);
Q_ASSERT(status == S_OK);
+ resource->Release();
if (!sharedHandle)
qFatal("VULKAN: Unable to extract shared handle.");
diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp
index 7192edbc2..28ed6ef7c 100644
--- a/src/core/content_browser_client_qt.cpp
+++ b/src/core/content_browser_client_qt.cpp
@@ -276,14 +276,14 @@ void ContentBrowserClientQt::AllowCertificateError(content::WebContents *webCont
int cert_error,
const net::SSLInfo &ssl_info,
const GURL &request_url,
- bool /* is_main_frame_request */,
+ bool is_main_frame_request,
bool strict_enforcement,
base::OnceCallback<void(content::CertificateRequestResultType)> callback)
{
WebContentsDelegateQt* contentsDelegate = static_cast<WebContentsDelegateQt*>(webContents->GetDelegate());
QSharedPointer<CertificateErrorController> errorController(new CertificateErrorController(
- cert_error, ssl_info, request_url, strict_enforcement, std::move(callback)));
+ cert_error, ssl_info, request_url, is_main_frame_request, strict_enforcement, std::move(callback)));
contentsDelegate->allowCertificateError(errorController);
}
diff --git a/src/core/doc/src/qtwebengine-overview.qdoc b/src/core/doc/src/qtwebengine-overview.qdoc
index 6eccc669e..3a5d30338 100644
--- a/src/core/doc/src/qtwebengine-overview.qdoc
+++ b/src/core/doc/src/qtwebengine-overview.qdoc
@@ -44,8 +44,13 @@
dedicated profile for a \e {private browsing} mode, where no information is permanently saved.
\note The \QWE Widgets module uses the \l{Qt Quick Scene Graph}{Qt Quick scene graph}
- to compose the elements of a web page into one view. This means that the UI process
- requires OpenGL ES 2.0 or OpenGL 2.0 for its rendering.
+ to compose the elements of a web page into one view.
+
+ The content is rendered using the graphics card (GPU) capabilities. The scene
+ graph, in turn, relies on the Qt Rendering Hardware Interface as an abstraction
+ layer for the different capabilities and APIs a GPU might feature. For more
+ advice on how to tweak the rendering pipeline, see therefore
+ \l{Rendering via the Qt Rendering Hardware Interface}.
\section2 Qt WebEngine Module
diff --git a/src/core/doc/src/qwebengine-licensing.qdoc b/src/core/doc/src/qwebengine-licensing.qdoc
index 796a9664d..936ceff97 100644
--- a/src/core/doc/src/qwebengine-licensing.qdoc
+++ b/src/core/doc/src/qwebengine-licensing.qdoc
@@ -5,20 +5,49 @@
\group qtwebengine-licensing
\title Qt WebEngine Licensing
-The Qt specific parts of the \QWE module are dual-licensed
-under Commercial and GNU Lesser General Public License (LGPLv3).
-In addition, the module contains code licensed under LGPLv2.
-
-The module includes a snapshot of Chromium. As such, users need to
-respect the licenses of Chromium, and third-party code included in
-Chromium. The arguably most restrictive license to be respected by
-all users is LGPLv2.1.
+The \QWE module uses Chromium to provide most of its
+functionality. During the build process, Chromium becomes
+a part of the \l{Qt WebEngine Core} library.
+Therefore, when distributing \QWE, users need to comply
+to both the licenses of the \QWE part as developed under
+the Qt Project, as well as the licenses that are part of
+Chromium.
+
+The Qt specific parts of the \QWE module are available under
+commercial licenses from The Qt Company. Alternatively,
+they are available under GNU Lesser General Public License v3.0,
+or GNU General Public License v3.0, or
+GNU General Public License v2.0.
+
+The Chromium part contains code available under various
+licenses, with the most restrictive license being the
+\e{GNU Lesser General Public License v2.1} (LGPL 2.1).
+For a full list, see \l{Third-Party Licenses} below.
+
+\section1 Complying with LGPL 2.1
+
+The Qt Company allows commercial customers to
+distribute the source code of the \QWE module alongside the
+\QWE binaries, and allows recipients to customize and build
+\QWE from sources. This includes building and using
+such a modified \QWE with an application or system using
+an otherwise commercially licensed Qt.
+
+The Qt Company also keeps the Qt specific parts of the \QWE
+module available under the GNU Lesser General Public License v3.0,
+or the GNU General Public License v3.0, or
+the GNU General Public License v2.0, even if WebEngine is released
+as part of a commercial-only Long-Term Support release (LTS, see
+also \l{Long-Term Support releases}).
+
+\section1 Third-Party Licenses
+
+Third party licenses included in the sources as part of Chromium
+are found below.
\note Any GPL licenses listed below are only used to access Linux system
-resources. \QWE does not link to nor distribute GPL binary code, and
-it does not affect users of \QWE.
-
-Third party licenses included in the sources are:
+resources. The \QWE libraries and plugins does not link to nor distribute
+GPL binary code, and it does not affect users of \QWE.
*/
/*!
diff --git a/src/core/doc/src/qwebenginepage_lgpl.qdoc b/src/core/doc/src/qwebenginepage_lgpl.qdoc
index c2515cd13..1640ca8be 100644
--- a/src/core/doc/src/qwebenginepage_lgpl.qdoc
+++ b/src/core/doc/src/qwebenginepage_lgpl.qdoc
@@ -735,6 +735,8 @@
\brief The zoom factor for the page content.
Valid values are within the range from \c{0.25} to \c{5.0}. The default factor is \c{1.0}.
+
+ \sa zoomFactorChanged()
*/
/*!
@@ -772,7 +774,7 @@
during page destruction. When QWebEnginePage is deleted, the callback is triggered with an invalid
value and it is not safe to use the corresponding QWebEnginePage or QWebEngineView instance inside it.
- \sa scripts(), QWebEngineScript::ScriptWorldId, {Script Injection}
+ \sa scripts(), QWebEngineScript::ScriptWorldId, QWebEngineFrame::runJavaScript, {Script Injection}
*/
/*!
@@ -836,3 +838,12 @@
\sa QWebEngineWebAuthUxRequest
*/
+
+/*!
+ \fn void QWebEnginePage::zoomFactorChanged(qreal factor)
+ \since 6.8
+
+ This signal is emitted whenever the zoom \a factor for the page changes.
+
+ \sa zoomFactor(), setZoomFactor()
+*/
diff --git a/src/core/ozone/surface_factory_qt.cpp b/src/core/ozone/surface_factory_qt.cpp
index 04e6ec28f..2d311a02a 100644
--- a/src/core/ozone/surface_factory_qt.cpp
+++ b/src/core/ozone/surface_factory_qt.cpp
@@ -226,7 +226,7 @@ SurfaceFactoryQt::CreateNativePixmapFromHandle(
int fd = fds[i];
int stride = strides[i];
int offset = offsets[i];
- int size = handle.planes[i].size;
+ int planeSize = handle.planes[i].size;
if (fd == -1) {
fd = fds[0];
@@ -234,7 +234,7 @@ SurfaceFactoryQt::CreateNativePixmapFromHandle(
offset = handle.planes[i].offset;
}
- gfx::NativePixmapPlane plane(stride, offset, size, base::ScopedFD(::dup(fd)));
+ gfx::NativePixmapPlane plane(stride, offset, planeSize, base::ScopedFD(::dup(fd)));
bufferHandle.planes.push_back(std::move(plane));
}
diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp
index 6decf8780..b06ed2121 100644
--- a/src/core/web_contents_adapter.cpp
+++ b/src/core/web_contents_adapter.cpp
@@ -174,10 +174,9 @@ static QVariant fromJSValue(const base::Value *result)
return ret;
}
-static void callbackOnEvaluateJS(WebContentsAdapterClient *adapterClient, quint64 requestId, base::Value result)
+static void callbackOnEvaluateJS(WebContentsAdapter *adapter, quint64 requestId, base::Value result)
{
- if (requestId)
- adapterClient->didRunJavaScript(requestId, fromJSValue(&result));
+ adapter->didRunJavaScript(requestId, result);
}
#if QT_CONFIG(webengine_printing_and_pdf)
@@ -993,6 +992,9 @@ void WebContentsAdapter::setZoomFactor(qreal factor)
const content::GlobalRenderFrameHostId global_id = m_webContents->GetPrimaryMainFrame()->GetGlobalId();
zoomMap->SetTemporaryZoomLevel(global_id, zoomLevel);
}
+
+ if (m_adapterClient)
+ m_adapterClient->zoomFactorChanged(currentZoomFactor());
}
qreal WebContentsAdapter::currentZoomFactor() const
@@ -1039,36 +1041,67 @@ QAccessibleInterface *WebContentsAdapter::browserAccessible()
}
#endif // QT_CONFIG(accessibility)
-void WebContentsAdapter::runJavaScript(const QString &javaScript, quint32 worldId)
+content::RenderFrameHost *WebContentsAdapter::renderFrameHostFromFrameId(quint64 frameId) const
{
- CHECK_INITIALIZED();
- content::RenderFrameHost *rfh = m_webContents->GetPrimaryMainFrame();
- Q_ASSERT(rfh);
- if (!static_cast<content::RenderFrameHostImpl*>(rfh)->GetAssociatedLocalFrame()) {
- qWarning() << "Local frame is gone, not running script";
- return;
+ content::RenderFrameHost *result;
+ if (frameId == kUseMainFrameId) {
+ result = m_webContents->GetPrimaryMainFrame();
+ } else {
+ auto *ftn = content::FrameTreeNode::GloballyFindByID(static_cast<int>(frameId));
+ if (!ftn)
+ return nullptr;
+
+ result = ftn->current_frame_host();
}
- if (worldId == 0)
- rfh->ExecuteJavaScript(toString16(javaScript), base::NullCallback());
- else
- rfh->ExecuteJavaScriptInIsolatedWorld(toString16(javaScript), base::NullCallback(), worldId);
+ Q_ASSERT(result);
+ return result;
}
-quint64 WebContentsAdapter::runJavaScriptCallbackResult(const QString &javaScript, quint32 worldId)
+void WebContentsAdapter::runJavaScript(const QString &javaScript, quint32 worldId, quint64 frameId,
+ const std::function<void(const QVariant &)> &callback)
{
- CHECK_INITIALIZED(0);
- content::RenderFrameHost *rfh = m_webContents->GetPrimaryMainFrame();
- Q_ASSERT(rfh);
+ auto exit = [&] {
+ if (callback)
+ callback(QVariant());
+ };
+
+ if (!isInitialized())
+ return exit();
+ auto *rfh = renderFrameHostFromFrameId(frameId);
+ if (!rfh)
+ return exit();
if (!static_cast<content::RenderFrameHostImpl*>(rfh)->GetAssociatedLocalFrame()) {
qWarning() << "Local frame is gone, not running script";
- return 0;
+ return exit();
+ }
+
+ content::RenderFrameHost::JavaScriptResultCallback internalCallback = base::NullCallback();
+ if (callback) {
+ internalCallback = base::BindOnce(&callbackOnEvaluateJS, this, m_nextRequestId);
+ m_javaScriptCallbacks.insert(m_nextRequestId, callback);
+ ++m_nextRequestId;
}
- content::RenderFrameHost::JavaScriptResultCallback callback = base::BindOnce(&callbackOnEvaluateJS, m_adapterClient, m_nextRequestId);
if (worldId == 0)
- rfh->ExecuteJavaScript(toString16(javaScript), std::move(callback));
+ rfh->ExecuteJavaScript(toString16(javaScript), std::move(internalCallback));
else
- rfh->ExecuteJavaScriptInIsolatedWorld(toString16(javaScript), std::move(callback), worldId);
- return m_nextRequestId++;
+ rfh->ExecuteJavaScriptInIsolatedWorld(toString16(javaScript), std::move(internalCallback),
+ worldId);
+}
+
+void WebContentsAdapter::didRunJavaScript(quint64 requestId, const base::Value &result)
+{
+ Q_ASSERT(requestId);
+ auto callback = m_javaScriptCallbacks.take(requestId);
+ Q_ASSERT(callback);
+ callback(fromJSValue(&result));
+}
+
+// Called when QWebEnginePage is deleted
+void WebContentsAdapter::clearJavaScriptCallbacks()
+{
+ for (auto varFun : std::as_const(m_javaScriptCallbacks))
+ varFun(QVariant());
+ m_javaScriptCallbacks.clear();
}
quint64 WebContentsAdapter::fetchDocumentMarkup()
diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h
index a5cad8664..24de7eb1b 100644
--- a/src/core/web_contents_adapter.h
+++ b/src/core/web_contents_adapter.h
@@ -16,8 +16,10 @@
#define WEB_CONTENTS_ADAPTER_H
#include <QtCore/QSharedPointer>
+#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QUrl>
+#include <QtCore/QVariant>
#include <QtCore/QPointer>
#include <QtGui/qtgui-config.h>
#include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h>
@@ -27,6 +29,7 @@
#include "web_contents_adapter_client.h"
+#include <functional>
#include <memory>
#include <optional>
@@ -36,9 +39,14 @@ struct WebPreferences;
}
}
+namespace base {
+class Value;
+}
+
namespace content {
class WebContents;
class SiteInstance;
+class RenderFrameHost;
}
QT_BEGIN_NAMESPACE
@@ -64,6 +72,8 @@ class WebChannelIPCTransportHost;
class Q_WEBENGINECORE_EXPORT WebContentsAdapter : public QEnableSharedFromThis<WebContentsAdapter> {
public:
+ // Sentinel to indicate that a behavior should happen on the main frame
+ static constexpr quint64 kUseMainFrameId = -2;
// Sentinel to indicate a frame doesn't exist, for example with `findFrameByName`
static constexpr quint64 kInvalidFrameId = -3;
@@ -129,8 +139,10 @@ public:
void serializeNavigationHistory(QDataStream &output);
void setZoomFactor(qreal);
qreal currentZoomFactor() const;
- void runJavaScript(const QString &javaScript, quint32 worldId);
- quint64 runJavaScriptCallbackResult(const QString &javaScript, quint32 worldId);
+ void runJavaScript(const QString &javaScript, quint32 worldId, quint64 frameId,
+ const std::function<void(const QVariant &)> &callback);
+ void didRunJavaScript(quint64 requestId, const base::Value &result);
+ void clearJavaScriptCallbacks();
quint64 fetchDocumentMarkup();
quint64 fetchDocumentInnerText();
void updateWebPreferences(const blink::web_pref::WebPreferences &webPreferences);
@@ -230,6 +242,7 @@ private:
Q_DISABLE_COPY(WebContentsAdapter)
void waitForUpdateDragActionCalled();
bool handleDropDataFileContents(const content::DropData &dropData, QMimeData *mimeData);
+ content::RenderFrameHost *renderFrameHostFromFrameId(quint64 frameId) const;
void wasShown();
void wasHidden();
@@ -255,6 +268,7 @@ private:
WebContentsAdapterClient *m_adapterClient;
quint64 m_nextRequestId;
QMap<QUrl, bool> m_pendingMouseLockPermissions;
+ QMap<quint64, std::function<void(const QVariant &)>> m_javaScriptCallbacks;
std::unique_ptr<content::DropData> m_currentDropData;
uint m_currentDropAction;
bool m_updateDragActionCalled;
diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h
index a1ad301ed..4c664fd21 100644
--- a/src/core/web_contents_adapter_client.h
+++ b/src/core/web_contents_adapter_client.h
@@ -147,6 +147,7 @@ public:
virtual void titleChanged(const QString&) = 0;
virtual void urlChanged() = 0;
virtual void iconChanged(const QUrl&) = 0;
+ virtual void zoomFactorChanged(qreal factor) = 0;
virtual void loadProgressChanged(int progress) = 0;
virtual void didUpdateTargetURL(const QUrl&) = 0;
virtual void selectionChanged() = 0;
@@ -175,7 +176,8 @@ public:
virtual void javascriptDialog(QSharedPointer<JavaScriptDialogController>) = 0;
virtual void runFileChooser(QSharedPointer<FilePickerController>) = 0;
virtual void showColorDialog(QSharedPointer<ColorChooserController>) = 0;
- virtual void didRunJavaScript(quint64 requestId, const QVariant& result) = 0;
+ virtual void runJavaScript(const QString &script, quint32 worldId, quint64 frameId,
+ const std::function<void(const QVariant &)> &callback) = 0;
virtual void didFetchDocumentMarkup(quint64 requestId, const QString& result) = 0;
virtual void didFetchDocumentInnerText(quint64 requestId, const QString& result) = 0;
virtual void didPrintPage(quint64 requestId, QSharedPointer<QByteArray>) = 0;
diff --git a/src/pdfquick/qquickpdfpageimage.cpp b/src/pdfquick/qquickpdfpageimage.cpp
index f2da067f1..9ff0337a5 100644
--- a/src/pdfquick/qquickpdfpageimage.cpp
+++ b/src/pdfquick/qquickpdfpageimage.cpp
@@ -42,7 +42,7 @@ QQuickPdfPageImage::~QQuickPdfPageImage()
{
Q_D(QQuickPdfPageImage);
// cancel any async rendering job that is running on my behalf
- d->pix.clear();
+ d->pendingPix->clear();
}
/*!
@@ -97,21 +97,23 @@ void QQuickPdfPageImage::load()
thisRequestFinished =
QQuickImageBase::staticMetaObject.indexOfSlot("requestFinished()");
}
+ static QMetaMethod requestFinishedSlot = staticMetaObject.method(thisRequestFinished);
- d->pix.loadImageFromDevice(qmlEngine(this), carrierFile, url,
+ d->pendingPix->loadImageFromDevice(qmlEngine(this), carrierFile, url,
d->sourceClipRect.toRect(), d->sourcesize * d->devicePixelRatio,
QQuickImageProviderOptions(), d->currentFrame, d->frameCount);
qCDebug(qLcImg) << "loading page" << d->currentFrame << "of" << d->frameCount
- << "from" << carrierFile->fileName() << "status" << d->pix.status();
+ << "from" << carrierFile->fileName() << "status" << d->pendingPix->status();
- switch (d->pix.status()) {
+ switch (d->pendingPix->status()) {
case QQuickPixmap::Ready:
+ requestFinishedSlot.invoke(this);
pixmapChange();
break;
case QQuickPixmap::Loading:
- d->pix.connectFinished(this, thisRequestFinished);
- d->pix.connectDownloadProgress(this, thisRequestProgress);
+ d->pendingPix->connectFinished(this, thisRequestFinished);
+ d->pendingPix->connectDownloadProgress(this, thisRequestProgress);
if (d->progress != 0.0) {
d->progress = 0.0;
emit progressChanged(d->progress);
@@ -122,7 +124,7 @@ void QQuickPdfPageImage::load()
}
break;
default:
- qCDebug(qLcImg) << "unexpected status" << d->pix.status();
+ qCDebug(qLcImg) << "unexpected status" << d->pendingPix->status();
break;
}
}
diff --git a/src/webenginequick/api/qquickwebengineview.cpp b/src/webenginequick/api/qquickwebengineview.cpp
index 11ed33b5e..7c77f22de 100644
--- a/src/webenginequick/api/qquickwebengineview.cpp
+++ b/src/webenginequick/api/qquickwebengineview.cpp
@@ -572,6 +572,12 @@ void QQuickWebEngineViewPrivate::iconChanged(const QUrl &url)
QTimer::singleShot(0, q, &QQuickWebEngineView::iconChanged);
}
+void QQuickWebEngineViewPrivate::zoomFactorChanged(qreal factor)
+{
+ Q_Q(QQuickWebEngineView);
+ Q_EMIT q->zoomFactorChanged(factor);
+}
+
void QQuickWebEngineViewPrivate::loadProgressChanged(int progress)
{
Q_Q(QQuickWebEngineView);
@@ -1225,7 +1231,6 @@ void QQuickWebEngineView::setZoomFactor(qreal arg)
d->adapter->setZoomFactor(arg);
// MEMO: should reset if factor was not applied due to being invalid
d->m_zoomFactor = zoomFactor();
- emit zoomFactorChanged(d->m_zoomFactor);
} else {
d->m_zoomFactor = arg;
}
@@ -1296,19 +1301,18 @@ bool QQuickWebEngineView::activeFocusOnPress() const
return d->m_activeFocusOnPress;
}
-void QQuickWebEngineViewPrivate::didRunJavaScript(quint64 requestId, const QVariant &result)
+void QQuickWebEngineViewPrivate::runJavaScript(
+ const QString &script, quint32 worldId, quint64 frameId,
+ const std::function<void(const QVariant &)> &callback)
{
- Q_Q(QQuickWebEngineView);
- QJSValue callback = m_callbacks.take(requestId);
- QJSValueList args;
- args.append(qmlEngine(q)->toScriptValue(result));
- callback.call(args);
+ ensureContentsAdapter();
+ adapter->runJavaScript(script, worldId, frameId, callback);
}
void QQuickWebEngineViewPrivate::didPrintPage(quint64 requestId, QSharedPointer<QByteArray> result)
{
Q_Q(QQuickWebEngineView);
- QJSValue callback = m_callbacks.take(requestId);
+ QJSValue callback = m_printCallbacks.take(requestId);
QJSValueList args;
args.append(qmlEngine(q)->toScriptValue(*(result.data())));
callback.call(args);
@@ -1487,16 +1491,15 @@ void QQuickWebEngineView::runJavaScript(const QString &script, const QJSValue &c
void QQuickWebEngineView::runJavaScript(const QString &script, quint32 worldId, const QJSValue &callback)
{
Q_D(QQuickWebEngineView);
- d->ensureContentsAdapter();
+ std::function<void(const QVariant &)> wrappedCallback;
if (!callback.isUndefined()) {
- quint64 requestId = d_ptr->adapter->runJavaScriptCallbackResult(script, worldId);
- if (requestId) {
- d->m_callbacks.insert(requestId, callback);
- } else {
- callback.call();
- }
- } else
- d->adapter->runJavaScript(script, worldId);
+ wrappedCallback = [this, callback](const QVariant &result) {
+ QJSValueList args;
+ args.append(qmlEngine(this)->toScriptValue(result));
+ callback.call(args);
+ };
+ }
+ d->runJavaScript(script, worldId, WebContentsAdapter::kUseMainFrameId, wrappedCallback);
}
qreal QQuickWebEngineView::zoomFactor() const
@@ -1593,7 +1596,7 @@ void QQuickWebEngineView::printToPdf(const QJSValue &callback, PrintedPageSizeId
d->ensureContentsAdapter();
quint64 requestId = d->adapter->printToPDFCallbackResult(pageLayout, ranges);
- d->m_callbacks.insert(requestId, callback);
+ d->m_printCallbacks.insert(requestId, callback);
#else
Q_UNUSED(pageSizeId);
Q_UNUSED(orientation);
diff --git a/src/webenginequick/api/qquickwebengineview_p_p.h b/src/webenginequick/api/qquickwebengineview_p_p.h
index cf4da7c40..50667dda0 100644
--- a/src/webenginequick/api/qquickwebengineview_p_p.h
+++ b/src/webenginequick/api/qquickwebengineview_p_p.h
@@ -64,6 +64,7 @@ public:
void titleChanged(const QString&) override;
void urlChanged() override;
void iconChanged(const QUrl&) override;
+ void zoomFactorChanged(qreal factor) override;
void loadProgressChanged(int progress) override;
void didUpdateTargetURL(const QUrl&) override;
void selectionChanged() override;
@@ -92,7 +93,8 @@ public:
void runFileChooser(QSharedPointer<QtWebEngineCore::FilePickerController>) override;
void desktopMediaRequested(QtWebEngineCore::DesktopMediaController *) override;
void showColorDialog(QSharedPointer<QtWebEngineCore::ColorChooserController>) override;
- void didRunJavaScript(quint64, const QVariant&) override;
+ void runJavaScript(const QString &script, quint32 worldId, quint64 frameId,
+ const std::function<void(const QVariant &)> &callback) override;
void didFetchDocumentMarkup(quint64, const QString&) override { }
void didFetchDocumentInnerText(quint64, const QString&) override { }
void didPrintPage(quint64 requestId, QSharedPointer<QByteArray>) override;
@@ -157,7 +159,7 @@ public:
bool m_fullscreenMode;
bool isLoading;
bool m_activeFocusOnPress;
- QMap<quint64, QJSValue> m_callbacks;
+ QMap<quint64, QJSValue> m_printCallbacks;
QQmlWebChannel *m_webChannel;
QPointer<QQuickWebEngineView> inspectedView;
QPointer<QQuickWebEngineView> devToolsView;
diff --git a/src/webenginequick/doc/src/webengineframe.qdoc b/src/webenginequick/doc/src/webengineframe.qdoc
index ef2a5c33d..e1c63b923 100644
--- a/src/webenginequick/doc/src/webengineframe.qdoc
+++ b/src/webenginequick/doc/src/webengineframe.qdoc
@@ -63,3 +63,37 @@
If the frame could not be found, returns a default size with dimensions (-1, -1).
*/
+
+/*!
+ \qmlmethod void WebEngineFrame::runJavaScript(string script, variant callback)
+ \qmlmethod void WebEngineFrame::runJavaScript(string script, uint worldId, variant callback)
+
+ Runs the JavaScript code contained in \a script on this frame, without checking
+ whether the DOM of the page has been constructed.
+
+ To avoid conflicts with other scripts executed on the page, the world in
+ which the script is run is specified by \a worldId. The world ID values are
+ the same as provided by QWebEngineScript::ScriptWorldId, and between \c 0
+ and \c 256. If you leave out the \c world ID, the script is run in the
+ \c MainWorld.
+
+ The \a callback parameter is optional. If a callback function is provided, it will be
+ invoked after the script finishes running.
+ \code
+ frame.runJavaScript("document.title", function(result) { console.log(result); });
+ \endcode
+
+ Only plain data can be returned from JavaScript as the result value.
+ Supported data types include all of the JSON data types as well as, for
+ example, \c{Date} and \c{ArrayBuffer}. Unsupported data types include, for
+ example, \c{Function} and \c{Promise}.
+
+ The script will run in the same \e world as other scripts that are
+ part of the loaded site.
+
+ \warning Do not execute lengthy routines in the callback function, because it might block the
+ rendering of the web content.
+
+ For more information about injecting scripts, see \l {Script Injection}.
+ For an alternative way to inject scripts, see WebEngineView::userScripts.
+*/
diff --git a/src/webenginequick/doc/src/webengineview_lgpl.qdoc b/src/webenginequick/doc/src/webengineview_lgpl.qdoc
index dbaea62e4..bbefcd2bc 100644
--- a/src/webenginequick/doc/src/webengineview_lgpl.qdoc
+++ b/src/webenginequick/doc/src/webengineview_lgpl.qdoc
@@ -367,6 +367,8 @@
/*!
\qmlmethod void WebEngineView::runJavaScript(string script, variant callback)
+ \qmlmethod void WebEngineView::runJavaScript(string script, int worldId, variant callback)
+
Runs the specified \a script in the content of the web view.
The \a callback parameter is optional. If a callback function is provided,
@@ -381,8 +383,10 @@
example, \c{Date} and \c{ArrayBuffer}. Unsupported data types include, for
example, \c{Function} and \c{Promise}.
- The script will run in the same \e world as other scripts that are
- part of the loaded site.
+ To avoid conflicts with other scripts executed on the page, the world in
+ which the script is run can be specified by \a worldId. The world ID must be
+ between \c 0 and \c 256. If you leave out the \c world ID, the script is
+ run in the \c MainWorld.
\warning Do not execute lengthy routines in the callback function, because it might block the
rendering of the web content.
@@ -1598,5 +1602,14 @@
\sa QWebEngineWebAuthUxRequest
*/
+/*!
+ \qmlsignal WebEngineView::zoomFactorChanged(qreal factor);
+ \since QtWebEngine 6.8
+
+ This signal is emitted whenever the zoom \a factor for the page changes.
+
+ \sa zoomFactor
+*/
+
\sa {WebEngine Qt Quick Custom Touch Handle Example}
*/
diff --git a/tests/auto/core/certificateerror/tst_certificateerror.cpp b/tests/auto/core/certificateerror/tst_certificateerror.cpp
index 67e2d8ae4..61201e250 100644
--- a/tests/auto/core/certificateerror/tst_certificateerror.cpp
+++ b/tests/auto/core/certificateerror/tst_certificateerror.cpp
@@ -19,6 +19,7 @@ private Q_SLOTS:
void handleError_data();
void handleError();
void fatalError();
+ void resourceError();
};
struct PageWithCertificateErrorHandler : QWebEnginePage
@@ -130,5 +131,20 @@ void tst_CertificateError::fatalError()
}
}
+void tst_CertificateError::resourceError()
+{
+ PageWithCertificateErrorHandler page(false, false);
+ page.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false);
+
+ page.setHtml("<img src=\"https://expired.badssl.com\">");
+ if (!page.loadSpy.wait(10000)) {
+ QVERIFY2(!page.error, "There shouldn't be any certificate error if not loaded due to missing internet access!");
+ QSKIP("Couldn't load page from network, skipping test.");
+ }
+
+ QTRY_VERIFY(page.error);
+ QCOMPARE(page.error->isMainFrame(), false);
+}
+
QTEST_MAIN(tst_CertificateError)
#include <tst_certificateerror.moc>
diff --git a/tests/auto/core/qwebengineframe/tst_qwebengineframe.cpp b/tests/auto/core/qwebengineframe/tst_qwebengineframe.cpp
index b70a655d3..7cd075443 100644
--- a/tests/auto/core/qwebengineframe/tst_qwebengineframe.cpp
+++ b/tests/auto/core/qwebengineframe/tst_qwebengineframe.cpp
@@ -37,6 +37,7 @@ private Q_SLOTS:
void childrenOfInvalidFrame();
void url();
void size();
+ void runJavaScript();
private:
};
@@ -175,6 +176,19 @@ void tst_QWebEngineFrame::size()
QCOMPARE(frame1.size(), QSizeF());
}
+void tst_QWebEngineFrame::runJavaScript()
+{
+ QWebEnginePage page;
+ QSignalSpy loadSpy{ &page, SIGNAL(loadFinished(bool)) };
+ page.load(QUrl("qrc:/resources/iframes.html"));
+ QTRY_COMPARE(loadSpy.size(), 1);
+ auto children = page.mainFrame().children();
+ CallbackSpy<QVariant> spy;
+ children[0].runJavaScript("window.name", spy.ref());
+ auto result = spy.waitForResult();
+ QCOMPARE(result, QString("test-subframe0"));
+}
+
QTEST_MAIN(tst_QWebEngineFrame)
#include "tst_qwebengineframe.moc"
diff --git a/tests/auto/quick/publicapi/tst_publicapi.cpp b/tests/auto/quick/publicapi/tst_publicapi.cpp
index 4d9d02bca..990b1de4f 100644
--- a/tests/auto/quick/publicapi/tst_publicapi.cpp
+++ b/tests/auto/quick/publicapi/tst_publicapi.cpp
@@ -134,6 +134,7 @@ static const QStringList expectedAPI = QStringList()
<< "QWebEngineCertificateError.defer() --> void"
<< "QWebEngineCertificateError.description --> QString"
<< "QWebEngineCertificateError.type --> QWebEngineCertificateError::Type"
+ << "QWebEngineCertificateError.isMainFrame --> bool"
<< "QWebEngineCertificateError.acceptCertificate() --> void"
<< "QWebEngineCertificateError.overridable --> bool"
<< "QWebEngineCertificateError.rejectCertificate() --> void"
@@ -887,6 +888,10 @@ static const QStringList expectedAPI = QStringList()
<< "QWebEngineFrame.htmlName --> QString"
<< "QWebEngineFrame.isValid --> bool"
<< "QWebEngineFrame.name --> QString"
+ << "QWebEngineFrame.runJavaScript(QString) --> void"
+ << "QWebEngineFrame.runJavaScript(QString,uint) --> void"
+ << "QWebEngineFrame.runJavaScript(QString,QJSValue) --> void"
+ << "QWebEngineFrame.runJavaScript(QString,uint,QJSValue) --> void"
<< "QWebEngineFrame.size --> QSizeF"
<< "QWebEngineFrame.url --> QUrl"
;
diff --git a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
index 5bd33332b..cebdaaa47 100644
--- a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
+++ b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
@@ -205,7 +205,11 @@ void tst_QWebEngineProfile::clearDataFromCache()
QCOMPARE_GT(sizeBeforeClear, 0);
profile.clearHttpCache();
QTRY_COMPARE(cacheSpy.size(), 1);
+#if defined(Q_OS_WIN)
+ QTRY_COMPARE_GT(sizeBeforeClear, totalSize(cacheDir));
+#else
QCOMPARE_GT(sizeBeforeClear, totalSize(cacheDir));
+#endif
(void)server.stop();
}
diff --git a/tests/manual/quick/pdf/withdoc.qml b/tests/manual/quick/pdf/withdoc.qml
index d4bf12e29..0a2a86630 100644
--- a/tests/manual/quick/pdf/withdoc.qml
+++ b/tests/manual/quick/pdf/withdoc.qml
@@ -19,6 +19,11 @@ Window {
onPasswordRequired: function() { passwordDialog.open() }
}
+ Component.onCompleted: {
+ if (Application.arguments.length > 2)
+ doc.source = Application.arguments[Application.arguments.length - 1]
+ }
+
FileDialog {
id: fileDialog
title: "Open a PDF file"
@@ -85,6 +90,7 @@ Window {
PdfPageImage {
id: image
document: doc
+ retainWhileLoading: true
property real zoomFactor: Math.sqrt(2)