summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmake/Functions.cmake2
-rw-r--r--coin/qt-installer-package-config.json4
-rw-r--r--configure.cmake3
-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/printme/doc/src/printme.qdoc11
-rw-r--r--examples/webenginewidgets/printme/printhandler.cpp4
-rw-r--r--examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc27
-rw-r--r--examples/webenginewidgets/simplebrowser/tabwidget.cpp5
-rw-r--r--examples/webenginewidgets/simplebrowser/webpage.cpp7
m---------src/3rdparty0
-rw-r--r--src/core/api/CMakeLists.txt1
-rw-r--r--src/core/api/qwebenginecertificateerror.cpp13
-rw-r--r--src/core/api/qwebenginecertificateerror.h2
-rw-r--r--src/core/api/qwebengineframe.cpp118
-rw-r--r--src/core/api/qwebengineframe.h62
-rw-r--r--src/core/api/qwebenginenavigationrequest.cpp27
-rw-r--r--src/core/api/qwebenginenavigationrequest.h4
-rw-r--r--src/core/api/qwebenginepage.cpp78
-rw-r--r--src/core/api/qwebenginepage.h7
-rw-r--r--src/core/api/qwebenginepage_p.h6
-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.cpp8
-rw-r--r--src/core/compositor/native_skia_output_device_mac.mm9
-rw-r--r--src/core/compositor/native_skia_output_device_metal.cpp21
-rw-r--r--src/core/compositor/native_skia_output_device_metal.h3
-rw-r--r--src/core/compositor/native_skia_output_device_opengl.cpp2
-rw-r--r--src/core/content_browser_client_qt.cpp7
-rw-r--r--src/core/doc/src/qwebengine-licensing.qdoc53
-rw-r--r--src/core/favicon_driver_qt.cpp7
-rw-r--r--src/core/favicon_driver_qt.h3
-rw-r--r--src/core/native_web_keyboard_event_qt_mac.mm2
-rw-r--r--src/core/ozone/gl_context_qt.cpp40
-rw-r--r--src/core/ozone/gl_context_qt.h10
-rw-r--r--src/core/ozone/ozone_platform_qt.cpp10
-rw-r--r--src/core/ozone/surface_factory_qt.cpp33
-rw-r--r--src/core/ozone/surface_factory_qt.h2
-rw-r--r--src/core/render_view_context_menu_qt.h2
-rw-r--r--src/core/web_contents_adapter.cpp131
-rw-r--r--src/core/web_contents_adapter.h28
-rw-r--r--src/core/web_contents_adapter_client.h5
-rw-r--r--src/core/web_contents_delegate_qt.cpp2
-rw-r--r--src/core/web_engine_context.cpp364
-rw-r--r--src/pdf/doc/snippets/pdfpageview.qml12
-rw-r--r--src/pdfquick/PdfPageView.qml2
-rw-r--r--src/pdfwidgets/qpdfview.cpp6
-rw-r--r--src/webenginequick/CMakeLists.txt6
-rw-r--r--src/webenginequick/api/qquickwebenginefaviconprovider.cpp224
-rw-r--r--src/webenginequick/api/qquickwebenginefaviconprovider_p_p.h83
-rw-r--r--src/webenginequick/api/qquickwebengineprofile.cpp4
-rw-r--r--src/webenginequick/api/qquickwebengineprofile.h2
-rw-r--r--src/webenginequick/api/qquickwebengineview.cpp69
-rw-r--r--src/webenginequick/api/qquickwebengineview_p.h9
-rw-r--r--src/webenginequick/api/qquickwebengineview_p_p.h11
-rw-r--r--src/webenginequick/doc/src/webengineframe.qdoc65
-rw-r--r--src/webenginequick/doc/src/webengineview_lgpl.qdoc25
-rw-r--r--src/webenginequick/qquickwebengine_accessible.cpp2
-rw-r--r--src/webenginequick/qquickwebengine_accessible_p.h (renamed from src/webenginequick/qquickwebengine_accessible.h)11
-rw-r--r--src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.cpp2
-rw-r--r--src/webenginequick/render_widget_host_view_qt_delegate_quickwindow_p.h (renamed from src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.h)11
-rw-r--r--src/webenginequick/ui_delegates_manager.cpp2
-rw-r--r--src/webenginequick/ui_delegates_manager_p.h (renamed from src/webenginequick/ui_delegates_manager.h)11
-rw-r--r--src/webenginewidgets/CMakeLists.txt2
-rw-r--r--src/webenginewidgets/api/qwebengineview.cpp2
-rw-r--r--src/webenginewidgets/qwebengine_accessible.cpp2
-rw-r--r--src/webenginewidgets/qwebengine_accessible_p.h (renamed from src/webenginewidgets/qwebengine_accessible.h)11
-rw-r--r--tests/auto/core/CMakeLists.txt1
-rw-r--r--tests/auto/core/certificateerror/tst_certificateerror.cpp16
-rw-r--r--tests/auto/core/qwebengineframe/CMakeLists.txt22
-rw-r--r--tests/auto/core/qwebengineframe/resources/frameset.html20
-rw-r--r--tests/auto/core/qwebengineframe/resources/iframes.html17
-rw-r--r--tests/auto/core/qwebengineframe/resources/nesting-iframe.html7
-rw-r--r--tests/auto/core/qwebengineframe/tst_qwebengineframe.cpp180
-rw-r--r--tests/auto/core/qwebengineglobalsettings/CMakeLists.txt1
-rw-r--r--tests/auto/core/qwebengineglobalsettings/tst_qwebengineglobalsettings.cpp17
-rw-r--r--tests/auto/quick/publicapi/tst_publicapi.cpp11
-rw-r--r--tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp29
-rw-r--r--tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp8
-rw-r--r--tests/manual/widgets/CMakeLists.txt4
81 files changed, 1637 insertions, 428 deletions
diff --git a/cmake/Functions.cmake b/cmake/Functions.cmake
index 9864cf97b..6cc8a401e 100644
--- a/cmake/Functions.cmake
+++ b/cmake/Functions.cmake
@@ -1222,6 +1222,8 @@ function(add_gn_build_artifacts_to_target)
if(APPLECLANG)
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "15.0.0")
target_link_options(${arg_CMAKE_TARGET} PRIVATE -ld_classic)
+ set_target_properties(${arg_CMAKE_TARGET} PROPERTIES
+ QT_NO_DISABLE_WARN_DUPLICATE_LIBRARIES TRUE)
endif()
endif()
if(QT_IS_MACOS_UNIVERSAL)
diff --git a/coin/qt-installer-package-config.json b/coin/qt-installer-package-config.json
index ac604d77b..aec45688b 100644
--- a/coin/qt-installer-package-config.json
+++ b/coin/qt-installer-package-config.json
@@ -18,7 +18,9 @@
"**/plugins/imageformats/**/*",
"**/qml/QtQuick/**/*",
"**/qml/QtQuick/Pdf/**/.rcc/*",
- "**/qml/QtQuick/Pdf/**/.rcc/qmlcache/*"
+ "**/qml/QtQuick/Pdf/**/.rcc/qmlcache/*",
+ "**/qml/QtQuick/Pdf/**/.qt/rcc/*",
+ "**/qml/QtQuick/Pdf/**/.qt/rcc/qmlcache/*"
]
}
}
diff --git a/configure.cmake b/configure.cmake
index 9f4831257..2d826e6dd 100644
--- a/configure.cmake
+++ b/configure.cmake
@@ -443,7 +443,8 @@ qt_feature("webengine-ozone-x11" PRIVATE
)
#### Support Checks
-if(WIN32 AND (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64" OR CMAKE_CROSSCOMPILING))
+if(WIN32 AND (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64"
+ OR CMAKE_CROSSCOMPILING))
set(WIN_ARM_64 ON)
else()
set(WIN_ARM_64 OFF)
diff --git a/dependencies.yaml b/dependencies.yaml
index fd2447644..205f9a01c 100644
--- a/dependencies.yaml
+++ b/dependencies.yaml
@@ -1,13 +1,13 @@
dependencies:
../qtdeclarative:
- ref: df707e25bf7adda63746a4ca00c08c41e14cfe20
+ ref: 757bfef221654d5aeee72086393bd67b2c8554e5
required: true
../qtpositioning:
- ref: 3e38181a05d5aea2deaa8a78f1c297faff5cde03
+ ref: 59261c78cd25e5179abd7a0854cf771b13e3ef91
required: false
../qttools:
- ref: 1e4ffb798102a56a73d84bc8ae09243aa8de348e
+ ref: f668ec434ae3c8621b2e27af98a129f6bd676c77
required: false
../qtwebchannel:
- ref: 33463ffbd0f7b06ddf9edc5a34023f1c02966cd4
+ ref: 2366411a5684535c45af03f53f09361afa433fcc
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/printme/doc/src/printme.qdoc b/examples/webenginewidgets/printme/doc/src/printme.qdoc
index cac69aa41..91aecf6de 100644
--- a/examples/webenginewidgets/printme/doc/src/printme.qdoc
+++ b/examples/webenginewidgets/printme/doc/src/printme.qdoc
@@ -55,9 +55,11 @@
Now we can implement the \c{PrintHandler::printDocument()} slot, which is
called in response to the \l{QPrintPreviewDialog::paintRequested} signal.
To do actual painting on a printer, we call the \l QWebEngineView::print()
- function. Because this call is asynchronous, we need to use
- a local event loop. We begin the local event loop by calling
- \l{QEventLoop::exec()}.
+ function. Printing is an async operation in Chromium, but not in Qt, so we
+ run a local event loop using \l{QEventLoop::exec()} to make sure printing
+ is done before returning. User input is blocked, since clicking on a button
+ while we're waiting for the print to finish can mess up the internal state
+ and cause a crash.
\quotefromfile webenginewidgets/printme/printhandler.cpp
\skipto PrintHandler::printDocument(
@@ -66,7 +68,8 @@
To get notified about the result of printing job, we implement
\c{PrintHandler::printFinished()} slot as handler of
\l QWebEngineView::printFinished() signal. We check for \c{success} and
- report any errors that occurred.
+ report any errors that occurred. Finally, we call \l{QEventLoop::quit()}
+ to exit out of the local event loop.
\quotefromfile webenginewidgets/printme/printhandler.cpp
\skipto PrintHandler::printFinished(
diff --git a/examples/webenginewidgets/printme/printhandler.cpp b/examples/webenginewidgets/printme/printhandler.cpp
index fa67fe314..9f8f6ee0b 100644
--- a/examples/webenginewidgets/printme/printhandler.cpp
+++ b/examples/webenginewidgets/printme/printhandler.cpp
@@ -32,7 +32,9 @@ void PrintHandler::print()
void PrintHandler::printDocument(QPrinter *printer)
{
m_view->print(printer);
- m_waitForResult.exec();
+ // User input in the print preview dialog while we're waiting on a print task
+ // can mess up the internal state and cause a crash.
+ m_waitForResult.exec(QEventLoop::ExcludeUserInputEvents);
}
void PrintHandler::printFinished(bool success)
diff --git a/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc b/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc
index dd7a8b998..a312da3ad 100644
--- a/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc
+++ b/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc
@@ -103,6 +103,25 @@
\skipto TabWidget::setupView
\printuntil /^\}/
+ \section1 Closing Tabs
+
+ When the user closes a tab, we first trigger the \l {QWebEnginePage::}{RequestClose} web action
+ on the corresponding \c WebView:
+
+ \quotefromfile webenginewidgets/simplebrowser/tabwidget.cpp
+ \skipto QTabBar::tabCloseRequested
+ \printuntil }
+
+ This allows any JavaScript \c beforeunload event listeners to fire, which may
+ prompt the user with a dialog to confirm that they want to close the page.
+ In this case, the user can reject the close request and leave the tab open,
+ otherwise the \l {QWebEnginePage::}{windowCloseRequested} signal is emitted and we close the
+ tab:
+
+ \quotefromfile webenginewidgets/simplebrowser/tabwidget.cpp
+ \skipto QWebEnginePage::windowCloseRequested
+ \printuntil }
+
\section1 Implementing WebView Functionality
The \c WebView is derived from QWebEngineView to support the following
@@ -204,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/tabwidget.cpp b/examples/webenginewidgets/simplebrowser/tabwidget.cpp
index f9037a8e1..acdf49510 100644
--- a/examples/webenginewidgets/simplebrowser/tabwidget.cpp
+++ b/examples/webenginewidgets/simplebrowser/tabwidget.cpp
@@ -21,7 +21,10 @@ TabWidget::TabWidget(QWebEngineProfile *profile, QWidget *parent)
tabBar->setMovable(true);
tabBar->setContextMenuPolicy(Qt::CustomContextMenu);
connect(tabBar, &QTabBar::customContextMenuRequested, this, &TabWidget::handleContextMenuRequested);
- connect(tabBar, &QTabBar::tabCloseRequested, this, &TabWidget::closeTab);
+ connect(tabBar, &QTabBar::tabCloseRequested, [this](int index) {
+ if (WebView *view = webView(index))
+ view->page()->triggerAction(QWebEnginePage::WebAction::RequestClose);
+ });
connect(tabBar, &QTabBar::tabBarDoubleClicked, [this](int index) {
if (index == -1)
createTab();
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/3rdparty b/src/3rdparty
-Subproject c60705f47d06c2059743e8170de8e805880a741
+Subproject 814db44bc99f79d0c4a847e0cac4a398034ee2f
diff --git a/src/core/api/CMakeLists.txt b/src/core/api/CMakeLists.txt
index f2ceb2dfd..c06f5e4ce 100644
--- a/src/core/api/CMakeLists.txt
+++ b/src/core/api/CMakeLists.txt
@@ -19,6 +19,7 @@ qt_internal_add_module(WebEngineCore
qwebenginedownloadrequest.cpp qwebenginedownloadrequest.h qwebenginedownloadrequest_p.h
qwebenginefilesystemaccessrequest.cpp qwebenginefilesystemaccessrequest.h
qwebenginefindtextresult.cpp qwebenginefindtextresult.h
+ qwebengineframe.cpp qwebengineframe.h
qwebenginefullscreenrequest.cpp qwebenginefullscreenrequest.h
qwebenginehistory.cpp qwebenginehistory.h qwebenginehistory_p.h
qwebenginehttprequest.cpp qwebenginehttprequest.h
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
new file mode 100644
index 000000000..edd89d663
--- /dev/null
+++ b/src/core/api/qwebengineframe.cpp
@@ -0,0 +1,118 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwebengineframe.h"
+
+#include "web_contents_adapter_client.h"
+#include "web_contents_adapter.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QWebEngineFrame
+ \brief The QWebEngineFrame class gives information about and control over a page frame.
+ \since 6.8
+
+ \inmodule QtWebEngineCore
+
+ A web engine frame represents a single frame within a web page, such as those created by
+ \c <frame> or \c <iframe> HTML elements.
+ An active QWebEnginePage has one or more frames arranged in a tree structure. The top-level
+ frame, the root of this tree, can be accessed through the mainFrame() method, and
+ children() provides a frame's direct descendants.
+
+ A frame's lifetime is, at most, as long as the QWebEnginePage object that produced it.
+ However, frames may be created and deleted spontaneously and dynamically, for example through
+ navigation and script execution. Because of this, many QWebEngineFrame methods return
+ optional values, which will be \c std::nullopt if the frame no longer exists.
+*/
+
+/*! \internal
+ */
+QWebEngineFrame::QWebEngineFrame(QtWebEngineCore::WebContentsAdapterClient *adapter, quint64 id)
+ : m_adapterClient(adapter), m_id(id)
+{
+}
+
+/*!
+ Returns \c{true} if this object represents an existing frame; \c{false} otherwise.
+
+ Once a frame is invalid, it never becomes valid again.
+*/
+bool QWebEngineFrame::isValid() const
+{
+ return m_adapterClient->webContentsAdapter()->hasFrame(m_id);
+}
+
+/*!
+ Returns the frame name; that is, what would be returned by \c window.name in JavaScript.
+
+ If the frame could not be found, returns a null QString.
+
+ \sa htmlName
+*/
+QString QWebEngineFrame::name() const
+{
+ return m_adapterClient->webContentsAdapter()->frameName(m_id);
+}
+
+/*!
+ Returns the value of the frame's \c name HTML attribute, or an empty string if it has none.
+
+ If the frame could not be found, returns a null QString.
+
+ \sa name
+*/
+QString QWebEngineFrame::htmlName() const
+{
+ return m_adapterClient->webContentsAdapter()->frameHtmlName(m_id);
+}
+
+/*!
+ Returns a list of the frame's children in an arbitrary order.
+
+ If the frame could not be found, returns an empty list.
+ */
+QList<QWebEngineFrame> QWebEngineFrame::children() const
+{
+ QList<QWebEngineFrame> result;
+ for (auto childId : m_adapterClient->webContentsAdapter()->frameChildren(m_id))
+ result.push_back(QWebEngineFrame{ m_adapterClient, childId });
+ return result;
+}
+
+/*!
+ Returns the URL of the content currently loaded in this frame.
+
+ If the frame could not be found, returns an empty QUrl.
+ */
+QUrl QWebEngineFrame::url() const
+{
+ return m_adapterClient->webContentsAdapter()->frameUrl(m_id);
+}
+
+/*!
+ Returns the size of the frame within the viewport.
+
+ If the frame could not be found, returns QSizeF().
+ */
+QSizeF QWebEngineFrame::size() const
+{
+ return m_adapterClient->webContentsAdapter()->frameSize(m_id);
+}
+
+/*! \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,
+ otherwise \c{false}.
+ */
+
+/*! \fn bool QWebEngineFrame::operator!=(const QWebEngineFrame &left, const QWebEngineFrame &right) noexcept
+
+ Returns \c{true} if \a left and \a right represent different frames in the same web page,
+ otherwise \c{false}.
+ */
+
+QT_END_NAMESPACE
+
+#include "moc_qwebengineframe.cpp"
diff --git a/src/core/api/qwebengineframe.h b/src/core/api/qwebengineframe.h
new file mode 100644
index 000000000..e58961848
--- /dev/null
+++ b/src/core/api/qwebengineframe.h
@@ -0,0 +1,62 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWEBENGINEFRAME_H
+#define QWEBENGINEFRAME_H
+
+#include <QtWebEngineCore/qtwebenginecoreglobal.h>
+#include <QtQml/qqmlregistration.h>
+#include <QtCore/qcompare.h>
+#include <QtCore/QList>
+#include <QtCore/QSizeF>
+#include <QtCore/QString>
+#include <QtCore/QUrl>
+
+namespace QtWebEngineCore {
+class WebContentsAdapterClient;
+}
+
+QT_BEGIN_NAMESPACE
+
+class Q_WEBENGINECORE_EXPORT QWebEngineFrame
+{
+ Q_GADGET
+
+ Q_PROPERTY(bool isValid READ isValid FINAL)
+ Q_PROPERTY(QString name READ name FINAL)
+ Q_PROPERTY(QString htmlName READ htmlName FINAL)
+ Q_PROPERTY(QUrl url READ url FINAL)
+ Q_PROPERTY(QSizeF size READ size FINAL)
+
+public:
+ QML_VALUE_TYPE(webEngineFrame)
+ QML_ADDED_IN_VERSION(6, 8)
+
+ bool isValid() const;
+ QString name() const;
+ QString htmlName() const;
+ QList<QWebEngineFrame> children() const;
+ QUrl url() const;
+ QSizeF size() const;
+
+ friend inline bool comparesEqual(const QWebEngineFrame &lhs,
+ const QWebEngineFrame &rhs) noexcept
+ {
+ return lhs.m_adapterClient == rhs.m_adapterClient && lhs.m_id == rhs.m_id;
+ }
+
+ Q_DECLARE_EQUALITY_COMPARABLE(QWebEngineFrame);
+
+private:
+ friend class QWebEnginePage;
+ friend class QQuickWebEngineView;
+
+ QWebEngineFrame(QtWebEngineCore::WebContentsAdapterClient *page, quint64 id);
+
+ QtWebEngineCore::WebContentsAdapterClient *m_adapterClient;
+ quint64 m_id;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWEBENGINEFRAME_H
diff --git a/src/core/api/qwebenginenavigationrequest.cpp b/src/core/api/qwebenginenavigationrequest.cpp
index 0a30f6472..dc7447b88 100644
--- a/src/core/api/qwebenginenavigationrequest.cpp
+++ b/src/core/api/qwebenginenavigationrequest.cpp
@@ -9,15 +9,17 @@ QT_BEGIN_NAMESPACE
class QWebEngineNavigationRequestPrivate {
public:
- QWebEngineNavigationRequestPrivate(const QUrl& url, QWebEngineNavigationRequest::NavigationType navigationType, bool mainFrame)
+ QWebEngineNavigationRequestPrivate(const QUrl& url, QWebEngineNavigationRequest::NavigationType navigationType, bool mainFrame, bool formData)
: url(url)
, navigationType(navigationType)
, isMainFrame(mainFrame)
+ , hasFormData(formData)
{}
QUrl url;
QWebEngineNavigationRequest::NavigationType navigationType;
bool isMainFrame;
+ bool hasFormData;
bool isAccepted = true;
};
@@ -51,9 +53,9 @@ public:
/*! \internal
*/
-QWebEngineNavigationRequest::QWebEngineNavigationRequest(const QUrl& url, QWebEngineNavigationRequest::NavigationType navigationType, bool mainFrame, QObject* parent)
+QWebEngineNavigationRequest::QWebEngineNavigationRequest(const QUrl& url, QWebEngineNavigationRequest::NavigationType navigationType, bool mainFrame, bool formData, QObject* parent)
: QObject(parent)
- , d_ptr(new QWebEngineNavigationRequestPrivate(url, navigationType, mainFrame))
+ , d_ptr(new QWebEngineNavigationRequestPrivate(url, navigationType, mainFrame, formData))
{
}
@@ -174,6 +176,25 @@ bool QWebEngineNavigationRequest::isMainFrame() const
return d->isMainFrame;
}
+/*!
+ \property QWebEngineNavigationRequest::hasFormData
+ \brief Whether the navigation request contains form data
+ \since 6.8
+*/
+/*!
+ \qmlproperty bool WebEngineNavigationRequest::hasFormData
+ \since 6.8
+ \readonly
+
+ Whether the navigation request contains form data
+*/
+
+bool QWebEngineNavigationRequest::hasFormData() const
+{
+ Q_D(const QWebEngineNavigationRequest);
+ return d->hasFormData;
+}
+
/*! \internal */
bool QWebEngineNavigationRequest::isAccepted() const
{
diff --git a/src/core/api/qwebenginenavigationrequest.h b/src/core/api/qwebenginenavigationrequest.h
index 12fc2b4a1..a810a59fe 100644
--- a/src/core/api/qwebenginenavigationrequest.h
+++ b/src/core/api/qwebenginenavigationrequest.h
@@ -17,6 +17,7 @@ class Q_WEBENGINECORE_EXPORT QWebEngineNavigationRequest : public QObject
Q_OBJECT
Q_PROPERTY(QUrl url READ url CONSTANT FINAL)
Q_PROPERTY(bool isMainFrame READ isMainFrame CONSTANT FINAL)
+ Q_PROPERTY(bool hasFormData READ hasFormData CONSTANT REVISION(6, 8) FINAL)
Q_PROPERTY(NavigationType navigationType READ navigationType CONSTANT FINAL)
public:
@@ -36,6 +37,7 @@ public:
QUrl url() const;
bool isMainFrame() const;
+ bool hasFormData() const;
NavigationType navigationType() const;
Q_INVOKABLE void accept();
@@ -60,7 +62,7 @@ Q_SIGNALS:
#endif
private:
- QWebEngineNavigationRequest(const QUrl &url, NavigationType navigationType, bool mainFrame,
+ QWebEngineNavigationRequest(const QUrl &url, NavigationType navigationType, bool mainFrame, bool formData,
QObject *parent = nullptr);
friend class QWebEnginePagePrivate;
diff --git a/src/core/api/qwebenginepage.cpp b/src/core/api/qwebenginepage.cpp
index ac645c430..146b1804e 100644
--- a/src/core/api/qwebenginepage.cpp
+++ b/src/core/api/qwebenginepage.cpp
@@ -489,10 +489,16 @@ void QWebEnginePagePrivate::windowCloseRejected()
// Do nothing for now.
}
-void QWebEnginePagePrivate::didRunJavaScript(quint64 requestId, const QVariant& result)
+void QWebEnginePagePrivate::runJavaScript(const QString &script, quint32 worldId,
+ 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, callback);
}
void QWebEnginePagePrivate::didFetchDocumentMarkup(quint64 requestId, const QString& result)
@@ -971,11 +977,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();
}
}
@@ -1516,13 +1520,13 @@ void QWebEnginePagePrivate::contextMenuRequested(QWebEngineContextMenuRequest *d
\sa acceptNavigationRequest()
*/
-void QWebEnginePagePrivate::navigationRequested(int navigationType, const QUrl &url, bool &accepted, bool isMainFrame)
+void QWebEnginePagePrivate::navigationRequested(int navigationType, const QUrl &url, bool &accepted, bool isMainFrame, bool hasFormData)
{
Q_Q(QWebEnginePage);
accepted = q->acceptNavigationRequest(url, static_cast<QWebEnginePage::NavigationType>(navigationType), isMainFrame);
if (accepted) {
- QWebEngineNavigationRequest navigationRequest(url, static_cast<QWebEngineNavigationRequest::NavigationType>(navigationType), isMainFrame);
+ QWebEngineNavigationRequest navigationRequest(url, static_cast<QWebEngineNavigationRequest::NavigationType>(navigationType), isMainFrame, hasFormData);
Q_EMIT q->navigationRequested(navigationRequest);
accepted = navigationRequest.isAccepted();
}
@@ -2029,40 +2033,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, resultCallback);
}
/*!
@@ -2501,6 +2478,33 @@ void QWebEnginePage::setVisible(bool visible)
d->adapter->setVisible(visible);
}
+/*!
+ \since 6.8
+
+ The main, top-level frame of the page. All other frames on this page are accessible
+ as children of the main frame.
+*/
+QWebEngineFrame QWebEnginePage::mainFrame()
+{
+ Q_D(QWebEnginePage);
+ return QWebEngineFrame(d, d->adapter->mainFrameId());
+}
+
+/*!
+ \since 6.8
+
+ Returns the frame with the given \a name. If there are multiple frames with the same
+ name, which one is returned is arbitrary. If no frame was found, returns \c std::nullopt.
+*/
+std::optional<QWebEngineFrame> QWebEnginePage::findFrameByName(const QString &name)
+{
+ Q_D(QWebEnginePage);
+ if (auto maybeId = d->adapter->findFrameIdByName(name)) {
+ return QWebEngineFrame(d, *maybeId);
+ }
+ return {};
+}
+
QDataStream &operator<<(QDataStream &stream, const QWebEngineHistory &history)
{
auto adapter = history.d_func()->adapter();
diff --git a/src/core/api/qwebenginepage.h b/src/core/api/qwebenginepage.h
index 621dacdc8..e5a4e9551 100644
--- a/src/core/api/qwebenginepage.h
+++ b/src/core/api/qwebenginepage.h
@@ -8,6 +8,7 @@
#include <QtWebEngineCore/qwebengineclientcertificateselection.h>
#include <QtWebEngineCore/qwebenginedownloadrequest.h>
#include <QtWebEngineCore/qwebenginequotarequest.h>
+#include <QtWebEngineCore/qwebengineframe.h>
#include <QtCore/qobject.h>
#include <QtCore/qurl.h>
@@ -16,6 +17,7 @@
#include <QtGui/qtgui-config.h>
#include <functional>
+#include <optional>
QT_BEGIN_NAMESPACE
@@ -50,7 +52,7 @@ class Q_WEBENGINECORE_EXPORT QWebEnginePage : public QObject
Q_PROPERTY(bool hasSelection READ hasSelection)
Q_PROPERTY(QUrl requestedUrl READ requestedUrl)
Q_PROPERTY(qreal zoomFactor READ zoomFactor WRITE setZoomFactor)
- Q_PROPERTY(QString title READ title)
+ 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)
Q_PROPERTY(QIcon icon READ icon NOTIFY iconChanged)
@@ -301,6 +303,9 @@ public:
bool isVisible() const;
void setVisible(bool visible);
+ QWebEngineFrame mainFrame();
+ std::optional<QWebEngineFrame> findFrameByName(const QString &name);
+
void acceptAsNewWindow(QWebEngineNewWindowRequest &request);
Q_SIGNALS:
diff --git a/src/core/api/qwebenginepage_p.h b/src/core/api/qwebenginepage_p.h
index a51d8603b..42aba54d4 100644
--- a/src/core/api/qwebenginepage_p.h
+++ b/src/core/api/qwebenginepage_p.h
@@ -124,13 +124,14 @@ public:
void windowCloseRejected() override;
void desktopMediaRequested(QtWebEngineCore::DesktopMediaController *) override;
void contextMenuRequested(QWebEngineContextMenuRequest *request) override;
- void navigationRequested(int navigationType, const QUrl &url, bool &accepted, bool isMainFrame) override;
+ void navigationRequested(int navigationType, const QUrl &url, bool &accepted, bool isMainFrame, bool hasFormData) override;
void requestFullScreenMode(const QUrl &origin, bool fullscreen) override;
bool isFullScreenMode() const override;
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,
+ 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 +215,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.cpp b/src/core/compositor/native_skia_output_device.cpp
index 8f11e5162..708692df7 100644
--- a/src/core/compositor/native_skia_output_device.cpp
+++ b/src/core/compositor/native_skia_output_device.cpp
@@ -309,11 +309,13 @@ std::vector<GrBackendSemaphore> NativeSkiaOutputDevice::Buffer::takeEndWriteSkia
void NativeSkiaOutputDevice::Buffer::createSkImageOnGPUThread()
{
- if (!m_scopedSkiaReadAccess)
+ if (!m_scopedSkiaReadAccess) {
+ m_skImageMutex.unlock();
return;
+ }
- QMutexLocker locker(&m_skImageMutex);
m_cachedSkImage = m_scopedSkiaReadAccess->CreateSkImage(m_parent->m_contextState.get());
+ m_skImageMutex.unlock();
if (!m_cachedSkImage)
qWarning("SKIA: Failed to create SkImage.");
}
@@ -341,6 +343,7 @@ void NativeSkiaOutputDevice::Buffer::beginPresent()
if (!beginSemaphores.empty())
qWarning("SKIA: Unexpected semaphores while reading texture, wait is not implemented.");
+ m_skImageMutex.tryLock();
m_parent->m_gpuTaskRunner->PostTask(FROM_HERE,
base::BindOnce(&NativeSkiaOutputDevice::Buffer::createSkImageOnGPUThread,
base::Unretained(this)));
@@ -390,6 +393,7 @@ void NativeSkiaOutputDevice::Buffer::consumeFence()
sk_sp<SkImage> NativeSkiaOutputDevice::Buffer::skImage()
{
+ QMutexLocker locker(&m_skImageMutex);
return m_cachedSkImage;
}
#if defined(USE_OZONE)
diff --git a/src/core/compositor/native_skia_output_device_mac.mm b/src/core/compositor/native_skia_output_device_mac.mm
index fd3930a9f..bf21ef8d7 100644
--- a/src/core/compositor/native_skia_output_device_mac.mm
+++ b/src/core/compositor/native_skia_output_device_mac.mm
@@ -36,10 +36,17 @@ QSGTexture *makeMetalTexture(QQuickWindow *win, IOSurfaceRef ioSurface, uint ioS
QSGRendererInterface *ri = win->rendererInterface();
auto device = (__bridge id<MTLDevice>)(ri->getResource(win, QSGRendererInterface::DeviceResource));
- auto texture = [device newTextureWithDescriptor:desc iosurface:ioSurface plane:ioSurfacePlane];
+ id<MTLTexture> texture = [device newTextureWithDescriptor:desc
+ iosurface:ioSurface
+ plane:ioSurfacePlane];
return QNativeInterface::QSGMetalTexture::fromNative(texture, win, size, texOpts);
}
+void releaseMetalTexture(void *texture)
+{
+ [static_cast<id<MTLTexture>>(texture) release];
+}
+
#if QT_CONFIG(opengl)
uint32_t makeCGLTexture(QQuickWindow *win, IOSurfaceRef ioSurface, const QSize &size)
{
diff --git a/src/core/compositor/native_skia_output_device_metal.cpp b/src/core/compositor/native_skia_output_device_metal.cpp
index 95ed02779..a9d6e4fd5 100644
--- a/src/core/compositor/native_skia_output_device_metal.cpp
+++ b/src/core/compositor/native_skia_output_device_metal.cpp
@@ -4,6 +4,7 @@
#include "native_skia_output_device_metal.h"
#include <QtQuick/qquickwindow.h>
+#include <QtQuick/qsgtexture.h>
namespace QtWebEngineCore {
@@ -28,6 +29,7 @@ NativeSkiaOutputDeviceMetal::~NativeSkiaOutputDeviceMetal() { }
QSGTexture *makeMetalTexture(QQuickWindow *win, IOSurfaceRef ioSurface, uint ioSurfacePlane,
const QSize &size, QQuickWindow::CreateTextureOptions texOpts);
+void releaseMetalTexture(void *texture);
QSGTexture *NativeSkiaOutputDeviceMetal::texture(QQuickWindow *win, uint32_t textureOptions)
{
@@ -40,8 +42,25 @@ QSGTexture *NativeSkiaOutputDeviceMetal::texture(QQuickWindow *win, uint32_t tex
return nullptr;
}
+ // This is a workaround to not to release metal texture too early.
+ // In RHI, QMetalTexture wraps MTLTexture. QMetalTexture seems to be only destructed after the
+ // next MTLTexture is imported. The "old" MTLTexture can be still pontentially used by RHI
+ // while QMetalTexture is not destructed. Metal Validation Layer also warns about it.
+ // Delay releasing MTLTexture after the next one is presented.
+ if (m_currentMetalTexture) {
+ m_frontBuffer->textureCleanupCallback = [texture = m_currentMetalTexture]() {
+ releaseMetalTexture(texture);
+ };
+ m_currentMetalTexture = nullptr;
+ }
+
QQuickWindow::CreateTextureOptions texOpts(textureOptions);
- return makeMetalTexture(win, ioSurface.release(), /* plane */ 0, size(), texOpts);
+ QSGTexture *qsgTexture = makeMetalTexture(win, ioSurface.get(), /* plane */ 0, size(), texOpts);
+
+ auto ni = qsgTexture->nativeInterface<QNativeInterface::QSGMetalTexture>();
+ m_currentMetalTexture = ni->nativeTexture();
+
+ return qsgTexture;
}
} // namespace QtWebEngineCore
diff --git a/src/core/compositor/native_skia_output_device_metal.h b/src/core/compositor/native_skia_output_device_metal.h
index e61665fb5..8e8d0fab8 100644
--- a/src/core/compositor/native_skia_output_device_metal.h
+++ b/src/core/compositor/native_skia_output_device_metal.h
@@ -21,6 +21,9 @@ public:
// Overridden from Compositor:
QSGTexture *texture(QQuickWindow *win, uint32_t textureOptions) override;
+
+private:
+ void *m_currentMetalTexture = nullptr;
};
} // namespace QtWebEngineCore
diff --git a/src/core/compositor/native_skia_output_device_opengl.cpp b/src/core/compositor/native_skia_output_device_opengl.cpp
index ea4c0c500..058573b9e 100644
--- a/src/core/compositor/native_skia_output_device_opengl.cpp
+++ b/src/core/compositor/native_skia_output_device_opengl.cpp
@@ -68,7 +68,7 @@ QSGTexture *NativeSkiaOutputDeviceOpenGL::texture(QQuickWindow *win, uint32_t te
// TODO: Add WGL support over ANGLE.
QT_NOT_YET_IMPLEMENTED
#elif defined(Q_OS_MACOS)
- uint32_t glTexture = makeCGLTexture(win, ioSurface.release(), size());
+ uint32_t glTexture = makeCGLTexture(win, ioSurface.get(), size());
texture = QNativeInterface::QSGOpenGLTexture::fromNative(glTexture, win, size(), texOpts);
m_frontBuffer->textureCleanupCallback = [glTexture]() {
diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp
index 53c2caa2d..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);
}
@@ -827,7 +827,8 @@ static bool navigationThrottleCallback(content::NavigationHandle *handle)
client->navigationRequested(pageTransitionToNavigationType(transition_type),
toQt(handle->GetURL()),
navigationAccepted,
- handle->IsInPrimaryMainFrame());
+ handle->IsInPrimaryMainFrame(),
+ handle->IsFormSubmission());
return !navigationAccepted;
}
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/favicon_driver_qt.cpp b/src/core/favicon_driver_qt.cpp
index bb4a734b4..e710d5358 100644
--- a/src/core/favicon_driver_qt.cpp
+++ b/src/core/favicon_driver_qt.cpp
@@ -263,13 +263,6 @@ void FaviconDriverQt::DidUpdateFaviconURL(
if (!entry)
return;
- // We update |m_faviconUrls| even if the list is believed to be partial
- // (checked below), because callers of our getter favicon_urls() expect so.
- std::vector<blink::mojom::FaviconURLPtr> faviconUrls;
- for (const auto &candidate : candidates)
- faviconUrls.push_back(candidate.Clone());
- m_faviconUrls = std::move(faviconUrls);
-
if (!rfh->IsDocumentOnLoadCompletedInMainFrame())
return;
diff --git a/src/core/favicon_driver_qt.h b/src/core/favicon_driver_qt.h
index 96bd682a2..6dc377969 100644
--- a/src/core/favicon_driver_qt.h
+++ b/src/core/favicon_driver_qt.h
@@ -137,9 +137,6 @@ private:
GURL m_bypassCachePageURL;
- // nullopt until the actual list is reported via DidUpdateFaviconURL().
- absl::optional<std::vector<blink::mojom::FaviconURLPtr>> m_faviconUrls;
-
int m_completedHandlersCount = 0;
FaviconStatusQt m_latestFavicon;
diff --git a/src/core/native_web_keyboard_event_qt_mac.mm b/src/core/native_web_keyboard_event_qt_mac.mm
index 57c575699..0f5b12db4 100644
--- a/src/core/native_web_keyboard_event_qt_mac.mm
+++ b/src/core/native_web_keyboard_event_qt_mac.mm
@@ -47,7 +47,7 @@ base::apple::OwnedNSEvent ToNativeEvent(QKeyEvent *keyEvent)
return base::apple::OwnedNSEvent([NSEvent
keyEventWithType:type
location:NSZeroPoint
- modifierFlags:keyEvent->nativeModifiers()
+ modifierFlags:QAppleKeyMapper::toCocoaModifiers(keyEvent->modifiers())
timestamp:keyEvent->timestamp() / 1000
windowNumber:0
context:nil
diff --git a/src/core/ozone/gl_context_qt.cpp b/src/core/ozone/gl_context_qt.cpp
index 608d5c21a..2e358c0fb 100644
--- a/src/core/ozone/gl_context_qt.cpp
+++ b/src/core/ozone/gl_context_qt.cpp
@@ -175,11 +175,11 @@ bool GLContextHelper::isCreateContextRobustnessSupported()
return contextHelper->m_robustness;
}
-#if defined(USE_OZONE)
+#if QT_CONFIG(opengl) && defined(USE_OZONE)
class ScopedGLContext
{
public:
- ScopedGLContext()
+ ScopedGLContext(QOffscreenSurface *surface)
: m_context(new QOpenGLContext())
, m_previousContext(gl::GLContext::GetCurrent())
, m_previousSurface(gl::GLSurface::GetCurrent())
@@ -189,10 +189,7 @@ public:
return;
}
- QOffscreenSurface *surface = new QOffscreenSurface(m_context->screen(), m_context.get());
- surface->create();
Q_ASSERT(surface->isValid());
-
if (!m_context->makeCurrent(surface)) {
qWarning("Failed to make OpenGL context current.");
return;
@@ -269,7 +266,8 @@ EGLHelper *EGLHelper::instance()
return &eglHelper;
}
-EGLHelper::EGLHelper() : m_functions(new EGLHelper::EGLFunctions())
+EGLHelper::EGLHelper()
+ : m_functions(new EGLHelper::EGLFunctions()), m_offscreenSurface(new QOffscreenSurface())
{
const char *extensions = m_functions->eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
if (!extensions) {
@@ -288,6 +286,9 @@ EGLHelper::EGLHelper() : m_functions(new EGLHelper::EGLFunctions())
return;
}
+ Q_ASSERT(QThread::currentThread() == qApp->thread());
+ m_offscreenSurface->create();
+
const char *displayExtensions = m_functions->eglQueryString(eglDisplay, EGL_EXTENSIONS);
m_isDmaBufSupported = strstr(displayExtensions, "EGL_EXT_image_dma_buf_import")
&& strstr(displayExtensions, "EGL_EXT_image_dma_buf_import_modifiers")
@@ -306,6 +307,16 @@ EGLHelper::EGLHelper() : m_functions(new EGLHelper::EGLFunctions())
const char *displayVendor = m_functions->eglQueryString(eglDisplay, EGL_VENDOR);
m_isDmaBufSupported = !strstr(displayVendor, "NVIDIA");
}
+
+ // Try to create dma-buf.
+ if (m_isDmaBufSupported) {
+ int fd = -1;
+ queryDmaBuf(2, 2, &fd, nullptr, nullptr, nullptr);
+ if (fd == -1)
+ m_isDmaBufSupported = false;
+ else
+ close(fd);
+ }
}
void EGLHelper::queryDmaBuf(const int width, const int height, int *fd, int *stride, int *offset,
@@ -314,7 +325,7 @@ void EGLHelper::queryDmaBuf(const int width, const int height, int *fd, int *str
if (!m_isDmaBufSupported)
return;
- ScopedGLContext context;
+ ScopedGLContext context(m_offscreenSurface.get());
if (!context.isValid())
return;
@@ -350,20 +361,9 @@ void EGLHelper::queryDmaBuf(const int width, const int height, int *fd, int *str
bool EGLHelper::isDmaBufSupported()
{
- if (!m_isDmaBufSupported)
- return false;
-
- int fd = -1;
- queryDmaBuf(2, 2, &fd, nullptr, nullptr, nullptr);
- if (fd == -1) {
- m_isDmaBufSupported = false;
- return false;
- }
-
- close(fd);
- return true;
+ return m_isDmaBufSupported;
}
-#endif // defined(USE_OZONE)
+#endif // QT_CONFIG(opengl) && defined(USE_OZONE)
QT_END_NAMESPACE
diff --git a/src/core/ozone/gl_context_qt.h b/src/core/ozone/gl_context_qt.h
index c1524abf2..41c6a5f0c 100644
--- a/src/core/ozone/gl_context_qt.h
+++ b/src/core/ozone/gl_context_qt.h
@@ -6,10 +6,11 @@
#include <QObject>
#include <QtCore/qscopedpointer.h>
+#include <QtGui/qtgui-config.h>
#include "ui/gl/gl_context.h"
-#if defined(USE_OZONE)
+#if QT_CONFIG(opengl) && defined(USE_OZONE)
#include <EGL/egl.h>
#include <EGL/eglext.h>
#endif
@@ -20,6 +21,8 @@ class GLSurface;
QT_BEGIN_NAMESPACE
+class QOffscreenSurface;
+
class GLContextHelper : public QObject {
Q_OBJECT
public:
@@ -45,7 +48,7 @@ private:
bool m_robustness = false;
};
-#if defined(USE_OZONE)
+#if QT_CONFIG(opengl) && defined(USE_OZONE)
#undef eglCreateImage
#undef eglDestroyImage
#undef eglExportDMABUFImageMESA
@@ -79,9 +82,10 @@ private:
EGLHelper();
QScopedPointer<EGLFunctions> m_functions;
+ QScopedPointer<QOffscreenSurface> m_offscreenSurface;
bool m_isDmaBufSupported = false;
};
-#endif // defined(USE_OZONE)
+#endif // QT_CONFIG(opengl) && defined(USE_OZONE)
QT_END_NAMESPACE
diff --git a/src/core/ozone/ozone_platform_qt.cpp b/src/core/ozone/ozone_platform_qt.cpp
index e8547fa87..623cf43cf 100644
--- a/src/core/ozone/ozone_platform_qt.cpp
+++ b/src/core/ozone/ozone_platform_qt.cpp
@@ -73,7 +73,8 @@ public:
if (has_initialized_gpu()) {
// This property is set when the GetPlatformRuntimeProperties is
// called on the gpu process side.
- properties.supports_native_pixmaps = surface_factory_ozone_->SupportsNativePixmaps();
+ DCHECK(m_supportsNativePixmaps);
+ properties.supports_native_pixmaps = m_supportsNativePixmaps.value();
}
return properties;
}
@@ -85,6 +86,7 @@ private:
void InitScreen(ui::PlatformScreen *) override {}
+ absl::optional<bool> m_supportsNativePixmaps;
std::unique_ptr<QtWebEngineCore::SurfaceFactoryQt> surface_factory_ozone_;
std::unique_ptr<CursorFactory> cursor_factory_;
@@ -109,9 +111,10 @@ const ui::OzonePlatform::PlatformProperties &OzonePlatformQt::GetPlatformPropert
static base::NoDestructor<ui::OzonePlatform::PlatformProperties> properties;
static bool initialized = false;
if (!initialized) {
- properties->fetch_buffer_formats_for_gmb_on_gpu = true;
+ DCHECK(m_supportsNativePixmaps);
+ properties->fetch_buffer_formats_for_gmb_on_gpu = m_supportsNativePixmaps.value();
#if BUILDFLAG(USE_VAAPI)
- properties->supports_vaapi = true;
+ properties->supports_vaapi = m_supportsNativePixmaps.value();
#endif
initialized = true;
}
@@ -227,6 +230,7 @@ bool OzonePlatformQt::InitializeUI(const ui::OzonePlatform::InitParams &)
input_controller_ = CreateStubInputController();
cursor_factory_.reset(new BitmapCursorFactory());
gpu_platform_support_host_.reset(ui::CreateStubGpuPlatformSupportHost());
+ m_supportsNativePixmaps = QtWebEngineCore::SurfaceFactoryQt::SupportsNativePixmaps();
return true;
}
diff --git a/src/core/ozone/surface_factory_qt.cpp b/src/core/ozone/surface_factory_qt.cpp
index 374f870e2..2d311a02a 100644
--- a/src/core/ozone/surface_factory_qt.cpp
+++ b/src/core/ozone/surface_factory_qt.cpp
@@ -16,6 +16,7 @@
#include "ui/ozone/buildflags.h"
#include <QDebug>
+#include <QtGui/qtgui-config.h>
#if BUILDFLAG(OZONE_PLATFORM_X11)
#include "ozone/gl_ozone_glx_qt.h"
@@ -91,7 +92,10 @@ scoped_refptr<gfx::NativePixmap> SurfaceFactoryQt::CreateNativePixmap(
gfx::BufferUsage usage,
absl::optional<gfx::Size> framebuffer_size)
{
- Q_ASSERT(SupportsNativePixmaps());
+ if (!SupportsNativePixmaps())
+ return nullptr;
+
+#if QT_CONFIG(opengl)
if (framebuffer_size && !gfx::Rect(size).Contains(gfx::Rect(*framebuffer_size)))
return nullptr;
@@ -125,6 +129,9 @@ scoped_refptr<gfx::NativePixmap> SurfaceFactoryQt::CreateNativePixmap(
}
return base::MakeRefCounted<gfx::NativePixmapDmaBuf>(size, format, std::move(handle));
+#else
+ return nullptr;
+#endif // QT_CONFIG(opengl)
}
void SurfaceFactoryQt::CreateNativePixmapAsync(
@@ -135,7 +142,11 @@ void SurfaceFactoryQt::CreateNativePixmapAsync(
gfx::BufferUsage usage,
NativePixmapCallback callback)
{
- Q_ASSERT(SupportsNativePixmaps());
+ if (!SupportsNativePixmaps()) {
+ std::move(callback).Run(nullptr);
+ return;
+ }
+
// CreateNativePixmap is non-blocking operation. Thus, it is safe to call it
// and return the result with the provided callback.
std::move(callback).Run(CreateNativePixmap(widget, device_queue, size, format, usage));
@@ -148,7 +159,10 @@ SurfaceFactoryQt::CreateNativePixmapFromHandle(
gfx::BufferFormat format,
gfx::NativePixmapHandle handle)
{
- Q_ASSERT(SupportsNativePixmaps());
+ if (!SupportsNativePixmaps())
+ return nullptr;
+
+#if QT_CONFIG(opengl)
gfx::NativePixmapHandle bufferHandle;
#if BUILDFLAG(OZONE_PLATFORM_X11)
@@ -212,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];
@@ -220,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));
}
@@ -228,17 +242,22 @@ SurfaceFactoryQt::CreateNativePixmapFromHandle(
}
return base::MakeRefCounted<gfx::NativePixmapDmaBuf>(size, format, std::move(bufferHandle));
+#else
+ return nullptr;
+#endif // QT_CONFIG(opengl)
}
-bool SurfaceFactoryQt::SupportsNativePixmaps() const
+bool SurfaceFactoryQt::SupportsNativePixmaps()
{
+#if QT_CONFIG(opengl)
#if BUILDFLAG(OZONE_PLATFORM_X11)
if (GLContextHelper::getGlxPlatformInterface())
return ui::GpuMemoryBufferSupportX11::GetInstance()->has_gbm_device();
-#endif
+#endif // BUILDFLAG(OZONE_PLATFORM_X11)
if (GLContextHelper::getEglPlatformInterface())
return EGLHelper::instance()->isDmaBufSupported();
+#endif // QT_CONFIG(opengl)
return false;
}
diff --git a/src/core/ozone/surface_factory_qt.h b/src/core/ozone/surface_factory_qt.h
index 07d7337ac..d69467a26 100644
--- a/src/core/ozone/surface_factory_qt.h
+++ b/src/core/ozone/surface_factory_qt.h
@@ -40,7 +40,7 @@ public:
gfx::BufferFormat format,
gfx::NativePixmapHandle handle) override;
- bool SupportsNativePixmaps() const;
+ static bool SupportsNativePixmaps();
private:
std::vector<gl::GLImplementationParts> m_impl;
diff --git a/src/core/render_view_context_menu_qt.h b/src/core/render_view_context_menu_qt.h
index 71901424c..1188f6cd4 100644
--- a/src/core/render_view_context_menu_qt.h
+++ b/src/core/render_view_context_menu_qt.h
@@ -15,7 +15,7 @@
#ifndef RENDER_VIEW_CONTEXT_MENU_QT_H
#define RENDER_VIEW_CONTEXT_MENU_QT_H
-#include "web_contents_adapter_client.h"
+#include "qtwebenginecoreglobal.h"
QT_FORWARD_DECLARE_CLASS(QWebEngineContextMenuRequest)
diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp
index 7ffeaaa5b..1140bf11a 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)
@@ -1039,36 +1038,50 @@ QAccessibleInterface *WebContentsAdapter::browserAccessible()
}
#endif // QT_CONFIG(accessibility)
-void WebContentsAdapter::runJavaScript(const QString &javaScript, quint32 worldId)
+void WebContentsAdapter::runJavaScript(const QString &javaScript, quint32 worldId,
+ const std::function<void(const QVariant &)> &callback)
{
- CHECK_INITIALIZED();
+ auto exit = [&] {
+ if (callback)
+ callback(QVariant());
+ };
+
+ if (!isInitialized())
+ return exit();
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;
+ return exit();
+ }
+
+ content::RenderFrameHost::JavaScriptResultCallback wrappedCallback = base::NullCallback();
+ if (callback) {
+ wrappedCallback = base::BindOnce(&callbackOnEvaluateJS, this, m_nextRequestId);
+ m_javaScriptCallbacks.insert(m_nextRequestId, callback);
+ ++m_nextRequestId;
}
if (worldId == 0)
- rfh->ExecuteJavaScript(toString16(javaScript), base::NullCallback());
+ rfh->ExecuteJavaScript(toString16(javaScript), std::move(wrappedCallback));
else
- rfh->ExecuteJavaScriptInIsolatedWorld(toString16(javaScript), base::NullCallback(), worldId);
+ rfh->ExecuteJavaScriptInIsolatedWorld(toString16(javaScript), std::move(wrappedCallback),
+ worldId);
}
-quint64 WebContentsAdapter::runJavaScriptCallbackResult(const QString &javaScript, quint32 worldId)
+void WebContentsAdapter::didRunJavaScript(quint64 requestId, const base::Value &result)
{
- CHECK_INITIALIZED(0);
- 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 0;
- }
- content::RenderFrameHost::JavaScriptResultCallback callback = base::BindOnce(&callbackOnEvaluateJS, m_adapterClient, m_nextRequestId);
- if (worldId == 0)
- rfh->ExecuteJavaScript(toString16(javaScript), std::move(callback));
- else
- rfh->ExecuteJavaScriptInIsolatedWorld(toString16(javaScript), std::move(callback), worldId);
- return m_nextRequestId++;
+ 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()
@@ -1812,6 +1825,80 @@ void WebContentsAdapter::changeTextDirection(bool leftToRight)
}
}
+quint64 WebContentsAdapter::mainFrameId() const
+{
+ CHECK_INITIALIZED(content::RenderFrameHost::kNoFrameTreeNodeId);
+ return static_cast<quint64>(m_webContents->GetPrimaryMainFrame()->GetFrameTreeNodeId());
+}
+
+#define CHECK_INITIALIZED_AND_VALID_FRAME(webengine_frame_id_variable, frame_tree_node_variable, \
+ return_value) \
+ CHECK_INITIALIZED(return_value); \
+ if (webengine_frame_id_variable == kInvalidFrameId) \
+ return return_value; \
+ auto *frame_tree_node_variable = content::FrameTreeNode::GloballyFindByID( \
+ static_cast<int>(webengine_frame_id_variable)); \
+ if (!frame_tree_node_variable) \
+ return return_value
+
+QString WebContentsAdapter::frameName(quint64 id) const
+{
+ CHECK_INITIALIZED_AND_VALID_FRAME(id, ftn, QString());
+ return QString::fromStdString(ftn->frame_name());
+}
+
+QString WebContentsAdapter::frameHtmlName(quint64 id) const
+{
+ CHECK_INITIALIZED_AND_VALID_FRAME(id, ftn, QString());
+ auto &maybeName = ftn->html_name();
+ return maybeName ? QString::fromStdString(*maybeName) : QString("");
+}
+
+QList<quint64> WebContentsAdapter::frameChildren(quint64 id) const
+{
+ CHECK_INITIALIZED_AND_VALID_FRAME(id, ftn, {});
+ QList<quint64> result;
+ size_t numChildren = ftn->child_count();
+ result.reserve(numChildren);
+ for (size_t i = 0; i < numChildren; ++i) {
+ result.push_back(ftn->child_at(i)->frame_tree_node_id());
+ }
+ return result;
+}
+
+QUrl WebContentsAdapter::frameUrl(quint64 id) const
+{
+ CHECK_INITIALIZED_AND_VALID_FRAME(id, ftn, QUrl());
+ return toQt(ftn->current_url());
+}
+
+QSizeF WebContentsAdapter::frameSize(quint64 id) const
+{
+ CHECK_INITIALIZED_AND_VALID_FRAME(id, ftn, QSizeF());
+ auto *rfh = ftn->current_frame_host();
+ Q_ASSERT(rfh);
+ auto maybeSize = rfh->GetFrameSize();
+ return maybeSize ? toQt(*maybeSize) : QSizeF();
+}
+
+std::optional<quint64> WebContentsAdapter::findFrameIdByName(const QString &name) const
+{
+ CHECK_INITIALIZED({});
+ auto *ftn = content::FrameTreeNode::From(m_webContents->GetPrimaryMainFrame());
+ Q_ASSERT(ftn);
+ if (auto *foundFtn = ftn->frame_tree().FindByName(name.toStdString()))
+ return foundFtn->frame_tree_node_id();
+ return {};
+}
+
+bool WebContentsAdapter::hasFrame(quint64 id) const
+{
+ CHECK_INITIALIZED_AND_VALID_FRAME(id, ftn, false);
+ auto *rfh = ftn->current_frame_host();
+ Q_ASSERT(rfh);
+ return content::WebContents::FromRenderFrameHost(rfh) == m_webContents.get();
+}
+
WebContentsAdapterClient::RenderProcessTerminationStatus
WebContentsAdapterClient::renderProcessExitStatus(int terminationStatus) {
auto status = WebContentsAdapterClient::RenderProcessTerminationStatus(-1);
diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h
index 62c3f087c..0c46e7d81 100644
--- a/src/core/web_contents_adapter.h
+++ b/src/core/web_contents_adapter.h
@@ -16,17 +16,22 @@
#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>
#include <QtWebEngineCore/qwebenginecontextmenurequest.h>
#include <QtWebEngineCore/qwebenginehttprequest.h>
+#include <QtWebEngineCore/qwebengineframe.h>
#include "web_contents_adapter_client.h"
+#include <functional>
#include <memory>
+#include <optional>
namespace blink {
namespace web_pref {
@@ -34,6 +39,10 @@ struct WebPreferences;
}
}
+namespace base {
+class Value;
+}
+
namespace content {
class WebContents;
class SiteInstance;
@@ -62,6 +71,9 @@ class WebChannelIPCTransportHost;
class Q_WEBENGINECORE_EXPORT WebContentsAdapter : public QEnableSharedFromThis<WebContentsAdapter> {
public:
+ // Sentinel to indicate a frame doesn't exist, for example with `findFrameByName`
+ static constexpr quint64 kInvalidFrameId = -3;
+
static QSharedPointer<WebContentsAdapter> createFromSerializedNavigationHistory(QDataStream &input, WebContentsAdapterClient *adapterClient);
WebContentsAdapter();
WebContentsAdapter(std::unique_ptr<content::WebContents> webContents);
@@ -124,8 +136,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,
+ 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);
@@ -204,6 +218,15 @@ public:
void resetTouchSelectionController();
void changeTextDirection(bool leftToRight);
+ quint64 mainFrameId() const;
+ QString frameName(quint64 id) const;
+ QString frameHtmlName(quint64 id) const;
+ QList<quint64> frameChildren(quint64 id) const;
+ QUrl frameUrl(quint64 id) const;
+ QSizeF frameSize(quint64 id) const;
+ std::optional<quint64> findFrameIdByName(const QString &name) const;
+ bool hasFrame(quint64 id) const;
+
// meant to be used within WebEngineCore only
void initialize(content::SiteInstance *site);
content::WebContents *webContents() const;
@@ -241,6 +264,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 1a1474644..bb350bba2 100644
--- a/src/core/web_contents_adapter_client.h
+++ b/src/core/web_contents_adapter_client.h
@@ -169,13 +169,14 @@ public:
virtual void windowCloseRejected() = 0;
virtual void contextMenuRequested(QWebEngineContextMenuRequest *request) = 0;
virtual void desktopMediaRequested(DesktopMediaController *) = 0;
- virtual void navigationRequested(int navigationType, const QUrl &url, bool &accepted, bool isMainFrame) = 0;
+ virtual void navigationRequested(int navigationType, const QUrl &url, bool &accepted, bool isMainFrame, bool hasFormData) = 0;
virtual void requestFullScreenMode(const QUrl &origin, bool fullscreen) = 0;
virtual bool isFullScreenMode() const = 0;
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,
+ 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/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp
index 194274fcb..4df73fb69 100644
--- a/src/core/web_contents_delegate_qt.cpp
+++ b/src/core/web_contents_delegate_qt.cpp
@@ -760,7 +760,7 @@ void WebContentsDelegateQt::launchExternalURL(const QUrl &url, ui::PageTransitio
}
if (navigationAllowedByPolicy) {
- m_viewClient->navigationRequested(pageTransitionToNavigationType(page_transition), url, navigationRequestAccepted, is_main_frame);
+ m_viewClient->navigationRequested(pageTransitionToNavigationType(page_transition), url, navigationRequestAccepted, is_main_frame, false);
#if QT_CONFIG(desktopservices)
if (navigationRequestAccepted)
QDesktopServices::openUrl(url);
diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp
index 2402e9570..faf9bd542 100644
--- a/src/core/web_engine_context.cpp
+++ b/src/core/web_engine_context.cpp
@@ -3,6 +3,7 @@
#include "web_engine_context.h"
+#include <map>
#include <math.h>
#include <QtGui/private/qrhi_p.h>
@@ -105,10 +106,6 @@
#include <QGuiApplication>
#include <QMutex>
#include <QOffscreenSurface>
-#if QT_CONFIG(opengl)
-#include <QOpenGLContext>
-#include <qopenglcontext_platform.h>
-#endif
#include <QQuickWindow>
#include <QRegularExpression>
#include <QStringList>
@@ -120,6 +117,9 @@
#include <QLoggingCategory>
#if QT_CONFIG(opengl)
+#include <QOpenGLContext>
+#include <qopenglcontext_platform.h>
+
QT_BEGIN_NAMESPACE
Q_GUI_EXPORT QOpenGLContext *qt_gl_global_share_context();
QT_END_NAMESPACE
@@ -132,7 +132,188 @@ namespace QtWebEngineCore {
Q_LOGGING_CATEGORY(webEngineContextLog, "qt.webenginecontext")
+class GPUInfo
+{
+public:
+ enum Vendor {
+ Unknown = -1,
+ AMD,
+ Apple,
+ ARM,
+ Google,
+ ImgTec,
+ Intel,
+ Microsoft,
+ Mesa,
+ Nvidia,
+ Qualcomm,
+ Samsung
+ };
+
+ static GPUInfo *instance()
+ {
+ static GPUInfo instance;
+ return &instance;
+ }
+
+ static Vendor vendorIdToVendor(quint64 vendorId)
+ {
+ // clang-format off
+ // Based on //third_party/dawn/src/dawn/gpu_info.json
+ static const std::map<quint64, Vendor> vendorIdMap = {
+ {0x0, Unknown},
+ {0x1002, AMD},
+ {0x106B, Apple},
+ {0x13B5, ARM},
+ {0x1AE0, Google},
+ {0x1010, ImgTec},
+ {0x8086, Intel},
+ {0x10005, Mesa},
+ {0x1414, Microsoft},
+ {0x10DE, Nvidia},
+ {0x5143, Qualcomm},
+ {0x144D, Samsung}
+ };
+ // clang-format on
+
+ auto it = vendorIdMap.find(vendorId);
+ if (it != vendorIdMap.end())
+ return it->second;
+
+ qWarning() << "Unknown Vendor ID:" << QString("0x%1").arg(vendorId, 0, 16);
+ return Unknown;
+ }
+
+ static Vendor deviceNameToVendor(QString deviceName)
+ {
+ // TODO: Test and add more vendors to the list.
+ if (deviceName.contains(QLatin1String("AMD"), Qt::CaseInsensitive))
+ return AMD;
+ if (deviceName.contains(QLatin1String("Intel"), Qt::CaseInsensitive))
+ return Intel;
+ if (deviceName.contains(QLatin1String("Nvidia"), Qt::CaseInsensitive))
+ return Nvidia;
+
+#if defined(USE_OZONE)
+ if (deviceName.contains(QLatin1String("Mesa llvmpipe")))
+ return Mesa;
+#endif
+
+#if defined(Q_OS_MACOS)
+ if (deviceName.contains(QLatin1String("Apple")))
+ return Apple;
+#endif
+
+ return Unknown;
+ }
+
+ static std::string vendorToString(Vendor vendor)
+ {
+ // clang-format off
+ static const std::map<Vendor, std::string> vendorNameMap = {
+ {Unknown, "Unknown"},
+ {AMD, "AMD"},
+ {Apple, "Apple"},
+ {ARM, "ARM"},
+ {Google, "Google"},
+ {ImgTec, "Img Tec"},
+ {Intel, "Intel"},
+ {Mesa, "Mesa"},
+ {Microsoft, "Microsoft"},
+ {Nvidia, "Nvidia"},
+ {Qualcomm, "Qualcomm"},
+ {Samsung, "Samsung"}
+ };
+ // clang-format on
+
+ auto it = vendorNameMap.find(vendor);
+ if (it != vendorNameMap.end())
+ return it->second;
+
+ Q_UNREACHABLE();
+ return "Unknown";
+ }
+
+ Vendor vendor() const { return m_vendor; }
+ QString getAdapterLuid() const { return m_adapterLuid; }
+
+private:
+ GPUInfo()
+ {
+#if defined(Q_OS_WIN)
+ {
+ static const bool preferSoftwareDevice =
+ qEnvironmentVariableIntValue("QSG_RHI_PREFER_SOFTWARE_RENDERER");
+ QRhiD3D11InitParams params;
+ QRhi::Flags flags;
+ if (preferSoftwareDevice) {
+ flags |= QRhi::PreferSoftwareRenderer;
+ }
+ QScopedPointer<QRhi> d3d11Rhi(QRhi::create(QRhi::D3D11, &params, flags, nullptr));
+ // mimic what QSGRhiSupport and QBackingStoreRhi does
+ if (!d3d11Rhi && !preferSoftwareDevice) {
+ flags |= QRhi::PreferSoftwareRenderer;
+ d3d11Rhi.reset(QRhi::create(QRhi::D3D11, &params, flags, nullptr));
+ }
+ if (d3d11Rhi) {
+ m_vendor = vendorIdToVendor(d3d11Rhi->driverInfo().vendorId);
+
+ const QRhiD3D11NativeHandles *handles =
+ static_cast<const QRhiD3D11NativeHandles *>(d3d11Rhi->nativeHandles());
+ Q_ASSERT(handles);
+ m_adapterLuid =
+ QString("%1,%2").arg(handles->adapterLuidHigh).arg(handles->adapterLuidLow);
+ }
+ }
+#elif defined(Q_OS_MACOS)
+ {
+ QRhiMetalInitParams params;
+ QScopedPointer<QRhi> metalRhi(
+ QRhi::create(QRhi::Metal, &params, QRhi::Flags(), nullptr));
+ if (metalRhi)
+ m_vendor = deviceNameToVendor(metalRhi->driverInfo().deviceName);
+ }
+#endif
+
#if QT_CONFIG(opengl)
+ if (m_vendor == Unknown) {
+ QRhiGles2InitParams params;
+ params.fallbackSurface = QRhiGles2InitParams::newFallbackSurface();
+ QScopedPointer<QRhi> glRhi(
+ QRhi::create(QRhi::OpenGLES2, &params, QRhi::Flags(), nullptr));
+ if (glRhi)
+ m_vendor = deviceNameToVendor(glRhi->driverInfo().deviceName);
+ }
+#endif
+
+#if QT_CONFIG(webengine_vulkan)
+ if (m_vendor == Unknown) {
+ QVulkanInstance vulkanInstance;
+ vulkanInstance.setApiVersion(QVersionNumber(1, 1));
+ if (vulkanInstance.create()) {
+ QRhiVulkanInitParams params;
+ params.inst = &vulkanInstance;
+ QScopedPointer<QRhi> vulkanRhi(
+ QRhi::create(QRhi::Vulkan, &params, QRhi::Flags(), nullptr));
+ if (vulkanRhi) {
+ // TODO: The primary GPU is not necessarily the one which is connected to the
+ // display in case of a Multi-GPU setup on Linux. This can be workarounded by
+ // installing the Mesa's Device Selection Layer,
+ // see https://www.phoronix.com/news/Mesa-20.1-Vulkan-Dev-Selection
+ // Try to detect this case and at least warn about it.
+ m_vendor = vendorIdToVendor(vulkanRhi->driverInfo().vendorId);
+ }
+ }
+ }
+#endif
+
+ if (m_vendor == Unknown)
+ qWarning("Unable to detect GPU vendor.");
+ }
+
+ Vendor m_vendor = Unknown;
+ QString m_adapterLuid;
+};
static bool usingSupportedSGBackend()
{
@@ -162,6 +343,7 @@ static bool usingSupportedSGBackend()
return device.isEmpty() || device == QLatin1String("rhi");
}
+#if QT_CONFIG(opengl)
bool usingSoftwareDynamicGL()
{
const char openGlVar[] = "QT_OPENGL";
@@ -190,14 +372,12 @@ static bool openGLPlatformSupport()
QPlatformIntegration::OpenGL);
}
-static const char *getGLType(bool enableGLSoftwareRendering, bool disableGpu)
+static std::string getGLType(bool enableGLSoftwareRendering, bool disableGpu)
{
- const char *glType = gl::kGLImplementationDisabledName;
const bool tryGL =
usingSupportedSGBackend() && !usingSoftwareDynamicGL() && openGLPlatformSupport();
-
if (disableGpu || (!tryGL && !enableGLSoftwareRendering))
- return glType;
+ return gl::kGLImplementationDisabledName;
#if defined(Q_OS_MACOS)
return gl::kGLImplementationANGLEName;
@@ -212,7 +392,7 @@ static const char *getGLType(bool enableGLSoftwareRendering, bool disableGpu)
if (!qt_gl_global_share_context() || !qt_gl_global_share_context()->isValid()) {
qWarning("WebEngineContext is used before QtWebEngineQuick::initialize() or OpenGL context "
"creation failed.");
- return glType;
+ return gl::kGLImplementationDisabledName;
}
const QSurfaceFormat sharedFormat = qt_gl_global_share_context()->format();
@@ -220,17 +400,13 @@ static const char *getGLType(bool enableGLSoftwareRendering, bool disableGpu)
switch (sharedFormat.renderableType()) {
case QSurfaceFormat::OpenGL:
if (sharedFormat.profile() == QSurfaceFormat::CoreProfile) {
- glType = gl::kGLImplementationDesktopName;
qWarning("An OpenGL Core Profile was requested, but it is not supported "
"on the current platform. Falling back to a non-Core profile. "
"Note that this might cause rendering issues.");
- } else {
- glType = gl::kGLImplementationDesktopName;
}
- break;
+ return gl::kGLImplementationDesktopName;
case QSurfaceFormat::OpenGLES:
- glType = gl::kGLImplementationEGLName;
- break;
+ return gl::kGLImplementationEGLName;
case QSurfaceFormat::OpenVG:
case QSurfaceFormat::DefaultRenderableType:
default:
@@ -238,11 +414,12 @@ static const char *getGLType(bool enableGLSoftwareRendering, bool disableGpu)
qWarning("Unsupported rendering surface format. Please open bug report at "
"https://bugreports.qt.io");
}
- return glType;
+
+ return gl::kGLImplementationDisabledName;
#endif // defined(Q_OS_MACOS)
}
#else
-static const char *getGLType(bool /*enableGLSoftwareRendering*/, bool disableGpu)
+static std::string getGLType(bool /*enableGLSoftwareRendering*/, bool disableGpu)
{
if (disableGpu)
return gl::kGLImplementationDisabledName;
@@ -258,30 +435,33 @@ static const char *getGLType(bool /*enableGLSoftwareRendering*/, bool disableGpu
}
#endif // QT_CONFIG(opengl)
+static std::string getVulkanType(base::CommandLine *cmd)
+{
+#if QT_CONFIG(webengine_vulkan)
+ if (cmd->HasSwitch(switches::kUseVulkan))
+ return cmd->GetSwitchValueASCII(switches::kUseVulkan);
+#endif
+
+ return "disabled";
+}
+
+static std::string getAngleType(const std::string &glType, base::CommandLine *cmd)
+{
+ if (glType == gl::kGLImplementationANGLEName) {
+ if (cmd->HasSwitch(switches::kUseANGLE))
+ return cmd->GetSwitchValueASCII(switches::kUseANGLE);
+
#if defined(Q_OS_WIN)
-static QString getAdapterLuid() {
- static const bool preferSoftwareDevice = qEnvironmentVariableIntValue("QSG_RHI_PREFER_SOFTWARE_RENDERER");
- QRhiD3D11InitParams rhiParams;
- QRhi::Flags flags;
- if (preferSoftwareDevice) {
- flags |= QRhi::PreferSoftwareRenderer;
- }
- QScopedPointer<QRhi> rhi(QRhi::create(QRhi::D3D11,&rhiParams,flags,nullptr));
- // mimic what QSGRhiSupport and QBackingStoreRhi does
- if (!rhi && !preferSoftwareDevice) {
- flags |= QRhi::PreferSoftwareRenderer;
- rhi.reset(QRhi::create(QRhi::D3D11, &rhiParams, flags));
- }
- if (rhi) {
- const QRhiD3D11NativeHandles *handles =
- static_cast<const QRhiD3D11NativeHandles *>(rhi->nativeHandles());
- Q_ASSERT(handles);
- return QString("%1,%2").arg(handles->adapterLuidHigh).arg(handles->adapterLuidLow);
- } else {
- return QString();
+ return gl::kANGLEImplementationD3D11Name;
+#elif defined(Q_OS_MACOS)
+ return gl::kANGLEImplementationMetalName;
+#else
+ return gl::kANGLEImplementationDefaultName;
+#endif
}
+
+ return "disabled";
}
-#endif
#if QT_CONFIG(webengine_pepper_plugins)
void dummyGetPluginCallback(const std::vector<content::WebPluginInfo>&)
@@ -289,43 +469,57 @@ void dummyGetPluginCallback(const std::vector<content::WebPluginInfo>&)
}
#endif
-static void logContext(const char *glType, base::CommandLine *cmd)
+static void logContext(const std::string &glType, base::CommandLine *cmd)
{
if (Q_UNLIKELY(webEngineContextLog().isDebugEnabled())) {
- const base::CommandLine::SwitchMap switch_map = cmd->GetSwitches();
- QStringList params;
- for (const auto &pair : switch_map)
- params << " * " << toQt(pair.first)
- << toQt(pair.second) << "\n";
+ QStringList log;
+ log << "\n";
+
+ log << "Chromium GL Backend:" << glType.c_str() << "\n";
+ log << "Chromium ANGLE Backend:" << getAngleType(glType, cmd).c_str() << "\n";
+ log << "Chromium Vulkan Backend:" << getVulkanType(cmd).c_str() << "\n";
+ log << "\n";
+
+ log << "QSG RHI Backend:" << QSGRhiSupport::instance()->rhiBackendName() << "\n";
+ log << "QSG RHI Backend Supported:" << (usingSupportedSGBackend() ? "yes" : "no") << "\n";
+ log << "GPU Vendor:" << GPUInfo::vendorToString(GPUInfo::instance()->vendor()).c_str();
+ log << "\n";
+
#if QT_CONFIG(opengl)
- const QSurfaceFormat sharedFormat = qt_gl_global_share_context() ? qt_gl_global_share_context()->format() : QSurfaceFormat::defaultFormat();
- const auto profile = QMetaEnum::fromType<QSurfaceFormat::OpenGLContextProfile>().valueToKey(
- sharedFormat.profile());
- const auto type = QMetaEnum::fromType<QSurfaceFormat::RenderableType>().valueToKey(
- sharedFormat.renderableType());
- qCDebug(webEngineContextLog,
- "\n\nChromium GL Backend: %s\n"
- "Surface Type: %s\n"
- "Surface Profile: %s\n"
- "Surface Version: %d.%d\n"
- "QSG RHI Backend: %s\n"
- "Using Supported QSG Backend: %s\n"
- "Using Software Dynamic GL: %s\n"
- "Using Shared GL: %s\n"
- "Init Parameters:\n %s",
- glType, type, profile, sharedFormat.majorVersion(), sharedFormat.minorVersion(),
- qUtf8Printable(QSGRhiSupport::instance()->rhiBackendName()),
- usingSupportedSGBackend() ? "yes" : "no", usingSoftwareDynamicGL() ? "yes" : "no",
- qt_gl_global_share_context() ? "yes" : "no",
- qPrintable(params.join(" ")));
-#else
- qCDebug(webEngineContextLog,
- "\n\nChromium GL Backend: %s\n"
- "QSG RHI Backend: %s\n\n"
- "Init Parameters:\n %s",
- glType, qUtf8Printable(QSGRhiSupport::instance()->rhiBackendName()),
- qPrintable(params.join(" ")));
-#endif //QT_CONFIG(opengl)
+#if defined(USE_OZONE)
+ log << "Using GLX:" << (GLContextHelper::getGlxPlatformInterface() ? "yes" : "no") << "\n";
+ log << "Using EGL:" << (GLContextHelper::getEglPlatformInterface() ? "yes" : "no") << "\n";
+#endif
+ log << "Using Shared GL:" << (qt_gl_global_share_context() ? "yes" : "no") << "\n";
+ if (qt_gl_global_share_context()) {
+ log << "Using Software Dynamic GL:" << (usingSoftwareDynamicGL() ? "yes" : "no")
+ << "\n";
+
+ const QSurfaceFormat sharedFormat = qt_gl_global_share_context()
+ ? qt_gl_global_share_context()->format()
+ : QSurfaceFormat::defaultFormat();
+ const auto profile =
+ QMetaEnum::fromType<QSurfaceFormat::OpenGLContextProfile>().valueToKey(
+ sharedFormat.profile());
+ const auto type = QMetaEnum::fromType<QSurfaceFormat::RenderableType>().valueToKey(
+ sharedFormat.renderableType());
+ log << "Surface Type:" << type << "\n";
+ log << "Surface Profile:" << profile << "\n";
+ log << "Surface Version:"
+ << QString("%1.%2")
+ .arg(sharedFormat.majorVersion())
+ .arg(sharedFormat.minorVersion())
+ << "\n";
+ }
+ log << "\n";
+#endif // QT_CONFIG(opengl)
+
+ log << "Init Parameters:\n";
+ const base::CommandLine::SwitchMap switchMap = cmd->GetSwitches();
+ for (const auto &pair : switchMap)
+ log << " * " << toQt(pair.first) << toQt(pair.second) << "\n";
+
+ qCDebug(webEngineContextLog) << qPrintable(log.join(" "));
}
}
@@ -732,7 +926,13 @@ WebEngineContext::WebEngineContext()
parsedCommandLine->AppendSwitch(cc::switches::kDisableCompositedAntialiasing);
}
-#if QT_CONFIG(webengine_vulkan) && defined(USE_OZONE)
+#if defined(USE_OZONE)
+ if (GPUInfo::instance()->vendor() == GPUInfo::Nvidia) {
+ disableFeatures.push_back(media::kVaapiVideoDecodeLinux.name);
+ parsedCommandLine->AppendSwitch(switches::kDisableGpuMemoryBufferVideoFrames);
+ }
+
+#if QT_CONFIG(webengine_vulkan)
if (QQuickWindow::graphicsApi() == QSGRendererInterface::Vulkan) {
enableFeatures.push_back(features::kVulkan.name);
parsedCommandLine->AppendSwitchASCII(switches::kUseVulkan,
@@ -759,12 +959,13 @@ WebEngineContext::WebEngineContext()
qputenv(deviceExtensionsVar, requiredDeviceExtensions.join(';'));
}
}
-#endif // QT_CONFIG(webengine_vulkan) && defined(USE_OZONE)
+#endif // QT_CONFIG(webengine_vulkan)
+#endif // defined(USE_OZONE)
#if defined(Q_OS_WIN)
if (QQuickWindow::graphicsApi() == QSGRendererInterface::Direct3D11
|| QQuickWindow::graphicsApi() == QSGRendererInterface::Vulkan) {
- const QString luid = getAdapterLuid();
+ const QString luid = GPUInfo::instance()->getAdapterLuid();
if (!luid.isEmpty())
parsedCommandLine->AppendSwitchASCII(switches::kUseAdapterLuid, luid.toStdString());
}
@@ -779,9 +980,14 @@ WebEngineContext::WebEngineContext()
// performant, but at least provides WebGL support.
// TODO(miklocek), check if this still works with latest chromium
const bool disableGpu = parsedCommandLine->HasSwitch(switches::kDisableGpu);
- const char *glType = getGLType(enableGLSoftwareRendering, disableGpu);
+ std::string glType;
+ if (parsedCommandLine->HasSwitch(switches::kUseGL))
+ glType = parsedCommandLine->GetSwitchValueASCII(switches::kUseGL);
+ else {
+ glType = getGLType(enableGLSoftwareRendering, disableGpu);
+ parsedCommandLine->AppendSwitchASCII(switches::kUseGL, glType);
+ }
- parsedCommandLine->AppendSwitchASCII(switches::kUseGL, glType);
parsedCommandLine->AppendSwitch(switches::kInProcessGPU);
if (glType != gl::kGLImplementationDisabledName) {
@@ -791,7 +997,9 @@ WebEngineContext::WebEngineContext()
}
#if QT_CONFIG(opengl)
if (glType != gl::kGLImplementationANGLEName) {
- const QSurfaceFormat sharedFormat = QOpenGLContext::globalShareContext()->format();
+ QOpenGLContext *shareContext = QOpenGLContext::globalShareContext();
+ Q_ASSERT(shareContext);
+ const QSurfaceFormat sharedFormat = shareContext->format();
if (sharedFormat.profile() == QSurfaceFormat::CompatibilityProfile)
parsedCommandLine->AppendSwitch(switches::kCreateDefaultGLContext);
#if defined(Q_OS_WIN)
diff --git a/src/pdf/doc/snippets/pdfpageview.qml b/src/pdf/doc/snippets/pdfpageview.qml
new file mode 100644
index 000000000..5e233961a
--- /dev/null
+++ b/src/pdf/doc/snippets/pdfpageview.qml
@@ -0,0 +1,12 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [0]
+import QtQuick
+import QtQuick.Pdf
+
+PdfPageView {
+ document: PdfDocument { source: "my.pdf" }
+}
+//! [0]
+
diff --git a/src/pdfquick/PdfPageView.qml b/src/pdfquick/PdfPageView.qml
index 290570f2b..e1d97f57b 100644
--- a/src/pdfquick/PdfPageView.qml
+++ b/src/pdfquick/PdfPageView.qml
@@ -30,7 +30,7 @@ Rectangle {
A PdfDocument object with a valid \c source URL is required:
- \snippet multipageview.qml 0
+ \snippet pdfpageview.qml 0
*/
required property PdfDocument document
diff --git a/src/pdfwidgets/qpdfview.cpp b/src/pdfwidgets/qpdfview.cpp
index a67667fed..a19b77a7f 100644
--- a/src/pdfwidgets/qpdfview.cpp
+++ b/src/pdfwidgets/qpdfview.cpp
@@ -19,7 +19,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(qLcLink, "qt.pdf.links")
+Q_LOGGING_CATEGORY(qLcWLink, "qt.pdf.widgets.links")
//#define DEBUG_LINKS
static const QColor SearchResultHighlight("#80B0C4DE");
@@ -681,7 +681,7 @@ void QPdfView::mouseMoveEvent(QMouseEvent *event)
auto dest = d->m_linkModel.linkAt(posInPoints);
setCursor(dest.isValid() ? Qt::PointingHandCursor : Qt::ArrowCursor);
if (dest.isValid())
- qCDebug(qLcLink) << event->position() << ":" << posInPoints << "pt ->" << dest;
+ qCDebug(qLcWLink) << event->position() << ":" << posInPoints << "pt ->" << dest;
}
}
}
@@ -699,7 +699,7 @@ void QPdfView::mouseReleaseEvent(QMouseEvent *event)
d->m_linkModel.setPage(page);
auto dest = d->m_linkModel.linkAt(posInPoints);
if (dest.isValid()) {
- qCDebug(qLcLink) << event << ": jumping to" << dest;
+ qCDebug(qLcWLink) << event << ": jumping to" << dest;
d->m_pageNavigator->jump(dest.page(), dest.location(), dest.zoom());
// TODO scroll and zoom to where the link tells us to
}
diff --git a/src/webenginequick/CMakeLists.txt b/src/webenginequick/CMakeLists.txt
index 5f8344f08..b7de1c2af 100644
--- a/src/webenginequick/CMakeLists.txt
+++ b/src/webenginequick/CMakeLists.txt
@@ -37,8 +37,8 @@ qt_internal_add_qml_module(WebEngineQuick
api/qquickwebengineforeigntypes_p.h
api/qtwebenginequickglobal.cpp api/qtwebenginequickglobal.h
api/qtwebenginequickglobal_p.h
- render_widget_host_view_qt_delegate_quickwindow.cpp render_widget_host_view_qt_delegate_quickwindow.h
- ui_delegates_manager.cpp ui_delegates_manager.h
+ render_widget_host_view_qt_delegate_quickwindow.cpp render_widget_host_view_qt_delegate_quickwindow_p.h
+ ui_delegates_manager.cpp ui_delegates_manager_p.h
DEFINES
QT_BUILD_WEBENGINE_LIB
INCLUDE_DIRECTORIES
@@ -65,7 +65,7 @@ qt_internal_extend_target(WebEngineQuick CONDITION QT_FEATURE_webengine_webchann
qt_internal_extend_target(WebEngineQuick CONDITION QT_FEATURE_accessibility
SOURCES
- qquickwebengine_accessible.cpp qquickwebengine_accessible.h
+ qquickwebengine_accessible.cpp qquickwebengine_accessible_p.h
)
qt_internal_extend_target(qtwebenginequickplugin
diff --git a/src/webenginequick/api/qquickwebenginefaviconprovider.cpp b/src/webenginequick/api/qquickwebenginefaviconprovider.cpp
index 56bbb97ac..00c7f1949 100644
--- a/src/webenginequick/api/qquickwebenginefaviconprovider.cpp
+++ b/src/webenginequick/api/qquickwebenginefaviconprovider.cpp
@@ -11,9 +11,9 @@
#include "web_contents_adapter.h"
#include <QtCore/qmimedatabase.h>
-#include <QtCore/qtimer.h>
#include <QtGui/qicon.h>
#include <QtGui/qpixmap.h>
+#include <QThread>
QT_BEGIN_NAMESPACE
@@ -79,123 +79,167 @@ static bool isIconURL(const QUrl &url)
return false;
}
-static QQuickWebEngineView *findViewById(const QString &id, QList<QQuickWebEngineView *> *views)
-{
- QQuickWebEngineView *result = nullptr;
- for (QQuickWebEngineView *view : *views) {
- if (isIconURL(QUrl(id))) {
- if (view->icon() == QQuickWebEngineFaviconProvider::faviconProviderUrl(QUrl(id))) {
- result = view;
- break;
- }
- } else if (view->url() == QUrl(id)) {
- result = view;
- break;
- }
- }
-
- return result;
-}
-
-FaviconImageResponseRunnable::FaviconImageResponseRunnable(const QString &id,
- const QSize &requestedSize,
- QList<QQuickWebEngineView *> *views)
- : m_id(id), m_requestedSize(requestedSize), m_views(views)
+FaviconImageRequester::FaviconImageRequester(const QUrl &imageSource, const QSize &requestedSize)
+ : m_imageSource(imageSource), m_requestedSize(requestedSize)
{
}
-void FaviconImageResponseRunnable::run()
+void FaviconImageRequester::start()
{
- if (tryNextView() == -1) {
+ if (!tryNextView()) {
// There is no non-otr view to access icon database.
Q_EMIT done(QPixmap());
}
}
-void FaviconImageResponseRunnable::iconRequestDone(const QIcon &icon)
+void FaviconImageRequester::iconRequestDone(const QIcon &icon)
{
if (icon.isNull()) {
- if (tryNextView() == -1) {
+ if (!tryNextView()) {
// Ran out of views.
Q_EMIT done(QPixmap());
}
return;
}
- Q_EMIT done(extractPixmap(icon, m_requestedSize).copy());
+ Q_EMIT done(extractPixmap(icon, m_requestedSize));
+}
+
+bool FaviconImageRequester::tryNextView()
+{
+ if (auto view = getNextViewForProcessing()) {
+ requestFaviconFromDatabase(view);
+ return true;
+ }
+
+ return false;
+}
+
+void FaviconImageRequester::requestFaviconFromDatabase(QPointer<QQuickWebEngineView> view)
+{
+ QtWebEngineCore::ProfileAdapter *profileAdapter = view->d_ptr->profileAdapter();
+ bool touchIconsEnabled = view->profile()->settings()->touchIconsEnabled();
+ if (isIconURL(m_imageSource)) {
+ profileAdapter->requestIconForIconURL(
+ m_imageSource, qMax(m_requestedSize.width(), m_requestedSize.height()),
+ touchIconsEnabled, [this](const QIcon &icon, const QUrl &) {
+ QMetaObject::invokeMethod(this, "iconRequestDone", Qt::QueuedConnection,
+ Q_ARG(const QIcon &, icon));
+ });
+ } else {
+ profileAdapter->requestIconForPageURL(
+ m_imageSource, qMax(m_requestedSize.width(), m_requestedSize.height()),
+ touchIconsEnabled, [this](const QIcon &icon, const QUrl &, const QUrl &) {
+ QMetaObject::invokeMethod(this, "iconRequestDone", Qt::QueuedConnection,
+ Q_ARG(const QIcon &, icon));
+ });
+ }
}
-int FaviconImageResponseRunnable::tryNextView()
+QPointer<QQuickWebEngineView> FaviconImageRequester::getNextViewForProcessing()
{
- for (; m_nextViewIndex < m_views->size(); ++m_nextViewIndex) {
- QQuickWebEngineView *view = m_views->at(m_nextViewIndex);
+ Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread());
+
+ for (QPointer<QQuickWebEngineView> view : FaviconProviderHelper::instance()->views()) {
+ if (view.isNull())
+ continue;
if (view->profile()->isOffTheRecord())
continue;
+ if (m_processedViews.contains(view))
+ continue;
+ m_processedViews.append(view);
+ return view;
+ }
+ return nullptr;
+}
- requestIconOnUIThread(view);
+FaviconProviderHelper::FaviconProviderHelper()
+{
+ moveToThread(qApp->thread());
+}
- return m_nextViewIndex++;
- }
+FaviconProviderHelper *FaviconProviderHelper::instance()
+{
+ static FaviconProviderHelper instance;
+ return &instance;
+}
- return -1;
+void FaviconProviderHelper::attach(QPointer<QQuickWebEngineView> view)
+{
+ if (!m_views.contains(view))
+ m_views.append(view);
}
-void FaviconImageResponseRunnable::requestIconOnUIThread(QQuickWebEngineView *view)
+void FaviconProviderHelper::detach(QPointer<QQuickWebEngineView> view)
{
- QTimer *timer = new QTimer();
- timer->moveToThread(qApp->thread());
- timer->setSingleShot(true);
- QObject::connect(timer, &QTimer::timeout, [this, view, timer]() {
- QtWebEngineCore::ProfileAdapter *profileAdapter = view->d_ptr->profileAdapter();
- bool touchIconsEnabled = view->profile()->settings()->touchIconsEnabled();
- if (isIconURL(QUrl(m_id))) {
- profileAdapter->requestIconForIconURL(QUrl(m_id),
- qMax(m_requestedSize.width(), m_requestedSize.height()),
- touchIconsEnabled,
- [this](const QIcon &icon, const QUrl &) { iconRequestDone(icon); });
- } else {
- profileAdapter->requestIconForPageURL(QUrl(m_id),
- qMax(m_requestedSize.width(), m_requestedSize.height()),
- touchIconsEnabled,
- [this](const QIcon &icon, const QUrl &, const QUrl &) { iconRequestDone(icon); });
- }
- timer->deleteLater();
- });
- QMetaObject::invokeMethod(timer, "start", Qt::QueuedConnection, Q_ARG(int, 0));
+ m_views.removeAll(view);
}
-FaviconImageResponse::FaviconImageResponse()
+void FaviconProviderHelper::handleImageRequest(QPointer<FaviconImageResponse> faviconResponse)
{
- Q_EMIT finished();
+ Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread());
+
+ if (faviconResponse.isNull())
+ return;
+
+ if (m_views.isEmpty()) {
+ QMetaObject::invokeMethod(faviconResponse, "handleDone", Qt::QueuedConnection,
+ Q_ARG(QPixmap, QPixmap()));
+ return;
+ }
+
+ auto view = findViewByImageSource(faviconResponse->imageSource());
+ if (view) {
+ QIcon icon = view->d_ptr->adapter->icon();
+ if (!icon.isNull()) {
+ QMetaObject::invokeMethod(
+ faviconResponse, "handleDone", Qt::QueuedConnection,
+ Q_ARG(QPixmap, extractPixmap(icon, faviconResponse->requestedSize())));
+ return;
+ }
+ }
+ startFaviconRequest(faviconResponse);
}
-FaviconImageResponse::FaviconImageResponse(const QString &id, const QSize &requestedSize,
- QList<QQuickWebEngineView *> *views, QThreadPool *pool)
+QPointer<QQuickWebEngineView> FaviconProviderHelper::findViewByImageSource(const QUrl &imageSource) const
{
- if (QQuickWebEngineView *view = findViewById(id, views)) {
- QTimer *timer = new QTimer();
- timer->moveToThread(qApp->thread());
- timer->setSingleShot(true);
- QObject::connect(timer, &QTimer::timeout, [this, id, requestedSize, views, pool, view, timer]() {
- QIcon icon = view->d_ptr->adapter->icon();
- if (icon.isNull())
- startRunnable(id, requestedSize, views, pool);
- else
- handleDone(extractPixmap(icon, requestedSize).copy());
- timer->deleteLater();
- });
- QMetaObject::invokeMethod(timer, "start", Qt::QueuedConnection, Q_ARG(int, 0));
- } else {
- startRunnable(id, requestedSize, views, pool);
+ for (QPointer<QQuickWebEngineView> view : m_views) {
+ if (view.isNull())
+ continue;
+
+ if (isIconURL(imageSource)) {
+ if (view->icon() == QQuickWebEngineFaviconProvider::faviconProviderUrl(imageSource)) {
+ return view;
+ }
+ } else if (view->url() == imageSource) {
+ return view;
+ }
}
+
+ return nullptr;
}
-FaviconImageResponse::~FaviconImageResponse() { }
+void FaviconProviderHelper::startFaviconRequest(QPointer<FaviconImageResponse> faviconResponse)
+{
+ FaviconImageRequester *requester = new FaviconImageRequester(faviconResponse->imageSource(),
+ faviconResponse->requestedSize());
+
+ connect(requester, &FaviconImageRequester::done, [requester, faviconResponse](QPixmap pixmap) {
+ QMetaObject::invokeMethod(faviconResponse, "handleDone", Qt::QueuedConnection,
+ Q_ARG(QPixmap, pixmap));
+ requester->deleteLater();
+ });
+
+ requester->start();
+}
+
+FaviconImageResponse::FaviconImageResponse(const QUrl &imageSource, const QSize &requestedSize)
+ : m_imageSource(imageSource), m_requestedSize(requestedSize)
+{
+}
void FaviconImageResponse::handleDone(QPixmap pixmap)
{
- if (m_runnable)
- delete m_runnable;
m_image = pixmap.toImage();
Q_EMIT finished();
}
@@ -205,16 +249,6 @@ QQuickTextureFactory *FaviconImageResponse::textureFactory() const
return QQuickTextureFactory::textureFactoryForImage(m_image);
}
-void FaviconImageResponse::startRunnable(const QString &id, const QSize &requestedSize,
- QList<QQuickWebEngineView *> *views, QThreadPool *pool)
-{
- m_runnable = new FaviconImageResponseRunnable(id, requestedSize, views);
- m_runnable->setAutoDelete(false);
- connect(m_runnable, &FaviconImageResponseRunnable::done, this,
- &FaviconImageResponse::handleDone);
- pool->start(m_runnable);
-}
-
QString QQuickWebEngineFaviconProvider::identifier()
{
return QStringLiteral("favicon");
@@ -238,17 +272,17 @@ QUrl QQuickWebEngineFaviconProvider::faviconProviderUrl(const QUrl &url)
return providerUrl;
}
-QQuickWebEngineFaviconProvider::QQuickWebEngineFaviconProvider() { }
-
-QQuickWebEngineFaviconProvider::~QQuickWebEngineFaviconProvider() { }
+QQuickWebEngineFaviconProvider::QQuickWebEngineFaviconProvider()
+{
+ connect(this, &QQuickWebEngineFaviconProvider::imageResponseRequested,
+ FaviconProviderHelper::instance(), &FaviconProviderHelper::handleImageRequest);
+}
QQuickImageResponse *
QQuickWebEngineFaviconProvider::requestImageResponse(const QString &id, const QSize &requestedSize)
{
- if (m_views.empty())
- return new FaviconImageResponse;
-
- FaviconImageResponse *response = new FaviconImageResponse(id, requestedSize, &m_views, &m_pool);
+ FaviconImageResponse *response = new FaviconImageResponse(QUrl(id), requestedSize);
+ emit imageResponseRequested(response);
return response;
}
diff --git a/src/webenginequick/api/qquickwebenginefaviconprovider_p_p.h b/src/webenginequick/api/qquickwebenginefaviconprovider_p_p.h
index 89bfb6e73..f1d948413 100644
--- a/src/webenginequick/api/qquickwebenginefaviconprovider_p_p.h
+++ b/src/webenginequick/api/qquickwebenginefaviconprovider_p_p.h
@@ -17,8 +17,6 @@
#include <QtWebEngineQuick/private/qtwebenginequickglobal_p.h>
#include <QtCore/qlist.h>
-#include <QtCore/qrunnable.h>
-#include <QtCore/qthreadpool.h>
#include <QtGui/qimage.h>
#include <QtQuick/qquickimageprovider.h>
@@ -26,65 +24,84 @@ QT_BEGIN_NAMESPACE
class QQuickWebEngineView;
-class FaviconImageResponseRunnable : public QObject, public QRunnable
+class FaviconImageResponse : public QQuickImageResponse
{
Q_OBJECT
public:
- FaviconImageResponseRunnable(const QString &id, const QSize &requestedSize,
- QList<QQuickWebEngineView *> *views);
- void run() override;
- void iconRequestDone(const QIcon &icon);
+ FaviconImageResponse(const QUrl &imageSource, const QSize &requestedSize);
-signals:
- void done(QPixmap pixmap);
+ QQuickTextureFactory *textureFactory() const override;
+ const QUrl &imageSource() const { return m_imageSource; }
+ const QSize &requestedSize() const { return m_requestedSize; }
-private:
- int tryNextView();
- void requestIconOnUIThread(QQuickWebEngineView *view);
+public slots:
+ void handleDone(QPixmap pixmap);
- QString m_id;
+private:
+ QImage m_image;
+ QUrl m_imageSource;
QSize m_requestedSize;
- QList<QQuickWebEngineView *> *m_views;
- int m_nextViewIndex = 0;
};
-class FaviconImageResponse : public QQuickImageResponse
+class FaviconImageRequester : public QObject
{
+ Q_OBJECT
+
public:
- FaviconImageResponse();
- FaviconImageResponse(const QString &id, const QSize &requestedSize,
- QList<QQuickWebEngineView *> *views, QThreadPool *pool);
- ~FaviconImageResponse();
- void handleDone(QPixmap pixmap);
- QQuickTextureFactory *textureFactory() const override;
+ FaviconImageRequester(const QUrl &imageSource, const QSize &requestedSize);
+ void start();
+
+public slots:
+ void iconRequestDone(const QIcon &icon);
+
+signals:
+ void done(QPixmap pixmap);
private:
- void startRunnable(const QString &id, const QSize &requestedSize,
- QList<QQuickWebEngineView *> *views, QThreadPool *pool);
+ bool tryNextView();
+ void requestFaviconFromDatabase(QPointer<QQuickWebEngineView> view);
+ QPointer<QQuickWebEngineView> getNextViewForProcessing();
- FaviconImageResponseRunnable *m_runnable = nullptr;
- QImage m_image;
+ QUrl m_imageSource;
+ QSize m_requestedSize;
+ QList<QPointer<QQuickWebEngineView>> m_processedViews;
};
class Q_WEBENGINEQUICK_EXPORT QQuickWebEngineFaviconProvider : public QQuickAsyncImageProvider
{
+ Q_OBJECT
+
public:
static QString identifier();
static QUrl faviconProviderUrl(const QUrl &);
QQuickWebEngineFaviconProvider();
- ~QQuickWebEngineFaviconProvider();
-
- void attach(QQuickWebEngineView *view) { m_views.append(view); }
- void detach(QQuickWebEngineView *view) { m_views.removeAll(view); }
-
QQuickImageResponse *requestImageResponse(const QString &id,
const QSize &requestedSize) override;
+signals:
+ void imageResponseRequested(QPointer<FaviconImageResponse> faviconResponse);
+};
+
+class Q_WEBENGINEQUICK_EXPORT FaviconProviderHelper : public QObject
+{
+ Q_OBJECT
+
+public:
+ static FaviconProviderHelper *instance();
+ void attach(QPointer<QQuickWebEngineView> view);
+ void detach(QPointer<QQuickWebEngineView> view);
+ const QList<QPointer<QQuickWebEngineView>> &views() const { return m_views; }
+
+public slots:
+ void handleImageRequest(QPointer<FaviconImageResponse> faviconResponse);
+
private:
- QThreadPool m_pool;
- QList<QQuickWebEngineView *> m_views;
+ FaviconProviderHelper();
+ void startFaviconRequest(QPointer<FaviconImageResponse> faviconResponse);
+ QPointer<QQuickWebEngineView> findViewByImageSource(const QUrl &imageSource) const;
+ QList<QPointer<QQuickWebEngineView>> m_views;
};
QT_END_NAMESPACE
diff --git a/src/webenginequick/api/qquickwebengineprofile.cpp b/src/webenginequick/api/qquickwebengineprofile.cpp
index 7c3d11fcf..edca5e99c 100644
--- a/src/webenginequick/api/qquickwebengineprofile.cpp
+++ b/src/webenginequick/api/qquickwebengineprofile.cpp
@@ -105,6 +105,8 @@ QT_BEGIN_NAMESPACE
The download item is parented by the profile. If it is not accepted, it
will be deleted immediately after the signal emission.
This signal cannot be used with a queued connection.
+
+ \note To use from C++ static_cast \a download to QWebEngineDownloadRequest
*/
/*!
@@ -113,6 +115,8 @@ QT_BEGIN_NAMESPACE
This signal is emitted whenever downloading stops, because it finished successfully, was
cancelled, or was interrupted (for example, because connectivity was lost).
The \a download argument holds the state of the finished download instance.
+
+ \note To use from C++ static_cast \a download to QWebEngineDownloadRequest
*/
/*!
diff --git a/src/webenginequick/api/qquickwebengineprofile.h b/src/webenginequick/api/qquickwebengineprofile.h
index 088a971e0..cbeb91147 100644
--- a/src/webenginequick/api/qquickwebengineprofile.h
+++ b/src/webenginequick/api/qquickwebengineprofile.h
@@ -144,7 +144,7 @@ private:
QQuickWebEngineSettings *settings() const;
void ensureQmlContext(const QObject *object);
- friend class FaviconImageResponseRunnable;
+ friend class FaviconImageRequester;
friend class QQuickWebEngineSingleton;
friend class QQuickWebEngineViewPrivate;
friend class QQuickWebEngineView;
diff --git a/src/webenginequick/api/qquickwebengineview.cpp b/src/webenginequick/api/qquickwebengineview.cpp
index 31e5d572e..85c5e1a73 100644
--- a/src/webenginequick/api/qquickwebengineview.cpp
+++ b/src/webenginequick/api/qquickwebengineview.cpp
@@ -25,9 +25,9 @@
#include "find_text_helper.h"
#include "javascript_dialog_controller.h"
#include "render_widget_host_view_qt_delegate_item.h"
-#include "render_widget_host_view_qt_delegate_quickwindow.h"
+#include "render_widget_host_view_qt_delegate_quickwindow_p.h"
#include "touch_selection_menu_controller.h"
-#include "ui_delegates_manager.h"
+#include "ui_delegates_manager_p.h"
#include "web_contents_adapter.h"
#include <QtWebEngineCore/qwebenginecertificateerror.h>
@@ -63,7 +63,7 @@
#include <QtQml/qqmlproperty.h>
#if QT_CONFIG(accessibility)
-#include "qquickwebengine_accessible.h"
+#include "qquickwebengine_accessible_p.h"
#include <QtGui/qaccessible.h>
#endif
@@ -332,8 +332,7 @@ QQuickWebEngineViewPrivate::~QQuickWebEngineViewPrivate()
{
Q_ASSERT(m_profileInitialized);
m_profile->d_ptr->removeWebContentsAdapterClient(this);
- if (m_faviconProvider)
- m_faviconProvider->detach(q_ptr);
+ FaviconProviderHelper::instance()->detach(q_ptr);
bindViewAndDelegateItem(this, nullptr);
}
@@ -446,10 +445,10 @@ void QQuickWebEngineViewPrivate::contextMenuRequested(QWebEngineContextMenuReque
ui()->showMenu(menu);
}
-void QQuickWebEngineViewPrivate::navigationRequested(int navigationType, const QUrl &url, bool &accepted, bool isMainFrame)
+void QQuickWebEngineViewPrivate::navigationRequested(int navigationType, const QUrl &url, bool &accepted, bool isMainFrame, bool hasFrameData)
{
Q_Q(QQuickWebEngineView);
- auto request = new QWebEngineNavigationRequest(url, static_cast<QWebEngineNavigationRequest::NavigationType>(navigationType), isMainFrame);
+ auto request = new QWebEngineNavigationRequest(url, static_cast<QWebEngineNavigationRequest::NavigationType>(navigationType), isMainFrame, hasFrameData);
qmlEngine(q)->newQObject(request);
Q_EMIT q->navigationRequested(request);
@@ -951,16 +950,7 @@ void QQuickWebEngineViewPrivate::ensureContentsAdapter()
adapter->loadDefault();
}
- if (!m_faviconProvider) {
- QQmlEngine *engine = qmlEngine(q_ptr);
- // TODO: this is a workaround for QTBUG-65044
- if (!engine)
- return;
- m_faviconProvider = static_cast<QQuickWebEngineFaviconProvider *>(
- engine->imageProvider(QQuickWebEngineFaviconProvider::identifier()));
- m_faviconProvider->attach(q_ptr);
- Q_ASSERT(m_faviconProvider);
- }
+ FaviconProviderHelper::instance()->attach(q_ptr);
}
void QQuickWebEngineViewPrivate::initializationFinished()
@@ -1306,19 +1296,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,
+ 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, 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);
@@ -1497,16 +1486,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, wrappedCallback);
}
qreal QQuickWebEngineView::zoomFactor() const
@@ -1603,7 +1591,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);
@@ -2529,6 +2517,19 @@ QQmlComponent *QQuickWebEngineView::touchHandleDelegate() const
return d_ptr->m_touchHandleDelegate;
}
+QWebEngineFrame QQuickWebEngineView::mainFrame()
+{
+ Q_D(QQuickWebEngineView);
+ return QWebEngineFrame(d, d->adapter->mainFrameId());
+}
+
+QWebEngineFrame QQuickWebEngineView::findFrameByName(const QString &name)
+{
+ Q_D(QQuickWebEngineView);
+ auto maybeId = d->adapter->findFrameIdByName(name);
+ return QWebEngineFrame(d, maybeId.value_or(WebContentsAdapter::kInvalidFrameId));
+}
+
void QQuickWebEngineView::save(const QString &filePath,
QWebEngineDownloadRequest::SavePageFormat format) const
{
diff --git a/src/webenginequick/api/qquickwebengineview_p.h b/src/webenginequick/api/qquickwebengineview_p.h
index 0fdd9f787..37e39dfed 100644
--- a/src/webenginequick/api/qquickwebengineview_p.h
+++ b/src/webenginequick/api/qquickwebengineview_p.h
@@ -19,6 +19,7 @@
#include <QtWebEngineCore/qwebenginequotarequest.h>
#include <QtWebEngineCore/qwebenginedesktopmediarequest.h>
#include <QtWebEngineCore/qwebenginedownloadrequest.h>
+#include <QtWebEngineCore/qwebengineframe.h>
#include <QtWebEngineQuick/private/qtwebenginequickglobal_p.h>
#include <QtGui/qcolor.h>
#include <QtQml/qqmlregistration.h>
@@ -91,6 +92,7 @@ class Q_WEBENGINEQUICK_EXPORT QQuickWebEngineView : public QQuickItem {
Q_PROPERTY(qint64 renderProcessPid READ renderProcessPid NOTIFY renderProcessPidChanged FINAL REVISION(1,11))
Q_PROPERTY(QQmlComponent *touchHandleDelegate READ touchHandleDelegate WRITE
setTouchHandleDelegate NOTIFY touchHandleDelegateChanged REVISION(0) FINAL)
+ Q_PROPERTY(QWebEngineFrame mainFrame READ mainFrame FINAL REVISION(6, 8))
QML_NAMED_ELEMENT(WebEngineView)
QML_ADDED_IN_VERSION(1, 0)
QML_EXTRA_VERSION(2, 0)
@@ -472,6 +474,9 @@ QT_WARNING_POP
QQmlComponent *touchHandleDelegate() const;
void setTouchHandleDelegate(QQmlComponent *delegagte);
+ QWebEngineFrame mainFrame();
+ Q_REVISION(6, 8) Q_INVOKABLE QWebEngineFrame findFrameByName(const QString &name);
+
public Q_SLOTS:
void runJavaScript(const QString&, const QJSValue & = QJSValue());
Q_REVISION(1,3) void runJavaScript(const QString&, quint32 worldId, const QJSValue & = QJSValue());
@@ -572,8 +577,8 @@ private:
QScopedPointer<QQuickWebEngineViewPrivate> d_ptr;
friend class QQuickContextMenuBuilder;
- friend class FaviconImageResponse;
- friend class FaviconImageResponseRunnable;
+ friend class FaviconProviderHelper;
+ friend class FaviconImageRequester;
#if QT_CONFIG(accessibility)
friend class QQuickWebEngineViewAccessible;
#endif // QT_CONFIG(accessibility)
diff --git a/src/webenginequick/api/qquickwebengineview_p_p.h b/src/webenginequick/api/qquickwebengineview_p_p.h
index ee7da99b9..eed8342eb 100644
--- a/src/webenginequick/api/qquickwebengineview_p_p.h
+++ b/src/webenginequick/api/qquickwebengineview_p_p.h
@@ -19,7 +19,7 @@
#include "qquickwebengineview_p.h"
#include "render_view_context_menu_qt.h"
#include "touch_handle_drawable_client.h"
-#include "ui_delegates_manager.h"
+#include "ui_delegates_manager_p.h"
#include "web_contents_adapter_client.h"
#include <QtCore/qcompilerdetection.h>
@@ -37,7 +37,6 @@ class WebContentsAdapter;
QT_BEGIN_NAMESPACE
class QQmlComponent;
-class QQuickWebEngineFaviconProvider;
class QQuickWebEngineScriptCollection;
class QQuickWebEngineSettings;
class QQuickWebEngineView;
@@ -88,12 +87,13 @@ public:
void requestFullScreenMode(const QUrl &origin, bool fullscreen) override;
bool isFullScreenMode() const override;
void contextMenuRequested(QWebEngineContextMenuRequest *request) override;
- void navigationRequested(int navigationType, const QUrl &url, bool &accepted, bool isMainFrame) override;
+ void navigationRequested(int navigationType, const QUrl &url, bool &accepted, bool isMainFrame, bool hasFrameData) override;
void javascriptDialog(QSharedPointer<QtWebEngineCore::JavaScriptDialogController>) override;
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,
+ 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;
@@ -158,7 +158,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;
@@ -178,7 +178,6 @@ private:
bool m_profileInitialized;
QWebEngineContextMenuRequest *m_contextMenuRequest;
QScopedPointer<QQuickWebEngineScriptCollection> m_scriptCollection;
- QPointer<QQuickWebEngineFaviconProvider> m_faviconProvider;
QQmlComponent *m_touchHandleDelegate;
};
diff --git a/src/webenginequick/doc/src/webengineframe.qdoc b/src/webenginequick/doc/src/webengineframe.qdoc
new file mode 100644
index 000000000..ef2a5c33d
--- /dev/null
+++ b/src/webenginequick/doc/src/webengineframe.qdoc
@@ -0,0 +1,65 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \qmltype webEngineFrame
+ \instantiates QQuickWebEngineFrame
+ \brief webEngineFrame provides information about and control over a page frame.
+ \since 6.8
+ \ingroup qmlvaluetypes
+ \inqmlmodule QtWebEngine
+
+ A web engine frame represents a single frame within a web page, such as those created by
+ \c <frame> or \c <iframe> HTML elements.
+ An active \l WebEngineView has one or more frames arranged in a tree structure. The top-level
+ frame, the root of this tree, can be accessed through the view's \l {WebEngineView::mainFrame}
+ {mainFrame} property.
+
+ A frame's lifetime is, at most, as long as the \l WebEngineView object that produced it.
+ However, frames may be created and deleted spontaneously and dynamically, for example through
+ navigation and script execution.
+*/
+
+/*!
+ \qmlproperty bool webEngineFrame::isValid
+
+ Returns \c{true} if this object represents an existing frame; \c{false} otherwise.
+
+ Once a frame is invalid, it never becomes valid again.
+*/
+
+/*!
+ \qmlproperty string webEngineFrame::name
+
+ Returns the frame name; that is, what would be returned by \c window.name in JavaScript.
+
+ If the frame could not be found, returns an empty string.
+
+ \sa htmlName
+*/
+
+/*!
+ \qmlproperty string webEngineFrame::htmlName
+
+ Returns the value of the frame's \c name HTML attribute, or an empty string if it has none.
+
+ If the frame could not be found, returns an empty string.
+
+ \sa name
+*/
+
+/*!
+ \qmlproperty url webEngineFrame::url
+
+ Returns the URL of the content currently loaded in this frame.
+
+ If the frame could not be found, returns an empty URL.
+*/
+
+/*!
+ \qmlproperty size webEngineFrame::size
+
+ Returns the size of the frame within the viewport.
+
+ If the frame could not be found, returns a default size with dimensions (-1, -1).
+*/
diff --git a/src/webenginequick/doc/src/webengineview_lgpl.qdoc b/src/webenginequick/doc/src/webengineview_lgpl.qdoc
index eeae34dcc..9dde89e65 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.
@@ -1551,6 +1555,23 @@
*/
/*!
+ \qmlproperty webEngineFrame WebEngineView::mainFrame
+ \since QtWebEngine 6.8
+
+ The main, top-level frame of the page. All other frames on this page are accessible
+ as children of the main frame.
+ */
+
+/*!
+ \qmlmethod webEngineFrame WebEngineView::findFrameByName(string name)
+ \since QtWebEngine 6.8
+
+ Returns the frame with the given \a name. If there are multiple frames with the same
+ name, which one is returned is arbitrary. If no frame was found, returns an
+ \l{webEngineFrame::isValid}{invalid} frame.
+*/
+
+/*!
\qmlmethod void WebEngineView::save(const QString &filePath, QWebEngineDownloadRequest::SavePageFormat format)
\since QtWebEngine 6.6
diff --git a/src/webenginequick/qquickwebengine_accessible.cpp b/src/webenginequick/qquickwebengine_accessible.cpp
index 2941f01b5..e156a5e8b 100644
--- a/src/webenginequick/qquickwebengine_accessible.cpp
+++ b/src/webenginequick/qquickwebengine_accessible.cpp
@@ -1,7 +1,7 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qquickwebengine_accessible.h"
+#include "qquickwebengine_accessible_p.h"
#include <QQuickItem>
#include <QQuickWindow>
diff --git a/src/webenginequick/qquickwebengine_accessible.h b/src/webenginequick/qquickwebengine_accessible_p.h
index 479de9789..2f774f898 100644
--- a/src/webenginequick/qquickwebengine_accessible.h
+++ b/src/webenginequick/qquickwebengine_accessible_p.h
@@ -4,6 +4,17 @@
#ifndef QQUICKWEBENGINE_ACCESSIBLE_H
#define QQUICKWEBENGINE_ACCESSIBLE_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <QtCore/qpointer.h>
#include <QtGui/qaccessibleobject.h>
diff --git a/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.cpp b/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.cpp
index b003dabe4..090b09281 100644
--- a/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.cpp
+++ b/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.cpp
@@ -1,7 +1,7 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "render_widget_host_view_qt_delegate_quickwindow.h"
+#include "render_widget_host_view_qt_delegate_quickwindow_p.h"
#include "api/qquickwebengineview_p_p.h"
diff --git a/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.h b/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow_p.h
index 712eef732..3559bd2f0 100644
--- a/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.h
+++ b/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow_p.h
@@ -4,6 +4,17 @@
#ifndef RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_QUICKWINDOW_H
#define RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_QUICKWINDOW_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include "render_widget_host_view_qt_delegate.h"
#include "render_widget_host_view_qt_delegate_item.h"
diff --git a/src/webenginequick/ui_delegates_manager.cpp b/src/webenginequick/ui_delegates_manager.cpp
index 3d6eff649..a4a22fedd 100644
--- a/src/webenginequick/ui_delegates_manager.cpp
+++ b/src/webenginequick/ui_delegates_manager.cpp
@@ -1,7 +1,7 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "ui_delegates_manager.h"
+#include "ui_delegates_manager_p.h"
#include "api/qquickwebengineaction_p.h"
#include "api/qquickwebengineview_p_p.h"
diff --git a/src/webenginequick/ui_delegates_manager.h b/src/webenginequick/ui_delegates_manager_p.h
index 24dde656c..3502757d7 100644
--- a/src/webenginequick/ui_delegates_manager.h
+++ b/src/webenginequick/ui_delegates_manager_p.h
@@ -4,6 +4,17 @@
#ifndef UI_DELEGATES_MANAGER_H
#define UI_DELEGATES_MANAGER_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <QtCore/qcoreapplication.h> // Q_DECLARE_TR_FUNCTIONS
#include <QtCore/qobject.h>
#include <QtCore/qpoint.h>
diff --git a/src/webenginewidgets/CMakeLists.txt b/src/webenginewidgets/CMakeLists.txt
index dd11e48be..ff043b45a 100644
--- a/src/webenginewidgets/CMakeLists.txt
+++ b/src/webenginewidgets/CMakeLists.txt
@@ -37,7 +37,7 @@ qt_internal_add_module(WebEngineWidgets
qt_internal_extend_target(WebEngineWidgets CONDITION QT_FEATURE_accessibility
SOURCES
- qwebengine_accessible.cpp qwebengine_accessible.h
+ qwebengine_accessible.cpp qwebengine_accessible_p.h
)
qt_internal_extend_target(WebEngineWidgets CONDITION QT_FEATURE_webengine_printing_and_pdf
diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp
index e28f70b5f..5b47d67bf 100644
--- a/src/webenginewidgets/api/qwebengineview.cpp
+++ b/src/webenginewidgets/api/qwebengineview.cpp
@@ -32,7 +32,7 @@
#include <QQuickWidget>
#if QT_CONFIG(accessibility)
-#include "qwebengine_accessible.h"
+#include "qwebengine_accessible_p.h"
#endif
#if QT_CONFIG(action)
diff --git a/src/webenginewidgets/qwebengine_accessible.cpp b/src/webenginewidgets/qwebengine_accessible.cpp
index 6880a5a3a..cbdd90104 100644
--- a/src/webenginewidgets/qwebengine_accessible.cpp
+++ b/src/webenginewidgets/qwebengine_accessible.cpp
@@ -1,7 +1,7 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qwebengine_accessible.h"
+#include "qwebengine_accessible_p.h"
#include "qwebengineview.h"
#include "qwebengineview_p.h"
diff --git a/src/webenginewidgets/qwebengine_accessible.h b/src/webenginewidgets/qwebengine_accessible_p.h
index f47996cf7..99604d90d 100644
--- a/src/webenginewidgets/qwebengine_accessible.h
+++ b/src/webenginewidgets/qwebengine_accessible_p.h
@@ -4,6 +4,17 @@
#ifndef QWEBENGINE_ACCESSIBLE_H
#define QWEBENGINE_ACCESSIBLE_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <QtCore/QPointer>
#include <QtWidgets/QAccessibleWidget>
diff --git a/tests/auto/core/CMakeLists.txt b/tests/auto/core/CMakeLists.txt
index 5908756b4..eb8e9266f 100644
--- a/tests/auto/core/CMakeLists.txt
+++ b/tests/auto/core/CMakeLists.txt
@@ -2,6 +2,7 @@
# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(qwebenginecookiestore)
+add_subdirectory(qwebengineframe)
add_subdirectory(qwebengineloadinginfo)
add_subdirectory(qwebenginesettings)
if(QT_FEATURE_ssl)
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/CMakeLists.txt b/tests/auto/core/qwebengineframe/CMakeLists.txt
new file mode 100644
index 000000000..d02b4307d
--- /dev/null
+++ b/tests/auto/core/qwebengineframe/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(../../util/util.cmake)
+
+qt_internal_add_test(tst_qwebengineframe
+ SOURCES
+ tst_qwebengineframe.cpp
+ LIBRARIES
+ Qt::WebEngineCore
+ Qt::WebEngineWidgets
+ Test::Util
+)
+
+qt_internal_add_resource(tst_qwebengineframe "tst_qwebengineframe"
+ PREFIX
+ "/"
+ FILES
+ "resources/frameset.html"
+ "resources/iframes.html"
+ "resources/nesting-iframe.html"
+)
diff --git a/tests/auto/core/qwebengineframe/resources/frameset.html b/tests/auto/core/qwebengineframe/resources/frameset.html
new file mode 100644
index 000000000..53f5e6638
--- /dev/null
+++ b/tests/auto/core/qwebengineframe/resources/frameset.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<html>
+ <head><title>Test-title</title></head>
+ <script>
+ window.name = 'test-main-frame'
+ onload = (e) => {
+ const frames = window.frames;
+ for (let i = 0; i < frames.length; i++) {
+ frames[i].name = 'test-subframe' + i;
+ }
+ };
+ </script>
+ <frameset cols="50%, 50%">
+ <frameset cols="50%, 50%">
+ <frame style="border: red dashed 1em;"/>
+ <frame style="border: green dashed 1em;"/>
+ </frameset>
+ <frame style="border: blue solid 1em;"/>
+ </frameset>
+</html>
diff --git a/tests/auto/core/qwebengineframe/resources/iframes.html b/tests/auto/core/qwebengineframe/resources/iframes.html
new file mode 100644
index 000000000..648acb166
--- /dev/null
+++ b/tests/auto/core/qwebengineframe/resources/iframes.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<html>
+ <head><title>Test-title</title></head>
+ <script>
+ window.name = 'test-main-frame'
+ onload = (e) => {
+ const frames = window.frames;
+ for (let i = 0; i < frames.length; i++) {
+ frames[i].name = 'test-subframe' + i;
+ }
+ };
+ </script>
+ <body>
+ <iframe name="iframe0-300x200" width="300" height="200"></iframe>
+ <iframe name="iframe1-350x250" width="350" height="250"></iframe>
+ </body>
+</html>
diff --git a/tests/auto/core/qwebengineframe/resources/nesting-iframe.html b/tests/auto/core/qwebengineframe/resources/nesting-iframe.html
new file mode 100644
index 000000000..cd784e3dd
--- /dev/null
+++ b/tests/auto/core/qwebengineframe/resources/nesting-iframe.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<html>
+ <head><title>Test-title</title></head>
+ <body>
+ <iframe name="iframe2-parent" src="iframes.html"></iframe>
+ </body>
+</html>
diff --git a/tests/auto/core/qwebengineframe/tst_qwebengineframe.cpp b/tests/auto/core/qwebengineframe/tst_qwebengineframe.cpp
new file mode 100644
index 000000000..b70a655d3
--- /dev/null
+++ b/tests/auto/core/qwebengineframe/tst_qwebengineframe.cpp
@@ -0,0 +1,180 @@
+/*
+ Copyright (C) 2024 The Qt Company Ltd.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <util.h>
+
+#include <QtTest/QtTest>
+
+#include <QtWebEngineCore/qwebengineframe.h>
+
+class tst_QWebEngineFrame : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void mainFrame();
+ void findFrameByName();
+ void isValid();
+ void name();
+ void htmlName();
+ void children();
+ void childrenOfInvalidFrame();
+ void url();
+ void size();
+
+private:
+};
+
+void tst_QWebEngineFrame::mainFrame()
+{
+ QWebEnginePage page;
+ QSignalSpy loadSpy{ &page, SIGNAL(loadFinished(bool)) };
+ page.load(QUrl("qrc:/resources/frameset.html"));
+ QTRY_COMPARE(loadSpy.size(), 1);
+ auto frame = page.mainFrame();
+ QVERIFY(frame.isValid());
+}
+
+void tst_QWebEngineFrame::findFrameByName()
+{
+ QWebEnginePage page;
+ QSignalSpy loadSpy{ &page, SIGNAL(loadFinished(bool)) };
+ page.load(QUrl("qrc:/resources/iframes.html"));
+ QTRY_COMPARE(loadSpy.size(), 1);
+ auto maybeFrame = page.findFrameByName("test-subframe0");
+ QVERIFY(maybeFrame.has_value());
+ QCOMPARE(maybeFrame->name(), "test-subframe0");
+ QVERIFY(!page.findFrameByName("foobar").has_value());
+}
+
+void tst_QWebEngineFrame::isValid()
+{
+ QWebEnginePage page;
+ QSignalSpy loadSpy{ &page, SIGNAL(loadFinished(bool)) };
+ page.load(QUrl("qrc:/resources/iframes.html"));
+ QTRY_COMPARE(loadSpy.size(), 1);
+ auto firstPageSubframe = page.findFrameByName("test-subframe0");
+ QVERIFY(firstPageSubframe && firstPageSubframe->isValid());
+
+ page.load(QUrl("qrc:/resources/frameset.html"));
+ QTRY_COMPARE(loadSpy.size(), 2);
+ QVERIFY(!firstPageSubframe->isValid());
+}
+
+void tst_QWebEngineFrame::name()
+{
+ QWebEnginePage page;
+ QSignalSpy loadSpy{ &page, SIGNAL(loadFinished(bool)) };
+ page.load(QUrl("qrc:/resources/frameset.html"));
+ QTRY_COMPARE(loadSpy.size(), 1);
+ QCOMPARE(page.mainFrame().name(), "test-main-frame");
+ auto children = page.mainFrame().children();
+ QCOMPARE(children.at(0).name(), "test-subframe0");
+ QCOMPARE(children.at(1).name(), "test-subframe1");
+ QCOMPARE(children.at(2).name(), "test-subframe2");
+
+ page.load(QUrl("qrc:/resources/iframes.html"));
+ QTRY_COMPARE(loadSpy.size(), 2);
+ QVERIFY(!children.at(0).isValid());
+ QCOMPARE(children.at(0).name(), QString());
+}
+
+void tst_QWebEngineFrame::htmlName()
+{
+ 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();
+ QCOMPARE(children.at(0).name(), "test-subframe0");
+ QCOMPARE(children.at(0).htmlName(), "iframe0-300x200");
+ QCOMPARE(children.at(1).name(), "test-subframe1");
+ QCOMPARE(children.at(1).htmlName(), "iframe1-350x250");
+
+ page.load(QUrl("qrc:/resources/frameset.html"));
+ QTRY_COMPARE(loadSpy.size(), 2);
+ QVERIFY(!children.at(0).isValid());
+ QCOMPARE(children.at(0).htmlName(), QString());
+}
+
+void tst_QWebEngineFrame::children()
+{
+ QWebEnginePage page;
+ QSignalSpy loadSpy{ &page, SIGNAL(loadFinished(bool)) };
+ page.load(QUrl("qrc:/resources/frameset.html"));
+ QTRY_COMPARE(loadSpy.size(), 1);
+ auto frame = page.mainFrame();
+ auto children = frame.children();
+ QCOMPARE(children.size(), 3);
+ for (auto child : children) {
+ QVERIFY(child.isValid());
+ }
+}
+
+void tst_QWebEngineFrame::childrenOfInvalidFrame()
+{
+ QWebEnginePage page;
+ QSignalSpy loadSpy{ &page, SIGNAL(loadFinished(bool)) };
+ page.load(QUrl("qrc:/resources/nesting-iframe.html"));
+ QTRY_COMPARE(loadSpy.size(), 1);
+ auto nestedFrame = page.mainFrame().children().at(0);
+ QCOMPARE(nestedFrame.children().size(), 2);
+
+ page.load(QUrl("qrc:/resources/frameset.html"));
+ QTRY_COMPARE(loadSpy.size(), 2);
+ QVERIFY(!nestedFrame.isValid());
+ QVERIFY(nestedFrame.children().empty());
+}
+
+void tst_QWebEngineFrame::url()
+{
+ QWebEnginePage page;
+ QSignalSpy loadSpy{ &page, SIGNAL(loadFinished(bool)) };
+ page.load(QUrl("qrc:/resources/nesting-iframe.html"));
+ QTRY_COMPARE(loadSpy.size(), 1);
+ auto children = page.mainFrame().children();
+ QCOMPARE(children.at(0).url(), QUrl("qrc:/resources/iframes.html"));
+
+ page.load(QUrl("qrc:/resources/frameset.html"));
+ QTRY_COMPARE(loadSpy.size(), 2);
+ QVERIFY(!children.at(0).isValid());
+ QCOMPARE(children.at(0).url(), QUrl());
+}
+
+void tst_QWebEngineFrame::size()
+{
+ QWebEnginePage page;
+ QSignalSpy loadSpy{ &page, SIGNAL(loadFinished(bool)) };
+ page.load(QUrl("qrc:/resources/iframes.html"));
+ QTRY_COMPARE(loadSpy.size(), 1);
+ auto frame1 = *page.findFrameByName("test-subframe0");
+ auto size1 = frame1.size();
+ auto size2 = page.findFrameByName("test-subframe1")->size();
+ QCOMPARE(size1, QSizeF(300, 200));
+ QCOMPARE(size2, QSizeF(350, 250));
+
+ page.load(QUrl("qrc:/resources/frameset.html"));
+ QTRY_COMPARE(loadSpy.size(), 2);
+ QVERIFY(!frame1.isValid());
+ QCOMPARE(frame1.size(), QSizeF());
+}
+
+QTEST_MAIN(tst_QWebEngineFrame)
+
+#include "tst_qwebengineframe.moc"
diff --git a/tests/auto/core/qwebengineglobalsettings/CMakeLists.txt b/tests/auto/core/qwebengineglobalsettings/CMakeLists.txt
index fa81ba8df..dd2f28857 100644
--- a/tests/auto/core/qwebengineglobalsettings/CMakeLists.txt
+++ b/tests/auto/core/qwebengineglobalsettings/CMakeLists.txt
@@ -8,6 +8,7 @@ qt_internal_add_test(tst_qwebengineglobalsettings
SOURCES
tst_qwebengineglobalsettings.cpp
LIBRARIES
+ Qt::Network
Qt::WebEngineCore
Test::HttpServer
Qt::WebEngineWidgets
diff --git a/tests/auto/core/qwebengineglobalsettings/tst_qwebengineglobalsettings.cpp b/tests/auto/core/qwebengineglobalsettings/tst_qwebengineglobalsettings.cpp
index 0af85a711..5b6b64778 100644
--- a/tests/auto/core/qwebengineglobalsettings/tst_qwebengineglobalsettings.cpp
+++ b/tests/auto/core/qwebengineglobalsettings/tst_qwebengineglobalsettings.cpp
@@ -3,6 +3,8 @@
#include <QtTest>
#include <widgetutil.h>
+#include <QNetworkAccessManager>
+#include <QNetworkRequest>
#include <QWebEngineProfile>
#include <QWebEnginePage>
#include <QWebEngineGlobalSettings>
@@ -68,6 +70,15 @@ void tst_QWebEngineGlobalSettings::dnsOverHttps_data()
void tst_QWebEngineGlobalSettings::dnsOverHttps()
{
+ const QUrl url = QStringLiteral("https://google.com/");
+ // Verify network access with NAM because the result of loadFinished signal
+ // is used to verify that the DNS resolution was successful.
+ QNetworkAccessManager nam;
+ QSignalSpy namSpy(&nam, &QNetworkAccessManager::finished);
+ QScopedPointer<QNetworkReply> reply(nam.get(QNetworkRequest(url)));
+ if (!namSpy.wait(20000) || reply->error() != QNetworkReply::NoError)
+ QSKIP("Couldn't load page from network, skipping test.");
+
QFETCH(QWebEngineGlobalSettings::SecureDnsMode, dnsMode);
QFETCH(QString, uriTemplate);
QFETCH(bool, isMockDnsServerCalledExpected);
@@ -105,10 +116,8 @@ void tst_QWebEngineGlobalSettings::dnsOverHttps()
connect(&page, &QWebEnginePage::loadFinished, this,
[&isLoadSuccessful](bool ok) { isLoadSuccessful = ok; });
- page.load(QUrl("https://google.com/"));
- if (!loadSpy.wait(20000)) {
- QSKIP("Couldn't load page from network, skipping test.");
- }
+ page.load(url);
+ QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 1, 20000);
QTRY_COMPARE(isMockDnsServerCalled, isMockDnsServerCalledExpected);
QCOMPARE(isLoadSuccessful, isDnsResolutionSuccessExpected);
diff --git a/tests/auto/quick/publicapi/tst_publicapi.cpp b/tests/auto/quick/publicapi/tst_publicapi.cpp
index cfa75f0bf..d3358cab4 100644
--- a/tests/auto/quick/publicapi/tst_publicapi.cpp
+++ b/tests/auto/quick/publicapi/tst_publicapi.cpp
@@ -25,6 +25,7 @@
#include <QtWebEngineCore/QWebEngineScript>
#include <QtWebEngineCore/QWebEngineLoadingInfo>
#include <QtWebEngineCore/QWebEngineWebAuthUxRequest>
+#include <QtWebEngineCore/QWebEngineFrame>
#include <private/qquickwebengineview_p.h>
#include <private/qquickwebengineaction_p.h>
#include <private/qquickwebengineclientcertificateselection_p.h>
@@ -76,6 +77,7 @@ static const QList<const QMetaObject *> typesToCheck = QList<const QMetaObject *
<< &QQuickWebEngineTouchSelectionMenuRequest::staticMetaObject
<< &QWebEngineWebAuthUxRequest::staticMetaObject
<< &QWebEngineWebAuthPinRequest::staticMetaObject
+ << &QWebEngineFrame::staticMetaObject
;
static QList<QMetaEnum> knownEnumNames = QList<QMetaEnum>()
@@ -132,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"
@@ -328,6 +331,7 @@ static const QStringList expectedAPI = QStringList()
<< "QWebEngineNavigationRequest.action --> QWebEngineNavigationRequest::NavigationRequestAction"
<< "QWebEngineNavigationRequest.actionChanged() --> void"
<< "QWebEngineNavigationRequest.isMainFrame --> bool"
+ << "QWebEngineNavigationRequest.hasFormData --> bool"
<< "QWebEngineNavigationRequest.navigationType --> QWebEngineNavigationRequest::NavigationType"
<< "QWebEngineNavigationRequest.url --> QUrl"
<< "QWebEngineNavigationRequest.AcceptRequest --> NavigationRequestAction"
@@ -714,6 +718,7 @@ static const QStringList expectedAPI = QStringList()
<< "QQuickWebEngineView.featurePermissionRequested(QUrl,QQuickWebEngineView::Feature) --> void"
<< "QQuickWebEngineView.fileDialogRequested(QQuickWebEngineFileDialogRequest*) --> void"
<< "QQuickWebEngineView.fileSystemAccessRequested(QWebEngineFileSystemAccessRequest) --> void"
+ << "QQuickWebEngineView.findFrameByName(QString) --> QWebEngineFrame"
<< "QQuickWebEngineView.findText(QString) --> void"
<< "QQuickWebEngineView.findText(QString,FindFlags) --> void"
<< "QQuickWebEngineView.findText(QString,FindFlags,QJSValue) --> void"
@@ -743,6 +748,7 @@ static const QStringList expectedAPI = QStringList()
<< "QQuickWebEngineView.loadProgressChanged() --> void"
<< "QQuickWebEngineView.loading --> bool"
<< "QQuickWebEngineView.loadingChanged(QWebEngineLoadingInfo) --> void"
+ << "QQuickWebEngineView.mainFrame --> QWebEngineFrame"
<< "QQuickWebEngineView.navigationRequested(QWebEngineNavigationRequest*) --> void"
<< "QQuickWebEngineView.newWindowRequested(QQuickWebEngineNewWindowRequest*) --> void"
<< "QQuickWebEngineView.AcceptRequest --> NavigationRequestAction"
@@ -879,6 +885,11 @@ static const QStringList expectedAPI = QStringList()
<< "QQuickWebEngineSettings.DisallowImageAnimation --> ImageAnimationPolicy"
<< "QQuickWebEngineSettings.imageAnimationPolicy --> QQuickWebEngineSettings::ImageAnimationPolicy"
<< "QQuickWebEngineSettings.imageAnimationPolicyChanged() --> void"
+ << "QWebEngineFrame.htmlName --> QString"
+ << "QWebEngineFrame.isValid --> bool"
+ << "QWebEngineFrame.name --> QString"
+ << "QWebEngineFrame.size --> QSizeF"
+ << "QWebEngineFrame.url --> QUrl"
;
static bool isCheckedEnum(QMetaType t)
diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
index 39a28759c..f1d64776b 100644
--- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
+++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
@@ -117,6 +117,7 @@ private Q_SLOTS:
void comboBoxPopupPositionAfterChildMove_data();
void comboBoxPopupPositionAfterChildMove();
void acceptNavigationRequest();
+ void acceptNavigationRequestWithFormData();
void acceptNavigationRequestNavigationType();
void acceptNavigationRequestRelativeToNothing();
#ifndef Q_OS_MACOS
@@ -636,6 +637,7 @@ public:
QWebEngineNavigationRequest::NavigationType type;
QUrl url;
bool isMainFrame;
+ bool hasFormData;
};
QList<Navigation> navigations;
@@ -653,6 +655,7 @@ private Q_SLOTS:
n.url = request.url();
n.type = request.navigationType();
n.isMainFrame = request.isMainFrame();
+ n.hasFormData = request.hasFormData();
navigations.append(n);
request.accept();
}
@@ -670,9 +673,33 @@ private Q_SLOTS:
}
};
-void tst_QWebEnginePage::acceptNavigationRequestNavigationType()
+void tst_QWebEnginePage::acceptNavigationRequestWithFormData()
{
+ QWebEngineProfile profile;
+ profile.installUrlSchemeHandler("echo", new EchoingUrlSchemeHandler(&profile));
+ TestPage page(nullptr, &profile);
+ QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool)));
+
+ page.setHtml(QString("<html><body><form name='tstform' action='foo' method='post'>"
+ "<input type='text'><input type='submit'></form></body></html>"),
+ QUrl("echo:/"));
+ QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 1, 20000);
+ QCOMPARE(page.navigations[0].type, QWebEngineNavigationRequest::TypedNavigation);
+ QVERIFY(!page.navigations[0].hasFormData);
+ evaluateJavaScriptSync(&page, "tstform.submit();");
+ QTRY_COMPARE(loadSpy.size(), 2);
+ QCOMPARE(page.navigations[1].type, QWebEngineNavigationRequest::FormSubmittedNavigation);
+ QVERIFY(page.navigations[1].hasFormData);
+
+ page.triggerAction(QWebEnginePage::Reload);
+ QTRY_COMPARE(loadSpy.size(), 3);
+ QCOMPARE(page.navigations[2].type, QWebEngineNavigationRequest::ReloadNavigation);
+ QVERIFY(page.navigations[2].hasFormData);
+}
+
+void tst_QWebEnginePage::acceptNavigationRequestNavigationType()
+{
TestPage page;
QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool)));
diff --git a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
index 095d4c8f2..cebdaaa47 100644
--- a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
+++ b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
@@ -188,6 +188,7 @@ void tst_QWebEngineProfile::clearDataFromCache()
QVERIFY(server.start());
AutoDir cacheDir("./tst_QWebEngineProfile_clearDataFromCache");
+ QVERIFY(!cacheDir.exists("Cache"));
QWebEngineProfile profile(QStringLiteral("clearDataFromCache"));
QSignalSpy cacheSpy(&profile, &QWebEngineProfile::clearHttpCacheCompleted);
@@ -201,9 +202,14 @@ void tst_QWebEngineProfile::clearDataFromCache()
QVERIFY(cacheDir.exists("Cache"));
qint64 sizeBeforeClear = totalSize(cacheDir);
+ QCOMPARE_GT(sizeBeforeClear, 0);
profile.clearHttpCache();
QTRY_COMPARE(cacheSpy.size(), 1);
- QVERIFY(sizeBeforeClear > totalSize(cacheDir));
+#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/widgets/CMakeLists.txt b/tests/manual/widgets/CMakeLists.txt
index 2baf669d8..7c19f9e43 100644
--- a/tests/manual/widgets/CMakeLists.txt
+++ b/tests/manual/widgets/CMakeLists.txt
@@ -1,7 +1,9 @@
add_subdirectory(inputmethods)
add_subdirectory(geolocation)
add_subdirectory(touchbrowser)
-add_subdirectory(webgl)
+if(QT_FEATURE_opengl)
+ add_subdirectory(webgl)
+endif()
if(TARGET Qt6::HttpServer)
add_subdirectory(webrtc)
endif()