diff options
Diffstat (limited to 'src')
131 files changed, 3105 insertions, 961 deletions
diff --git a/src/3rdparty b/src/3rdparty -Subproject 814db44bc99f79d0c4a847e0cac4a398034ee2f +Subproject e2c589700c312d35a503a15c30ea6432d77cbca diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 8ba77607b..d43188813 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -349,7 +349,8 @@ foreach(arch ${archs}) devtools_skip_typecheck=false use_static_angle=true use_perfetto_client_library=false - trial_comparison_cert_verifier_supported=false + enable_extensions_legacy_ipc=true + enable_bound_session_credentials=false ) extend_gn_list(gnArgArg ARGS use_v8_context_snapshot v8_use_external_startup_data @@ -577,6 +578,7 @@ target_include_directories(WebEngineCore PRIVATE ${buildDir}/$<CONFIG>/${arch}/gen ${buildDir}/$<CONFIG>/${arch}/gen/third_party/perfetto ${buildDir}/$<CONFIG>/${arch}/gen/third_party/perfetto/build_config + ${buildDir}/$<CONFIG>/${arch}/gen/base/allocator/partition_allocator/src ) set(stamps QtWebEngineCore.stamp) @@ -632,7 +634,9 @@ if(QT_FEATURE_webengine_spellchecker AND NOT CMAKE_CROSSCOMPILING) target_include_directories(${dict_target_name} PRIVATE ../3rdparty/chromium ../3rdparty/chromium/third_party/boringssl/src/include + ../3rdparty/chromium/base/allocator/partition_allocator/src ${buildDir}/$<CONFIG>/${arch}/gen + ${buildDir}/$<CONFIG>/${arch}/gen/base/allocator/partition_allocator/src ) add_gn_build_artifacts_to_target( CMAKE_TARGET ${dict_target_name} diff --git a/src/core/api/CMakeLists.txt b/src/core/api/CMakeLists.txt index c06f5e4ce..2a06baec6 100644 --- a/src/core/api/CMakeLists.txt +++ b/src/core/api/CMakeLists.txt @@ -29,6 +29,7 @@ qt_internal_add_module(WebEngineCore qwebenginenewwindowrequest.cpp qwebenginenewwindowrequest.h qwebenginenewwindowrequest_p.h qwebenginenotification.cpp qwebenginenotification.h qwebenginepage.cpp qwebenginepage.h qwebenginepage_p.h + qwebenginepermission.cpp qwebenginepermission.h qwebenginepermission_p.h qwebengineprofile.cpp qwebengineprofile.h qwebengineprofile_p.h qwebenginequotarequest.cpp qwebenginequotarequest.h qwebengineregisterprotocolhandlerrequest.cpp qwebengineregisterprotocolhandlerrequest.h @@ -50,6 +51,7 @@ qt_internal_add_module(WebEngineCore ../../3rdparty/chromium/third_party/abseil-cpp ../../3rdparty/chromium/third_party/perfetto/include ../../3rdparty/chromium/third_party/boringssl/src/include + ../../3rdparty/chromium/base/allocator/partition_allocator/src LIBRARIES Qt::CorePrivate Qt::GuiPrivate @@ -66,10 +68,13 @@ qt_internal_add_module(WebEngineCore set_target_properties(WebEngineCore PROPERTIES QTWEBENGINEPROCESS_NAME ${qtWebEngineProcessName}) set_target_properties(WebEngineCore PROPERTIES CXX_STANDARD 20) - # Chromium included headers are not clean qt_skip_warnings_are_errors(WebEngineCore) +if(MSVC AND NOT CLANG) + target_compile_options(WebEngineCore PRIVATE "/Zc:preprocessor") +endif() + if(CLANG OR GCC) target_compile_options(WebEngineCore PRIVATE "-Wno-unused-parameter" diff --git a/src/core/api/qwebenginecertificateerror.cpp b/src/core/api/qwebenginecertificateerror.cpp index 90d8a542d..85c5d5127 100644 --- a/src/core/api/qwebenginecertificateerror.cpp +++ b/src/core/api/qwebenginecertificateerror.cpp @@ -88,6 +88,19 @@ QUrl QWebEngineCertificateError::url() const } /*! + \property QWebEngineCertificateError::isMainFrame + \since 6.8 + + Returns whether the certificate error comes from the main frame. If false, + the error comes from a sub-resource and most likely needs to be rejected without + user input. +*/ +bool QWebEngineCertificateError::isMainFrame() const +{ + return d->isMainFrame(); +} + +/*! Returns the type of the error. \sa description(), isOverridable() diff --git a/src/core/api/qwebenginecertificateerror.h b/src/core/api/qwebenginecertificateerror.h index c4a3585f4..3eef3dcca 100644 --- a/src/core/api/qwebenginecertificateerror.h +++ b/src/core/api/qwebenginecertificateerror.h @@ -24,6 +24,7 @@ class Q_WEBENGINECORE_EXPORT QWebEngineCertificateError Q_PROPERTY(Type type READ type CONSTANT FINAL) Q_PROPERTY(QString description READ description CONSTANT FINAL) Q_PROPERTY(bool overridable READ isOverridable CONSTANT FINAL) + Q_PROPERTY(bool isMainFrame READ isMainFrame CONSTANT FINAL REVISION(6, 8)) public: QWebEngineCertificateError(const QWebEngineCertificateError &other); @@ -57,6 +58,7 @@ public: QUrl url() const; bool isOverridable() const; QString description() const; + bool isMainFrame() const; Q_INVOKABLE void defer(); Q_INVOKABLE void rejectCertificate(); diff --git a/src/core/api/qwebengineframe.cpp b/src/core/api/qwebengineframe.cpp index edd89d663..fa2cbb507 100644 --- a/src/core/api/qwebengineframe.cpp +++ b/src/core/api/qwebengineframe.cpp @@ -3,6 +3,11 @@ #include "qwebengineframe.h" +#include "qwebenginescript.h" +#include <QtQml/qqmlengine.h> +#include <QtGui/qpagelayout.h> +#include <QtGui/qpageranges.h> + #include "web_contents_adapter_client.h" #include "web_contents_adapter.h" @@ -101,6 +106,146 @@ QSizeF QWebEngineFrame::size() const return m_adapterClient->webContentsAdapter()->frameSize(m_id); } +/*! + Returns \c{true} if this object represents the page's main frame; \c{false} otherwise. +*/ +bool QWebEngineFrame::isMainFrame() const +{ + return m_adapterClient->webContentsAdapter()->mainFrameId() == m_id; +} + +/*! \fn void QWebEngineFrame::runJavaScript(const QString &script, const std::function<void(const QVariant &)> &callback) + \fn void QWebEngineFrame::runJavaScript(const QString &script, quint32 worldId) + \fn void QWebEngineFrame::runJavaScript(const QString &script, quint32 worldId, const + std::function<void(const QVariant &)> &callback) + + Runs the JavaScript code contained in \a script on this frame, without checking + whether the DOM of the page has been constructed. + To avoid conflicts with other scripts executed on the page, the world in + which the script is run is specified by \a worldId. The world ID values are + the same as provided by QWebEngineScript::ScriptWorldId, and between \c 0 + and \c 256. If you leave out the \c world ID, the script is run in the + \c MainWorld. + When the script has been executed, \a callback is called with the result of the last + executed statement. \c callback can be any of a function pointer, a functor or a lambda, + and it is expected to take a QVariant parameter. For example: + \code + page.runJavaScript("document.title", [](const QVariant &v) { qDebug() << v.toString(); }); + \endcode + Only plain data can be returned from JavaScript as the result value. + Supported data types include all of the JSON data types as well as, for + example, \c{Date} and \c{ArrayBuffer}. Unsupported data types include, for + example, \c{Function} and \c{Promise}. + \warning Do not execute lengthy routines in the callback function, because it might block the + rendering of the web engine page. + \warning We guarantee that the \a callback is always called, but it might be + done during page destruction. When QWebEnginePage is deleted, the callback is triggered with an + invalid value and it is not safe to use the corresponding QWebEnginePage or QWebEngineView + instance inside it. + \sa QWebEngineScript::ScriptWorldId, QWebEnginePage::runJavaScript, {Script Injection} + */ +void QWebEngineFrame::runJavaScript(const QString &script, + const std::function<void(const QVariant &)> &callback) +{ + runJavaScript(script, QWebEngineScript::MainWorld, callback); +} + +void QWebEngineFrame::runJavaScript(const QString &script, quint32 worldId, + const std::function<void(const QVariant &)> &callback) +{ + m_adapterClient->runJavaScript(script, worldId, m_id, callback); +} + +void QWebEngineFrame::runJavaScript(const QString &script, quint32 worldId) +{ + runJavaScript(script, worldId, std::function<void(const QVariant &)>{}); +} + +void QWebEngineFrame::runJavaScript(const QString &script, const QJSValue &callback) +{ + runJavaScript(script, QWebEngineScript::MainWorld, callback); +} + +void QWebEngineFrame::runJavaScript(const QString &script, quint32 worldId, + const QJSValue &callback) +{ + std::function<void(const QVariant &)> wrappedCallback; + if (!callback.isUndefined()) { + const QObject *holdingObject = m_adapterClient->holdingQObject(); + wrappedCallback = [holdingObject, callback](const QVariant &result) { + if (auto engine = qmlEngine(holdingObject)) { + QJSValueList args; + args.append(engine->toScriptValue(result)); + callback.call(args); + } else { + qWarning("No QML engine found to execute runJavaScript() callback"); + } + }; + } + runJavaScript(script, worldId, wrappedCallback); +} + +/*! + Renders the current content of the frame into a PDF document and saves it in the location + specified in \a filePath. Printing uses a page size of A4, portrait layout, and includes the + full range of pages. + + This method issues an asynchronous request for printing the web page into a PDF and returns + immediately. To be informed about the result of the request, connect to the \l + QWebEnginePage::pdfPrintingFinished() signal. + + \note The \l QWebEnginePage::Stop web action can be used to interrupt this asynchronous + operation. + + If a file already exists at the provided file path, it will be overwritten. + + \sa QWebEnginePage::pdfPrintingFinished() + */ +void QWebEngineFrame::printToPdf(const QString &filePath) +{ + QPageLayout layout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF()); + m_adapterClient->printToPdf(filePath, layout, QPageRanges(), m_id); +} + +/*! + Renders the current content of the frame into a PDF document and returns a byte array containing + the PDF data as parameter to \a callback. Printing uses a page size of A4, portrait layout, and + includes the full range of pages. + + The \a callback must take a const reference to a QByteArray as parameter. If printing was + successful, this byte array will contain the PDF data, otherwise, the byte array will be empty. + + \note The \l QWebEnginePage::Stop web action can be used to interrupt this operation. +*/ +void QWebEngineFrame::printToPdf(const std::function<void(const QByteArray &)> &callback) +{ + std::function wrappedCallback = [callback](QSharedPointer<QByteArray> result) { + if (callback) + callback(result ? *result : QByteArray()); + }; + QPageLayout layout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF()); + m_adapterClient->printToPdf(std::move(wrappedCallback), layout, QPageRanges(), m_id); +} + +void QWebEngineFrame::printToPdf(const QJSValue &callback) +{ + std::function<void(QSharedPointer<QByteArray>)> wrappedCallback; + if (!callback.isUndefined()) { + const QObject *holdingObject = m_adapterClient->holdingQObject(); + wrappedCallback = [holdingObject, callback](QSharedPointer<QByteArray> result) { + if (auto engine = qmlEngine(holdingObject)) { + QJSValueList args; + args.append(engine->toScriptValue(result ? *result : QByteArray())); + callback.call(args); + } else { + qWarning("No QML engine found to execute runJavaScript() callback"); + } + }; + } + QPageLayout layout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF()); + m_adapterClient->printToPdf(std::move(wrappedCallback), layout, QPageRanges(), 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, diff --git a/src/core/api/qwebengineframe.h b/src/core/api/qwebengineframe.h index e58961848..b6953cdd2 100644 --- a/src/core/api/qwebengineframe.h +++ b/src/core/api/qwebengineframe.h @@ -6,6 +6,7 @@ #include <QtWebEngineCore/qtwebenginecoreglobal.h> #include <QtQml/qqmlregistration.h> +#include <QtQml/qjsvalue.h> #include <QtCore/qcompare.h> #include <QtCore/QList> #include <QtCore/QSizeF> @@ -27,6 +28,7 @@ class Q_WEBENGINECORE_EXPORT QWebEngineFrame Q_PROPERTY(QString htmlName READ htmlName FINAL) Q_PROPERTY(QUrl url READ url FINAL) Q_PROPERTY(QSizeF size READ size FINAL) + Q_PROPERTY(bool isMainFrame READ isMainFrame FINAL) public: QML_VALUE_TYPE(webEngineFrame) @@ -38,6 +40,20 @@ public: QList<QWebEngineFrame> children() const; QUrl url() const; QSizeF size() const; + bool isMainFrame() const; + + void runJavaScript(const QString &script, + const std::function<void(const QVariant &)> &callback); + void runJavaScript(const QString &script, quint32 worldId, + const std::function<void(const QVariant &)> &callback); + Q_INVOKABLE void runJavaScript(const QString &script, quint32 worldId = 0); + Q_INVOKABLE void runJavaScript(const QString &script, const QJSValue &callback); + Q_INVOKABLE void runJavaScript(const QString &script, quint32 worldId, + const QJSValue &callback); + + Q_INVOKABLE void printToPdf(const QString &filePath); + void printToPdf(const std::function<void(const QByteArray &)> &callback); + Q_INVOKABLE void printToPdf(const QJSValue &callback); friend inline bool comparesEqual(const QWebEngineFrame &lhs, const QWebEngineFrame &rhs) noexcept @@ -49,7 +65,9 @@ public: private: friend class QWebEnginePage; + friend class QWebEnginePagePrivate; friend class QQuickWebEngineView; + friend class QQuickWebEngineViewPrivate; QWebEngineFrame(QtWebEngineCore::WebContentsAdapterClient *page, quint64 id); diff --git a/src/core/api/qwebenginepage.cpp b/src/core/api/qwebenginepage.cpp index c2a737d72..f0260fd0d 100644 --- a/src/core/api/qwebenginepage.cpp +++ b/src/core/api/qwebenginepage.cpp @@ -24,6 +24,7 @@ #include "qwebenginescriptcollection_p.h" #include "qwebenginesettings.h" #include "qwebenginewebauthuxrequest.h" +#include "qwebenginepermission_p.h" #include "authentication_dialog_controller.h" #include "autofill_popup_controller.h" @@ -199,6 +200,12 @@ void QWebEnginePagePrivate::iconChanged(const QUrl &url) Q_EMIT q->iconChanged(iconUrl.isEmpty() ? QIcon() : adapter->icon()); } +void QWebEnginePagePrivate::zoomFactorChanged(qreal factor) +{ + Q_Q(QWebEnginePage); + Q_EMIT q->zoomFactorChanged(factor); +} + void QWebEnginePagePrivate::loadProgressChanged(int progress) { Q_Q(QWebEnginePage); @@ -268,6 +275,20 @@ void QWebEnginePagePrivate::loadFinished(QWebEngineLoadingInfo info) }); } +void QWebEnginePagePrivate::printToPdf(const QString &filePath, const QPageLayout &layout, + const QPageRanges &ranges, quint64 frameId) +{ + adapter->printToPDF(layout, ranges, filePath, frameId); +} + +void QWebEnginePagePrivate::printToPdf(std::function<void(QSharedPointer<QByteArray>)> &&callback, + const QPageLayout &layout, const QPageRanges &ranges, + quint64 frameId) +{ + adapter->printToPDFCallbackResult(std::move(callback), layout, ranges, /*colorMode*/ true, + /*useCustomMargins*/ true, frameId); +} + void QWebEnginePagePrivate::didPrintPageToPdf(const QString &filePath, bool success) { Q_Q(QWebEnginePage); @@ -489,10 +510,16 @@ void QWebEnginePagePrivate::windowCloseRejected() // Do nothing for now. } -void QWebEnginePagePrivate::didRunJavaScript(quint64 requestId, const QVariant& result) +void QWebEnginePagePrivate::runJavaScript(const QString &script, quint32 worldId, quint64 frameId, + const std::function<void(const QVariant &)> &callback) { - if (auto callback = m_variantCallbacks.take(requestId)) - callback(result); + ensureInitialized(); + if (adapter->lifecycleState() == WebContentsAdapter::LifecycleState::Discarded) { + qWarning("runJavaScript: disabled in Discarded state"); + if (callback) + callback(QVariant()); + } else + adapter->runJavaScript(script, worldId, frameId, callback); } void QWebEnginePagePrivate::didFetchDocumentMarkup(quint64 requestId, const QString& result) @@ -507,27 +534,18 @@ void QWebEnginePagePrivate::didFetchDocumentInnerText(quint64 requestId, const Q callback(result); } -void QWebEnginePagePrivate::didPrintPage(quint64 requestId, QSharedPointer<QByteArray> result) +void QWebEnginePagePrivate::didPrintPage(QSharedPointer<QByteArray> result) { #if QT_CONFIG(webengine_printing_and_pdf) - // If no currentPrinter is set that means that were printing to PDF only. - if (!currentPrinter) { - if (!result.data()) - return; - if (auto callback = m_pdfResultCallbacks.take(requestId)) - callback(*(result.data())); - return; - } - + Q_ASSERT(currentPrinter); if (view) view->didPrintPage(currentPrinter, result); else currentPrinter = nullptr; #else - // we should never enter this branch, but just for safe-keeping... + // should not get here Q_UNUSED(result); - if (auto callback = m_pdfResultCallbacks.take(requestId)) - callback(QByteArray()); + Q_ASSERT(false); #endif } @@ -572,50 +590,121 @@ void QWebEnginePagePrivate::showColorDialog(QSharedPointer<ColorChooserControlle void QWebEnginePagePrivate::runMediaAccessPermissionRequest(const QUrl &securityOrigin, WebContentsAdapterClient::MediaRequestFlags requestFlags) { Q_Q(QWebEnginePage); - QWebEnginePage::Feature feature; - if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture) && - requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture)) - feature = QWebEnginePage::MediaAudioVideoCapture; + QWebEnginePermission::Feature feature; + + if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture) + && requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture)) + feature = QWebEnginePermission::MediaAudioVideoCapture; else if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture)) - feature = QWebEnginePage::MediaAudioCapture; + feature = QWebEnginePermission::MediaAudioCapture; else if (requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture)) - feature = QWebEnginePage::MediaVideoCapture; - else if (requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopAudioCapture) && - requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture)) - feature = QWebEnginePage::DesktopAudioVideoCapture; + feature = QWebEnginePermission::MediaVideoCapture; + else if (requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopAudioCapture) + && requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture)) + feature = QWebEnginePermission::DesktopAudioVideoCapture; else // if (requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture)) - feature = QWebEnginePage::DesktopVideoCapture; - Q_EMIT q->featurePermissionRequested(securityOrigin, feature); + feature = QWebEnginePermission::DesktopVideoCapture; + + Q_EMIT q->permissionRequested(createFeaturePermissionObject(securityOrigin, feature)); + +#if QT_DEPRECATED_SINCE(6, 8) + QT_WARNING_PUSH + QT_WARNING_DISABLE_DEPRECATED + QWebEnginePage::Feature deprecatedFeature; + + if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture) + && requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture)) + deprecatedFeature = QWebEnginePage::MediaAudioVideoCapture; + else if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture)) + deprecatedFeature = QWebEnginePage::MediaAudioCapture; + else if (requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture)) + deprecatedFeature = QWebEnginePage::MediaVideoCapture; + else if (requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopAudioCapture) + && requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture)) + deprecatedFeature = QWebEnginePage::DesktopAudioVideoCapture; + else // if (requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture)) + deprecatedFeature = QWebEnginePage::DesktopVideoCapture; + + Q_EMIT q->featurePermissionRequested(securityOrigin, deprecatedFeature); + QT_WARNING_POP +#endif // QT_DEPRECATED_SINCE(6, 8) } -static QWebEnginePage::Feature toFeature(QtWebEngineCore::ProfileAdapter::PermissionType type) +#if QT_DEPRECATED_SINCE(6, 8) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED +static QWebEnginePage::Feature toDeprecatedFeature(QWebEnginePermission::Feature feature) { - switch (type) { - case QtWebEngineCore::ProfileAdapter::NotificationPermission: + switch (feature) { + case QWebEnginePermission::Feature::Notifications: return QWebEnginePage::Notifications; - case QtWebEngineCore::ProfileAdapter::GeolocationPermission: + case QWebEnginePermission::Feature::Geolocation: return QWebEnginePage::Geolocation; - case QtWebEngineCore::ProfileAdapter::ClipboardReadWrite: + case QWebEnginePermission::Feature::ClipboardReadWrite: return QWebEnginePage::ClipboardReadWrite; - case QtWebEngineCore::ProfileAdapter::LocalFontsPermission: + case QWebEnginePermission::Feature::LocalFontsAccess: return QWebEnginePage::LocalFontsAccess; - default: + case QWebEnginePermission::Feature::MediaAudioCapture: + return QWebEnginePage::MediaAudioCapture; + case QWebEnginePermission::Feature::MediaVideoCapture: + return QWebEnginePage::MediaVideoCapture; + case QWebEnginePermission::Feature::MediaAudioVideoCapture: + return QWebEnginePage::MediaAudioVideoCapture; + case QWebEnginePermission::Feature::DesktopVideoCapture: + return QWebEnginePage::DesktopVideoCapture; + case QWebEnginePermission::Feature::DesktopAudioVideoCapture: + return QWebEnginePage::DesktopAudioVideoCapture; + case QWebEnginePermission::Feature::MouseLock: + return QWebEnginePage::MouseLock; + case QWebEnginePermission::Feature::Unsupported: break; } + Q_UNREACHABLE(); return QWebEnginePage::Feature(-1); } +QT_WARNING_POP +#endif // QT_DEPRECATED_SINCE(6, 8) -void QWebEnginePagePrivate::runFeaturePermissionRequest(QtWebEngineCore::ProfileAdapter::PermissionType permission, const QUrl &securityOrigin) +void QWebEnginePagePrivate::runFeaturePermissionRequest(QWebEnginePermission::Feature feature, const QUrl &securityOrigin) { Q_Q(QWebEnginePage); - Q_EMIT q->featurePermissionRequested(securityOrigin, toFeature(permission)); + switch (feature) { + case QWebEnginePermission::Notifications: + case QWebEnginePermission::Geolocation: + case QWebEnginePermission::ClipboardReadWrite: + case QWebEnginePermission::LocalFontsAccess: + Q_EMIT q->permissionRequested(createFeaturePermissionObject(securityOrigin, feature)); +#if QT_DEPRECATED_SINCE(6, 8) + QT_WARNING_PUSH + QT_WARNING_DISABLE_DEPRECATED + Q_EMIT q->featurePermissionRequested(securityOrigin, toDeprecatedFeature(feature)); + QT_WARNING_POP +#endif // QT_DEPRECATED_SINCE(6, 8) + return; + case QWebEnginePermission::MouseLock: + case QWebEnginePermission::MediaAudioCapture: + case QWebEnginePermission::MediaVideoCapture: + case QWebEnginePermission::MediaAudioVideoCapture: + case QWebEnginePermission::DesktopAudioVideoCapture: + case QWebEnginePermission::DesktopVideoCapture: + case QWebEnginePermission::Unsupported: + Q_UNREACHABLE(); + return; + } } void QWebEnginePagePrivate::runMouseLockPermissionRequest(const QUrl &securityOrigin) { Q_Q(QWebEnginePage); + Q_EMIT q->permissionRequested(createFeaturePermissionObject(securityOrigin, QWebEnginePermission::MouseLock)); + +#if QT_DEPRECATED_SINCE(6, 8) + QT_WARNING_PUSH + QT_WARNING_DISABLE_DEPRECATED Q_EMIT q->featurePermissionRequested(securityOrigin, QWebEnginePage::MouseLock); + QT_WARNING_POP +#endif // QT_DEPRECATED_SINCE(6, 8) } void QWebEnginePagePrivate::runRegisterProtocolHandlerRequest(QWebEngineRegisterProtocolHandlerRequest request) @@ -804,6 +893,12 @@ void QWebEnginePagePrivate::showWebAuthDialog(QWebEngineWebAuthUxRequest *reques Q_EMIT q->webAuthUxRequested(request); } +QWebEnginePermission QWebEnginePagePrivate::createFeaturePermissionObject(const QUrl &securityOrigin, QWebEnginePermission::Feature feature) +{ + auto *returnPrivate = new QWebEnginePermissionPrivate{securityOrigin, feature, adapter, profileAdapter()}; + return QWebEnginePermission(returnPrivate); +} + QWebEnginePage::QWebEnginePage(QObject* parent) : QObject(parent) , d_ptr(new QWebEnginePagePrivate()) @@ -971,11 +1066,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(); } } @@ -1652,11 +1745,14 @@ void QWebEnginePagePrivate::setToolTip(const QString &toolTipText) \fn void QWebEnginePage::printRequested() \since 5.12 - This signal is emitted when the JavaScript \c{window.print()} method is called or the user pressed the print - button of PDF viewer plugin. + This signal is emitted when the JavaScript \c{window.print()} method is called on the main + frame, or the user pressed the print button of PDF viewer plugin. Typically, the signal handler can simply call printToPdf(). - \sa printToPdf() + Since 6.8, this signal is only emitted for the main frame, instead of being emitted for any + frame that requests printing. + + \sa printToPdf(), printRequestedByFrame() */ void QWebEnginePagePrivate::printRequested() @@ -1669,6 +1765,25 @@ void QWebEnginePagePrivate::printRequested() view->printRequested(); } +/*! + \fn void QWebEnginePage::printRequestedByFrame(QWebEngineFrame frame) + \since 6.8 + + This signal is emitted when the JavaScript \c{window.print()} method is called on \a frame. + If the frame is the main frame, \c{printRequested} is emitted instead. + + \sa printRequested(), printToPdf(), QWebEngineFrame::printToPdf() +*/ + +void QWebEnginePagePrivate::printRequestedByFrame(quint64 frameId) +{ + Q_Q(QWebEnginePage); + QWebEngineFrame frame(this, frameId); + QTimer::singleShot(0, q, [q, frame]() { Q_EMIT q->printRequestedByFrame(frame); }); + if (view) + view->printRequestedByFrame(frame); +} + QtWebEngineCore::TouchHandleDrawableDelegate * QWebEnginePagePrivate::createTouchHandleDelegate(const QMap<int, QImage> &images) { @@ -1736,104 +1851,64 @@ void QWebEnginePage::setUrlRequestInterceptor(QWebEngineUrlRequestInterceptor *i d->adapter->setRequestInterceptor(interceptor); } +#if QT_DEPRECATED_SINCE(6, 8) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED void QWebEnginePage::setFeaturePermission(const QUrl &securityOrigin, QWebEnginePage::Feature feature, QWebEnginePage::PermissionPolicy policy) { Q_D(QWebEnginePage); - if (policy == PermissionUnknown) { - switch (feature) { - case MediaAudioVideoCapture: - case MediaAudioCapture: - case MediaVideoCapture: - case DesktopAudioVideoCapture: - case DesktopVideoCapture: - case MouseLock: - break; - case Geolocation: - d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::GeolocationPermission, ProfileAdapter::AskPermission); - break; - case Notifications: - d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::NotificationPermission, ProfileAdapter::AskPermission); - break; - case ClipboardReadWrite: - d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::ClipboardReadWrite, - ProfileAdapter::AskPermission); - break; - case LocalFontsAccess: - d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::LocalFontsPermission, ProfileAdapter::AskPermission); - break; - } - return; + QWebEnginePermission::Feature f; + QWebEnginePermission::State s; + + switch (feature) { + case QWebEnginePage::Notifications: + f = QWebEnginePermission::Notifications; + break; + case QWebEnginePage::Geolocation: + f = QWebEnginePermission::Geolocation; + break; + case QWebEnginePage::MediaAudioCapture: + f = QWebEnginePermission::MediaAudioCapture; + break; + case QWebEnginePage::MediaVideoCapture: + f = QWebEnginePermission::MediaVideoCapture; + break; + case QWebEnginePage::MediaAudioVideoCapture: + f = QWebEnginePermission::MediaAudioVideoCapture; + break; + case QWebEnginePage::MouseLock: + f = QWebEnginePermission::MouseLock; + break; + case QWebEnginePage::DesktopVideoCapture: + f = QWebEnginePermission::DesktopVideoCapture; + break; + case QWebEnginePage::DesktopAudioVideoCapture: + f = QWebEnginePermission::DesktopAudioVideoCapture; + break; + case QWebEnginePage::ClipboardReadWrite: + f = QWebEnginePermission::ClipboardReadWrite; + break; + case QWebEnginePage::LocalFontsAccess: + f = QWebEnginePermission::LocalFontsAccess; + break; } - const WebContentsAdapterClient::MediaRequestFlags audioVideoCaptureFlags( - WebContentsAdapterClient::MediaVideoCapture | - WebContentsAdapterClient::MediaAudioCapture); - const WebContentsAdapterClient::MediaRequestFlags desktopAudioVideoCaptureFlags( - WebContentsAdapterClient::MediaDesktopVideoCapture | - WebContentsAdapterClient::MediaDesktopAudioCapture); - - if (policy == PermissionGrantedByUser) { - switch (feature) { - case MediaAudioVideoCapture: - d->adapter->grantMediaAccessPermission(securityOrigin, audioVideoCaptureFlags); - break; - case MediaAudioCapture: - d->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaAudioCapture); - break; - case MediaVideoCapture: - d->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaVideoCapture); - break; - case DesktopAudioVideoCapture: - d->adapter->grantMediaAccessPermission(securityOrigin, desktopAudioVideoCaptureFlags); - break; - case DesktopVideoCapture: - d->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaDesktopVideoCapture); - break; - case MouseLock: - d->adapter->grantMouseLockPermission(securityOrigin, true); - break; - case Geolocation: - d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::GeolocationPermission, ProfileAdapter::AllowedPermission); - break; - case Notifications: - d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::NotificationPermission, ProfileAdapter::AllowedPermission); - break; - case ClipboardReadWrite: - d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::ClipboardReadWrite, - ProfileAdapter::AllowedPermission); - break; - case LocalFontsAccess: - d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::LocalFontsPermission, ProfileAdapter::AllowedPermission); - break; - } - } else { // if (policy == PermissionDeniedByUser) - switch (feature) { - case MediaAudioVideoCapture: - case MediaAudioCapture: - case MediaVideoCapture: - case DesktopAudioVideoCapture: - case DesktopVideoCapture: - d->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaNone); - break; - case Geolocation: - d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::GeolocationPermission, ProfileAdapter::DeniedPermission); - break; - case MouseLock: - d->adapter->grantMouseLockPermission(securityOrigin, false); - break; - case Notifications: - d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::NotificationPermission, ProfileAdapter::DeniedPermission); - break; - case ClipboardReadWrite: - d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::ClipboardReadWrite, - ProfileAdapter::DeniedPermission); - break; - case LocalFontsAccess: - d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::LocalFontsPermission, ProfileAdapter::DeniedPermission); - break; - } + switch (policy) { + case QWebEnginePage::PermissionUnknown: + s = QWebEnginePermission::Ask; + break; + case QWebEnginePage::PermissionDeniedByUser: + s = QWebEnginePermission::Denied; + break; + case QWebEnginePage::PermissionGrantedByUser: + s = QWebEnginePermission::Granted; + break; } + + d->adapter->setFeaturePermission(securityOrigin, f, s); } +QT_WARNING_POP +#endif // QT_DEPRECATED_SINCE(6, 8) static inline QWebEnginePage::FileSelectionMode toPublic(FilePickerController::FileChooserMode mode) { @@ -2020,7 +2095,7 @@ void QWebEnginePage::setZoomFactor(qreal factor) Q_D(QWebEnginePage); d->defaultZoomFactor = factor; - if (d->adapter->isInitialized()) { + if (d->adapter->isInitialized() && !qFuzzyCompare(factor, zoomFactor())) { d->adapter->setZoomFactor(factor); // MEMO: should reset if factor was not applied due to being invalid d->defaultZoomFactor = zoomFactor(); @@ -2029,40 +2104,13 @@ void QWebEnginePage::setZoomFactor(qreal factor) void QWebEnginePage::runJavaScript(const QString& scriptSource, const std::function<void(const QVariant &)> &resultCallback) { - Q_D(QWebEnginePage); - d->ensureInitialized(); - if (d->adapter->lifecycleState() == WebContentsAdapter::LifecycleState::Discarded) { - qWarning("runJavaScript: disabled in Discarded state"); - if (resultCallback) - resultCallback(QVariant()); - return; - } - quint64 requestId = d->adapter->runJavaScriptCallbackResult(scriptSource, QWebEngineScript::MainWorld); - if (requestId) - d->m_variantCallbacks.insert(requestId, resultCallback); - else if (resultCallback) - resultCallback(QVariant()); + runJavaScript(scriptSource, QWebEngineScript::MainWorld, resultCallback); } void QWebEnginePage::runJavaScript(const QString& scriptSource, quint32 worldId, const std::function<void(const QVariant &)> &resultCallback) { Q_D(QWebEnginePage); - d->ensureInitialized(); - if (d->adapter->lifecycleState() == WebContentsAdapter::LifecycleState::Discarded) { - qWarning("runJavaScript: disabled in Discarded state"); - if (resultCallback) - resultCallback(QVariant()); - return; - } - if (resultCallback) { - quint64 requestId = d->adapter->runJavaScriptCallbackResult(scriptSource, worldId); - if (requestId) - d->m_variantCallbacks.insert(requestId, resultCallback); - else - resultCallback(QVariant()); - } else { - d->adapter->runJavaScript(scriptSource, worldId); - } + d->runJavaScript(scriptSource, worldId, WebContentsAdapter::kUseMainFrameId, resultCallback); } /*! @@ -2322,7 +2370,7 @@ void QWebEnginePage::printToPdf(const QString &filePath, const QPageLayout &layo #if QT_CONFIG(webengine_printing_and_pdf) Q_D(QWebEnginePage); d->ensureInitialized(); - d->adapter->printToPDF(layout, ranges, filePath); + d->printToPdf(filePath, layout, ranges, WebContentsAdapter::kUseMainFrameId); #else Q_UNUSED(filePath); Q_UNUSED(layout); @@ -2347,11 +2395,14 @@ void QWebEnginePage::printToPdf(const QString &filePath, const QPageLayout &layo */ void QWebEnginePage::printToPdf(const std::function<void(const QByteArray&)> &resultCallback, const QPageLayout &layout, const QPageRanges &ranges) { - Q_D(QWebEnginePage); #if QT_CONFIG(webengine_printing_and_pdf) + Q_D(QWebEnginePage); d->ensureInitialized(); - quint64 requestId = d->adapter->printToPDFCallbackResult(layout, ranges); - d->m_pdfResultCallbacks.insert(requestId, resultCallback); + std::function wrappedCallback = [resultCallback](QSharedPointer<QByteArray> result) { + if (resultCallback && result) + resultCallback(*result); + }; + d->printToPdf(std::move(wrappedCallback), layout, ranges, WebContentsAdapter::kUseMainFrameId); #else Q_UNUSED(layout); Q_UNUSED(ranges); diff --git a/src/core/api/qwebenginepage.h b/src/core/api/qwebenginepage.h index e5a4e9551..cca7c55e7 100644 --- a/src/core/api/qwebenginepage.h +++ b/src/core/api/qwebenginepage.h @@ -9,6 +9,7 @@ #include <QtWebEngineCore/qwebenginedownloadrequest.h> #include <QtWebEngineCore/qwebenginequotarequest.h> #include <QtWebEngineCore/qwebengineframe.h> +#include <QtWebEngineCore/qwebenginepermission.h> #include <QtCore/qobject.h> #include <QtCore/qurl.h> @@ -51,7 +52,7 @@ class Q_WEBENGINECORE_EXPORT QWebEnginePage : public QObject Q_PROPERTY(QString selectedText READ selectedText) Q_PROPERTY(bool hasSelection READ hasSelection) Q_PROPERTY(QUrl requestedUrl READ requestedUrl) - Q_PROPERTY(qreal zoomFactor READ zoomFactor WRITE setZoomFactor) + Q_PROPERTY(qreal zoomFactor READ zoomFactor WRITE setZoomFactor NOTIFY zoomFactorChanged) Q_PROPERTY(QString title READ title NOTIFY titleChanged) Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged) Q_PROPERTY(QUrl iconUrl READ iconUrl NOTIFY iconUrlChanged) @@ -147,12 +148,19 @@ public: }; Q_ENUM(WebWindowType) - enum PermissionPolicy { +#if QT_DEPRECATED_SINCE(6, 8) +QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED + enum QT_DEPRECATED_VERSION_X_6_8( + "QWebEnginePage::PermissionPolicy has been deprecated. " + "The updated permissions API uses QWebEnginePermission::State.") + PermissionPolicy { PermissionUnknown, PermissionGrantedByUser, PermissionDeniedByUser }; Q_ENUM(PermissionPolicy) +QT_WARNING_POP +#endif // must match WebContentsAdapterClient::NavigationType enum NavigationType { @@ -166,7 +174,12 @@ public: }; Q_ENUM(NavigationType) - enum Feature { +#if QT_DEPRECATED_SINCE(6, 8) +QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED + enum QT_DEPRECATED_VERSION_X_6_8( + "QWebEnginePage::Feature has been deprecated. " + "The updated permissions API uses QWebEnginePermission::Feature.") + Feature { Notifications = 0, Geolocation = 1, MediaAudioCapture = 2, @@ -179,6 +192,8 @@ public: LocalFontsAccess, }; Q_ENUM(Feature) +QT_WARNING_POP +#endif // Ex-QWebFrame enum @@ -236,7 +251,12 @@ public: void findText(const QString &subString, FindFlags options = {}, const std::function<void(const QWebEngineFindTextResult &)> &resultCallback = std::function<void(const QWebEngineFindTextResult &)>()); +#if QT_DEPRECATED_SINCE(6, 8) +QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED + QT_DEPRECATED_VERSION_X_6_8("Setting permissions through QWebEnginePage has been deprecated. Please use QWebEnginePermission instead.") void setFeaturePermission(const QUrl &securityOrigin, Feature feature, PermissionPolicy policy); +QT_WARNING_POP +#endif bool isLoading() const; @@ -319,9 +339,23 @@ Q_SIGNALS: void geometryChangeRequested(const QRect &geom); void windowCloseRequested(); +#if QT_DEPRECATED_SINCE(6, 8) +#if !defined(Q_MOC_RUN) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED +#endif // !defined(Q_MOC_RUN) + QT_MOC_COMPAT QT_DEPRECATED_VERSION_X_6_8("The signal has been deprecated; please use permissionRequested instead.") void featurePermissionRequested(const QUrl &securityOrigin, QWebEnginePage::Feature feature); + QT_MOC_COMPAT QT_DEPRECATED_VERSION_X_6_8("The signal has been deprecated, and no longer functions.") void featurePermissionRequestCanceled(const QUrl &securityOrigin, QWebEnginePage::Feature feature); +#if !defined(Q_MOC_RUN) +QT_WARNING_POP +#endif // !defined(Q_MOC_RUN) +#endif // QT_DEPRECATED_SINCE(6, 8) + void fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest); + void permissionRequested(QWebEnginePermission permissionRequest); + #if QT_DEPRECATED_SINCE(6, 5) QT_DEPRECATED_VERSION_X_6_5("Requesting host quota is no longer supported.") void quotaRequested(QWebEngineQuotaRequest quotaRequest); @@ -344,6 +378,7 @@ Q_SIGNALS: void iconUrlChanged(const QUrl &url); void iconChanged(const QIcon &icon); + void zoomFactorChanged(qreal factor); void scrollPositionChanged(const QPointF &position); void contentsSizeChanged(const QSizeF &size); void audioMutedChanged(bool muted); @@ -352,6 +387,7 @@ Q_SIGNALS: void pdfPrintingFinished(const QString &filePath, bool success); void printRequested(); + void printRequestedByFrame(QWebEngineFrame frame); void visibleChanged(bool visible); diff --git a/src/core/api/qwebenginepage_p.h b/src/core/api/qwebenginepage_p.h index 31ace7e9d..77d3dd8c2 100644 --- a/src/core/api/qwebenginepage_p.h +++ b/src/core/api/qwebenginepage_p.h @@ -74,6 +74,7 @@ public: virtual void didPrintPage(QPrinter *&printer, QSharedPointer<QByteArray> result) = 0; virtual void didPrintPageToPdf(const QString &filePath, bool success) = 0; virtual void printRequested() = 0; + virtual void printRequestedByFrame(QWebEngineFrame frame) = 0; virtual void showAutofillPopup(QtWebEngineCore::AutofillPopupController *controller, const QRect &bounds, bool autoselectFirstSuggestion) = 0; virtual void hideAutofillPopup() = 0; @@ -102,6 +103,7 @@ public: void titleChanged(const QString &) override; void urlChanged() override; void iconChanged(const QUrl &) override; + void zoomFactorChanged(qreal factor) override; void loadProgressChanged(int progress) override; void didUpdateTargetURL(const QUrl &) override; void selectionChanged() override; @@ -130,10 +132,14 @@ public: void javascriptDialog(QSharedPointer<QtWebEngineCore::JavaScriptDialogController>) override; void runFileChooser(QSharedPointer<QtWebEngineCore::FilePickerController>) override; void showColorDialog(QSharedPointer<QtWebEngineCore::ColorChooserController>) override; - void didRunJavaScript(quint64 requestId, const QVariant &result) override; + void runJavaScript(const QString &script, quint32 worldId, quint64 frameId, + const std::function<void(const QVariant &)> &callback) override; void didFetchDocumentMarkup(quint64 requestId, const QString &result) override; void didFetchDocumentInnerText(quint64 requestId, const QString &result) override; - void didPrintPage(quint64 requestId, QSharedPointer<QByteArray> result) override; + void printToPdf(const QString &filePath, const QPageLayout &layout, const QPageRanges &ranges, + quint64 frameId) override; + void printToPdf(std::function<void(QSharedPointer<QByteArray>)> &&callback, + const QPageLayout &layout, const QPageRanges &ranges, quint64 frameId) override; void didPrintPageToPdf(const QString &filePath, bool success) override; bool passOnFocus(bool reverse) override; void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString &message, @@ -142,7 +148,7 @@ public: QSharedPointer<QtWebEngineCore::AuthenticationDialogController>) override; void releaseProfile() override; void runMediaAccessPermissionRequest(const QUrl &securityOrigin, MediaRequestFlags requestFlags) override; - void runFeaturePermissionRequest(QtWebEngineCore::ProfileAdapter::PermissionType permission, const QUrl &securityOrigin) override; + void runFeaturePermissionRequest(QWebEnginePermission::Feature feature, const QUrl &securityOrigin) override; void runMouseLockPermissionRequest(const QUrl &securityOrigin) override; void runRegisterProtocolHandlerRequest(QWebEngineRegisterProtocolHandlerRequest) override; void runFileSystemAccessRequest(QWebEngineFileSystemAccessRequest) override; @@ -161,6 +167,7 @@ public: bool isEnabled() const override; void setToolTip(const QString &toolTipText) override; void printRequested() override; + void printRequestedByFrame(quint64 frameId) override; QtWebEngineCore::TouchHandleDrawableDelegate * createTouchHandleDelegate(const QMap<int, QImage> &) override; void showTouchSelectionMenu(QtWebEngineCore::TouchSelectionMenuController *, const QRect &, @@ -173,6 +180,7 @@ public: const QRect &bounds, bool autoselectFirstSuggestion) override; void hideAutofillPopup() override; void showWebAuthDialog(QWebEngineWebAuthUxRequest *controller) override; + QWebEnginePermission createFeaturePermissionObject(const QUrl &securityOrigin, QWebEnginePermission::Feature feature) override; QtWebEngineCore::ProfileAdapter *profileAdapter() override; QtWebEngineCore::WebContentsAdapter *webContentsAdapter() override; @@ -184,6 +192,7 @@ public: bool adoptWebContents(QtWebEngineCore::WebContentsAdapter *webContents); QtWebEngineCore::WebContentsAdapter *webContents() { return adapter.data(); } void recreateFromSerializedHistory(QDataStream &input); + void didPrintPage(QSharedPointer<QByteArray> result); void setFullScreenMode(bool); void ensureInitialized() const; @@ -214,9 +223,7 @@ 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/api/qwebenginepermission.cpp b/src/core/api/qwebenginepermission.cpp new file mode 100644 index 000000000..d898b8c7e --- /dev/null +++ b/src/core/api/qwebenginepermission.cpp @@ -0,0 +1,307 @@ +// 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 "qwebenginepermission.h" +#include "qwebenginepermission_p.h" +#include "web_contents_adapter.h" +#include "profile_adapter.h" + +QT_BEGIN_NAMESPACE + +QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QWebEnginePermissionPrivate) + +QWebEnginePermissionPrivate::QWebEnginePermissionPrivate() + : QSharedData() + , feature(QWebEnginePermission::Unsupported) +{ +} + +QWebEnginePermissionPrivate::QWebEnginePermissionPrivate(const QUrl &origin_, QWebEnginePermission::Feature feature_, + QSharedPointer<QtWebEngineCore::WebContentsAdapter> webContentsAdapter_, QtWebEngineCore::ProfileAdapter *profileAdapter_) + : QSharedData() + , origin(origin_) + , feature(feature_) + , webContentsAdapter(webContentsAdapter_) + , profileAdapter(profileAdapter_) +{ +} + +/*! + \class QWebEnginePermission + \inmodule QtWebEngineCore + \since 6.8 + \brief A QWebEnginePermission is an object used to access and modify the state of a single permission that's been + granted or denied to a specific origin URL. + + The typical usage pattern is as follows: + \list 1 + \li A website requests a specific feature, triggering the QWebEnginePage::permissionRequested() signal; + \li The signal handler triggers a prompt asking the user whether they want to grant the permission; + \li When the user has made their decision, the application calls \l grant() or \l deny(); + \endlist + + Alternatively, an application interested in modifying already granted permissions may use QWebEngineProfile::listPermissions() + to get a list of existing permissions associated with a profile, or QWebEngineProfile::getPermission() to get + a QWebEnginePermission object for a specific permission. + + The \l origin() property can be used to query which origin the QWebEnginePermission is associated with, while the + \l feature() property describes the associated feature. A website origin is the combination of its scheme, hostname, + and port. Permissions are granted on a per-origin basis; thus, if the web page \c{https://www.example.com:12345/some/page.html} + requests a permission, it will be granted to the origin \c{https://www.example.com:12345/}. + + \l QWebEnginePermission::Feature describes all the feature types Qt WebEngine supports. Some Features are transient; + in practice, this means that they are never remembered, and a website that uses them will trigger a permission + prompt every time the Feature is needed. Transient Features cannot be granted in advance. + + The usability lifetime of a QWebEnginePermission is tied either to its associated QWebEnginePage + (for transient feature types), or QWebEngineProfile (for permanent feature types). A transient permission is one which + needs to be explicitly granted or denied every time it's needed (e.g. webcam/screen sharing permission), whereas a permanent + one might be stored inside the current profile, depending on the value of QWebEngineProfile::persistentPermissionsPolicy(). + You can check whether a QWebEnginePermission is in a valid state using its \l isValid() property. For invalid objects, calls to \l grant(), + \l deny(), or \l reset() will do nothing, while calls to \l state() will always return QWebEnginePermission::Invalid. + + \sa QWebEnginePage::permissionRequested(), QWebEngineProfile::getPermission(), QWebEngineProfile::listPermissions() +*/ + +/*! \fn QWebEnginePermission::QWebEnginePermission() + \internal +*/ + +/*! \internal */ +QWebEnginePermission::QWebEnginePermission() + : d_ptr(new QWebEnginePermissionPrivate()) +{ +} + +/*! \internal */ +QWebEnginePermission::QWebEnginePermission(QWebEnginePermissionPrivate *pvt) + : d_ptr(pvt) +{ +} + +QWebEnginePermission::QWebEnginePermission(const QWebEnginePermission &other) + : d_ptr(new QWebEnginePermissionPrivate(*other.d_ptr)) +{ +} + +QWebEnginePermission::~QWebEnginePermission() = default; + +QWebEnginePermission &QWebEnginePermission::operator=(const QWebEnginePermission &other) +{ + if (this == &other) + return *this; + + d_ptr.reset(new QWebEnginePermissionPrivate(*other.d_ptr)); + return *this; +} + +bool QWebEnginePermission::comparesEqual(const QWebEnginePermission &other) const +{ + if (this == &other) + return true; + + if (d_ptr->feature != other.d_ptr->feature || d_ptr->origin != other.d_ptr->origin) + return false; + + if (isTransient(d_ptr->feature)) { + if (d_ptr->webContentsAdapter != other.d_ptr->webContentsAdapter) + return false; + } else { + QtWebEngineCore::ProfileAdapter *thisProfile = d_ptr->webContentsAdapter + ? d_ptr->webContentsAdapter.toStrongRef()->profileAdapter() + : d_ptr->profileAdapter.get(); + QtWebEngineCore::ProfileAdapter *otherProfile = d_ptr->webContentsAdapter + ? other.d_ptr->webContentsAdapter.toStrongRef()->profileAdapter() + : other.d_ptr->profileAdapter.get(); + + if (thisProfile != otherProfile) + return false; + } + + return true; +} + +/*! + \property QWebEnginePermission::origin + \brief The URL of the permission's associated origin. + + A website origin is the combination of its scheme, hostname, and port. Permissions are granted on a + per-origin basis; thus, if the web page \c{https://www.example.com:12345/some/page.html} + requests a permission, it will be granted to the origin \c{https://www.example.com:12345/}. +*/ +const QUrl QWebEnginePermission::origin() const +{ + return d_ptr->origin; +} + +/*! + \enum QWebEnginePermission::Feature + + This enum type holds the type of the requested feature: + + \value MediaAudioCapture Access to a microphone, or another audio source. This feature is transient. + \value MediaVideoCapture Access to a webcam, or another video source. This feature is transient. + \value MediaAudioVideoCapture Combination of \l MediaAudioCapture and \l MediaVideoCapture. This feature is transient. + \value DesktopVideoCapture Access to the contents of the user's screen. This feature is transient. + \value DesktopAudioVideoCapture Access to the contents of the user's screen, and application audio. This feature is transient. + \value MouseLock Locks the pointer inside an element on the web page. This feature is transient. + \value Notifications Allows the website to send notifications to the user. + \value Geolocation Access to the user's physical location. + \value ClipboardReadWrite Access to the user's clipboard. + \value LocalFontsAccess Access to the fonts installed on the user's machine. Only available on desktops. + \value Unsupported An unsupported feature type. + + \note Transient feature types are ones that will never be remembered by the underlying storage, and will trigger + a permission request every time a website tries to use them. Transient Features can only be denied/granted + as they're needed; any attempts to pre-grant a transient Feature will fail. +*/ + +/*! + \property QWebEnginePermission::feature + \brief The feature type associated with this permission. +*/ +QWebEnginePermission::Feature QWebEnginePermission::feature() const +{ + return d_ptr->feature; +} + +/*! + \enum QWebEnginePermission::State + + This enum type holds the current state of the requested feature: + + \value Invalid Object is in an invalid state, and any attempts to modify the described permission will fail. + \value Ask Either the permission has not been requested before, or the feature() is transient. + \value Granted Permission has already been granted. + \value Denied Permission has already been denied. +*/ + +/*! + \property QWebEnginePermission::state + \brief The current state of the permission. + + If a permission for the specified \l feature() and \l origin() has already been granted or denied, + the return value is QWebEnginePermission::Granted, or QWebEnginePermission::Denied, respectively. + When this is the first time the permission is requested, or if the \l feature() is transient, + the return value is QWebEnginePermission::Ask. If the object is in an invalid state, the returned + value is QWebEnginePermission::Invalid. + + \sa isValid(), isTransient() +*/ +QWebEnginePermission::State QWebEnginePermission::state() const +{ + if (!isValid()) + return Invalid; + if (d_ptr->webContentsAdapter) + return d_ptr->webContentsAdapter.toStrongRef()->getPermissionState(origin(), feature()); + if (d_ptr->profileAdapter) + return d_ptr->profileAdapter->getPermissionState(origin(), feature()); + Q_UNREACHABLE(); + return Ask; +} + +/*! + \property QWebEnginePermission::isValid + \brief Indicates whether attempts to change the permission's state will be successful. + + An invalid QWebEnginePermission is either: + \list + \li One whose \l feature() is unsupported; + \li One whose \l feature() is transient, and the associated page/view has been destroyed; + \li One whose \l feature() is permanent, but the associated profile has been destroyed; + \li One whose \l origin() is invalid. + \endlist + + \sa isTransient() +*/ +bool QWebEnginePermission::isValid() const +{ + if (feature() == Unsupported) + return false; + if (isTransient(feature()) && !d_ptr->webContentsAdapter) + return false; + if (!d_ptr->profileAdapter) + return false; + if (!d_ptr->origin.isValid()) + return false; + return true; +} + +/*! + Allows the associated origin to access the requested feature. Does nothing when \l isValid() evaluates to false. + + \sa deny(), reset(), isValid() +*/ +void QWebEnginePermission::grant() const +{ + if (!isValid()) + return; + if (d_ptr->webContentsAdapter) + d_ptr->webContentsAdapter.toStrongRef()->setFeaturePermission(origin(), feature(), Granted); + else if (d_ptr->profileAdapter) + d_ptr->profileAdapter->setPermission(origin(), feature(), Granted); +} + +/*! + Stops the associated origin from accessing the requested feature. Does nothing when \l isValid() evaluates to false. + + \sa grant(), reset(), isValid() +*/ +void QWebEnginePermission::deny() const +{ + if (!isValid()) + return; + if (d_ptr->webContentsAdapter) + d_ptr->webContentsAdapter.toStrongRef()->setFeaturePermission(origin(), feature(), Denied); + else if (d_ptr->profileAdapter) + d_ptr->profileAdapter->setPermission(origin(), feature(), Denied); +} + +/*! + Removes the permission from the profile's underlying storage. By default, permissions are stored on disk (except for + off-the-record profiles, where permissions are stored in memory and are destroyed with the profile). + This means that an already granted/denied permission will not be requested twice, but will get automatically + granted/denied every subsequent time a website requests it. Calling reset() allows the query to be asked + again the next time the website requests it. + + Does nothing when \l isValid() evaluates to false. + + \sa grant(), deny(), isValid(), QWebEngineProfile::persistentPermissionsPolicy() +*/ +void QWebEnginePermission::reset() const +{ + if (!isValid()) + return; + if (d_ptr->webContentsAdapter) + d_ptr->webContentsAdapter.toStrongRef()->setFeaturePermission(origin(), feature(), Ask); + else if (d_ptr->profileAdapter) + d_ptr->profileAdapter->setPermission(origin(), feature(), Ask); +} + +/*! + Returns whether \a feature is transient, meaning that a permission will be requested + every time the associated functionality is used by a web page. +*/ +bool QWebEnginePermission::isTransient(QWebEnginePermission::Feature feature) +{ + switch (feature) { + case QWebEnginePermission::MediaAudioCapture: + case QWebEnginePermission::MediaVideoCapture: + case QWebEnginePermission::MediaAudioVideoCapture: + case QWebEnginePermission::DesktopVideoCapture: + case QWebEnginePermission::DesktopAudioVideoCapture: + case QWebEnginePermission::MouseLock: + return true; + case QWebEnginePermission::Notifications: + case QWebEnginePermission::Geolocation: + case QWebEnginePermission::ClipboardReadWrite: + case QWebEnginePermission::LocalFontsAccess: + return false; + case QWebEnginePermission::Unsupported: + return false; + } +} + +QT_END_NAMESPACE + +#include "moc_qwebenginepermission.cpp" diff --git a/src/core/api/qwebenginepermission.h b/src/core/api/qwebenginepermission.h new file mode 100644 index 000000000..09db8ce36 --- /dev/null +++ b/src/core/api/qwebenginepermission.h @@ -0,0 +1,90 @@ +// 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 QWEBENGINEPERMISSION_H +#define QWEBENGINEPERMISSION_H + +#include <QtWebEngineCore/qtwebenginecoreglobal.h> +#include <QtCore/qobject.h> +#include <QtCore/qurl.h> +#include <QtCore/qshareddata.h> + +QT_BEGIN_NAMESPACE + +struct QWebEnginePermissionPrivate; +QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QWebEnginePermissionPrivate, + Q_WEBENGINECORE_EXPORT) + +class QWebEnginePermission +{ + Q_GADGET_EXPORT(Q_WEBENGINECORE_EXPORT) + Q_PROPERTY(QUrl origin READ origin CONSTANT FINAL) + Q_PROPERTY(Feature feature READ feature CONSTANT FINAL) + Q_PROPERTY(State state READ state CONSTANT FINAL) + Q_PROPERTY(bool isValid READ isValid CONSTANT FINAL) + Q_CLASSINFO("RegisterEnumClassesUnscoped", "false") + +public: + Q_WEBENGINECORE_EXPORT QWebEnginePermission(); + + Q_WEBENGINECORE_EXPORT QWebEnginePermission(const QWebEnginePermission &other); + Q_WEBENGINECORE_EXPORT QWebEnginePermission(QWebEnginePermissionPrivate *pvt); + Q_WEBENGINECORE_EXPORT ~QWebEnginePermission(); + + Q_WEBENGINECORE_EXPORT QWebEnginePermission &operator=(const QWebEnginePermission &other); + QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QWebEnginePermission) + void swap(QWebEnginePermission &other) noexcept { d_ptr.swap(other.d_ptr); } + + enum Feature : quint8 { + Unsupported, + MediaAudioCapture, + MediaVideoCapture, + MediaAudioVideoCapture, + DesktopVideoCapture, + DesktopAudioVideoCapture, + MouseLock, + Notifications, + Geolocation, + ClipboardReadWrite, + LocalFontsAccess, + }; + Q_ENUM(Feature) + + enum State : quint8 { + Invalid, + Ask, + Granted, + Denied + }; + Q_ENUM(State) + + Q_WEBENGINECORE_EXPORT const QUrl origin() const; + Q_WEBENGINECORE_EXPORT Feature feature() const; + Q_WEBENGINECORE_EXPORT State state() const; + Q_WEBENGINECORE_EXPORT bool isValid() const; + + Q_WEBENGINECORE_EXPORT Q_INVOKABLE void grant() const; + Q_WEBENGINECORE_EXPORT Q_INVOKABLE void deny() const; + Q_WEBENGINECORE_EXPORT Q_INVOKABLE void reset() const; + + Q_WEBENGINECORE_EXPORT Q_INVOKABLE static bool isTransient(QWebEnginePermission::Feature feature); + +private: + inline friend bool operator==(const QWebEnginePermission &lhs, const QWebEnginePermission &rhs) + { return lhs.comparesEqual(rhs); }; + inline friend bool operator!=(const QWebEnginePermission &lhs, const QWebEnginePermission &rhs) + { return !lhs.comparesEqual(rhs); }; + + Q_WEBENGINECORE_EXPORT bool comparesEqual(const QWebEnginePermission &other) const; + +protected: + QExplicitlySharedDataPointer<QWebEnginePermissionPrivate> d_ptr; +}; + + + +Q_DECLARE_SHARED(QWebEnginePermission) + +QT_END_NAMESPACE + +#endif // QWEBENGINEPERMISSION_H diff --git a/src/core/api/qwebenginepermission_p.h b/src/core/api/qwebenginepermission_p.h new file mode 100644 index 000000000..94c898873 --- /dev/null +++ b/src/core/api/qwebenginepermission_p.h @@ -0,0 +1,46 @@ +// 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 QWEBENGINEPERMISSION_P_H +#define QWEBENGINEPERMISSION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qwebenginepermission.h" + +#include <QtCore/qpointer.h> +#include <QtCore/qsharedpointer.h> +#include <QtCore/qshareddata.h> + +namespace QtWebEngineCore { +class WebContentsAdapter; +class ProfileAdapter; +} + +QT_BEGIN_NAMESPACE + +struct QWebEnginePermissionPrivate : public QSharedData +{ + Q_WEBENGINECORE_EXPORT QWebEnginePermissionPrivate(); + Q_WEBENGINECORE_EXPORT QWebEnginePermissionPrivate(const QUrl &, QWebEnginePermission::Feature, + QSharedPointer<QtWebEngineCore::WebContentsAdapter>, QtWebEngineCore::ProfileAdapter *); + + QUrl origin; + QWebEnginePermission::Feature feature; + + QWeakPointer<QtWebEngineCore::WebContentsAdapter> webContentsAdapter; + QPointer<QtWebEngineCore::ProfileAdapter> profileAdapter; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINEPERMISSION_P_H diff --git a/src/core/api/qwebengineprofile.cpp b/src/core/api/qwebengineprofile.cpp index dbb98102c..5d7bb5559 100644 --- a/src/core/api/qwebengineprofile.cpp +++ b/src/core/api/qwebengineprofile.cpp @@ -11,6 +11,7 @@ #include "qwebenginesettings.h" #include "qwebenginescriptcollection.h" #include "qwebenginescriptcollection_p.h" +#include "qwebenginepermission_p.h" #include "qtwebenginecoreglobal.h" #include "profile_adapter.h" #include "visited_links_manager_qt.h" @@ -93,7 +94,7 @@ using QtWebEngineCore::ProfileAdapter; /*! \enum QWebEngineProfile::PersistentCookiesPolicy - This enum describes policy for cookie persistency: + This enum describes policy for cookie persistence: \value NoPersistentCookies Both session and persistent cookies are stored in memory. This is the only setting @@ -105,6 +106,28 @@ using QtWebEngineCore::ProfileAdapter; Both session and persistent cookies are saved to and restored from disk. */ +/*! + \enum QWebEngineProfile::PersistentPermissionsPolicy + + \since 6.8 + + This enum describes the policy for permission persistence: + + \value NoPersistentPermissions + The application will ask for permissions every time they're needed, regardless of + whether they've been granted before or not. This is intended for backwards compatibility + with existing applications, and otherwise not recommended. + \value PersistentPermissionsInMemory + A request will be made only the first time a permission is needed. Any subsequent + requests will be automatically granted or denied, depending on the initial user choice. + This carries over to all pages that use the same QWebEngineProfile instance, until the + application is shut down. This is the setting applied if \c off-the-record is set + or no persistent data path is available. + \value PersistentPermissionsOnDisk + Works the same way as \c PersistentPermissionsInMemory, but the permissions are saved to + and restored from disk. This is the default setting. +*/ + void QWebEngineProfilePrivate::showNotification(QSharedPointer<QtWebEngineCore::UserNotificationController> &controller) { if (m_notificationPresenter) { @@ -571,6 +594,31 @@ void QWebEngineProfile::setPersistentCookiesPolicy(QWebEngineProfile::Persistent } /*! + Returns the current policy for persistent permissions. + + Off-the-record profiles are not allowed to save data to the disk, so they can only return + PersistentPermissionsInMemory or NoPersistentPermissions. + + \sa setPersistentPermissionsPolicy() +*/ +QWebEngineProfile::PersistentPermissionsPolicy QWebEngineProfile::persistentPermissionsPolicy() const +{ + Q_D(const QWebEngineProfile); + return QWebEngineProfile::PersistentPermissionsPolicy(d->profileAdapter()->persistentPermissionsPolicy()); +} + +/*! + Sets the policy for persistent permissions to \a newPersistentPermissionsPolicy. + + \sa persistentPermissionsPolicy() +*/ +void QWebEngineProfile::setPersistentPermissionsPolicy(QWebEngineProfile::PersistentPermissionsPolicy newPersistentPermissionsPolicy) +{ + Q_D(QWebEngineProfile); + d->profileAdapter()->setPersistentPermissionsPolicy(ProfileAdapter::PersistentPermissionsPolicy(newPersistentPermissionsPolicy)); +} + +/*! Returns the maximum size of the HTTP cache in bytes. Will return \c 0 if the size is automatically controlled by QtWebEngine. @@ -930,6 +978,95 @@ void QWebEngineProfile::requestIconForIconURL(const QUrl &url, int desiredSizeIn } /*! + * Returns a QWebEnginePermission object corresponding to a single permission for the provided \a securityOrigin and + * \a feature. The object may be used to query for the current state of the permission, or to change it. It is not required + * for a permission to already exist; the returned object may also be used to pre-grant a permission if a website is + * known to use it. + * + * \note This may only be used for permanent feature types. Calling it with a transient \a feature will return an invalid object. + * \since 6.8 + * \sa listPermissions(), QWebEnginePermission::Feature + */ +QWebEnginePermission QWebEngineProfile::getPermission(const QUrl &securityOrigin, QWebEnginePermission::Feature feature) const +{ + Q_D(const QWebEngineProfile); + + if (feature == QWebEnginePermission::Unsupported) { + qWarning("Attempting to get unsupported permission. Returned object will be in an invalid state."); + return QWebEnginePermission(new QWebEnginePermissionPrivate()); + } + + if (QWebEnginePermission::isTransient(feature)) { + qWarning() << "Attempting to get permission for feature" << feature << ". Returned object will be in an invalid state."; + return QWebEnginePermission(new QWebEnginePermissionPrivate()); + } + + auto *pvt = new QWebEnginePermissionPrivate(securityOrigin, feature, nullptr, d->profileAdapter()); + return QWebEnginePermission(pvt); +} + +/*! + * Returns a QList of QWebEnginePermission objects, each one representing a single permission currently + * present in the permissions store. The returned list contains all previously granted/denied permissions for this profile, + * except for those of a transient feature type. + * + * \since 6.8 + * \sa getPermission(), QWebEnginePermission::Feature + */ +QList<QWebEnginePermission> QWebEngineProfile::listPermissions() const +{ + Q_D(const QWebEngineProfile); + if (persistentPermissionsPolicy() == NoPersistentPermissions) + return QList<QWebEnginePermission>(); + return d->profileAdapter()->listPermissions(); +} + +/*! + * Returns a QList of QWebEnginePermission objects, each one representing a single permission currently + * present in the permissions store. The returned list contains all previously granted/denied permissions associated with a + * specific \a securityOrigin for this profile, except for those of a transient feature type. + * + * \note Since permissions are granted on a per-origin basis, the provided \a securityOrigin will be stripped to its + * origin form, and the returned list will contain all permissions for the origin. Thus, passing https://www.example.com/some/page.html + * is the same as passing just https://www.example.com/. + * \since 6.8 + * \sa getPermission(), QWebEnginePermission::Feature + */ +QList<QWebEnginePermission> QWebEngineProfile::listPermissions(const QUrl &securityOrigin) const +{ + Q_D(const QWebEngineProfile); + if (persistentPermissionsPolicy() == NoPersistentPermissions) + return QList<QWebEnginePermission>(); + return d->profileAdapter()->listPermissions(securityOrigin); +} + +/*! + * Returns a QList of QWebEnginePermission objects, each one representing a single permission currently + * present in the permissions store. The returned list contains all previously granted/denied permissions of the \a feature + * type for this profile. If the feature is of a transient or unsupported type, the list will be empty. + * \since 6.8 + * \sa getPermission(), QWebEnginePermission::Feature + */ +QList<QWebEnginePermission> QWebEngineProfile::listPermissions(QWebEnginePermission::Feature feature) const +{ + Q_D(const QWebEngineProfile); + if (persistentPermissionsPolicy() == NoPersistentPermissions) + return QList<QWebEnginePermission>(); + + if (feature == QWebEnginePermission::Unsupported) { + qWarning("Attempting to get permission list for an unsupported type. Returned list will be empty."); + return QList<QWebEnginePermission>(); + } + + if (QWebEnginePermission::isTransient(feature)) { + qWarning() << "Attempting to get permission list for feature" << feature << ". Returned list will be empty."; + return QList<QWebEnginePermission>(); + } + + return d->profileAdapter()->listPermissions(QUrl(), feature); +} + +/*! Return the Client Hints settings associated with this browsing context. \since 6.8 diff --git a/src/core/api/qwebengineprofile.h b/src/core/api/qwebengineprofile.h index a0027cb81..573f39e7d 100644 --- a/src/core/api/qwebengineprofile.h +++ b/src/core/api/qwebengineprofile.h @@ -5,6 +5,7 @@ #define QWEBENGINEPROFILE_H #include <QtWebEngineCore/qtwebenginecoreglobal.h> +#include <QtWebEngineCore/qwebenginepermission.h> #include <QtCore/qobject.h> #include <QtCore/qscopedpointer.h> @@ -49,6 +50,13 @@ public: }; Q_ENUM(PersistentCookiesPolicy) + enum PersistentPermissionsPolicy : quint8 { + NoPersistentPermissions, + PersistentPermissionsInMemory, + PersistentPermissionsOnDisk, + }; + Q_ENUM(PersistentPermissionsPolicy) + QString storageName() const; bool isOffTheRecord() const; @@ -70,6 +78,9 @@ public: PersistentCookiesPolicy persistentCookiesPolicy() const; void setPersistentCookiesPolicy(QWebEngineProfile::PersistentCookiesPolicy); + PersistentPermissionsPolicy persistentPermissionsPolicy() const; + void setPersistentPermissionsPolicy(QWebEngineProfile::PersistentPermissionsPolicy); + int httpCacheMaximumSize() const; void setHttpCacheMaximumSize(int maxSize); @@ -110,6 +121,11 @@ public: void requestIconForPageURL(const QUrl &url, int desiredSizeInPixel, std::function<void(const QIcon &, const QUrl &, const QUrl &)> iconAvailableCallback) const; void requestIconForIconURL(const QUrl &url, int desiredSizeInPixel, std::function<void(const QIcon &, const QUrl &)> iconAvailableCallback) const; + QWebEnginePermission getPermission(const QUrl &securityOrigin, QWebEnginePermission::Feature feature) const; + QList<QWebEnginePermission> listPermissions() const; + QList<QWebEnginePermission> listPermissions(const QUrl &securityOrigin) const; + QList<QWebEnginePermission> listPermissions(QWebEnginePermission::Feature feature) const; + static QWebEngineProfile *defaultProfile(); Q_SIGNALS: diff --git a/src/core/api/qwebengineurlrequestinfo.cpp b/src/core/api/qwebengineurlrequestinfo.cpp index 152cf4dd0..b323b5ec3 100644 --- a/src/core/api/qwebengineurlrequestinfo.cpp +++ b/src/core/api/qwebengineurlrequestinfo.cpp @@ -161,6 +161,7 @@ QWebEngineUrlRequestInfo::QWebEngineUrlRequestInfo(QWebEngineUrlRequestInfoPriva \value ResourceTypeNavigationPreloadSubFrame A sub-frame service worker navigation preload request. (Added in Qt 5.14) \value ResourceTypeWebSocket A WebSocket request. (Added in Qt 6.4) \value ResourceTypeUnknown Unknown request type. + \value ResourceTypeJson A JSON module. (Added in Qt 6.9) \note For forward compatibility all values not matched should be treated as unknown, not just \c ResourceTypeUnknown. diff --git a/src/core/api/qwebengineurlrequestinfo.h b/src/core/api/qwebengineurlrequestinfo.h index 33efcbeda..b8a02d07a 100644 --- a/src/core/api/qwebengineurlrequestinfo.h +++ b/src/core/api/qwebengineurlrequestinfo.h @@ -47,8 +47,9 @@ public: ResourceTypePluginResource, // A resource requested by a plugin ResourceTypeNavigationPreloadMainFrame = 19, // A main-frame service worker navigation preload request ResourceTypeNavigationPreloadSubFrame, // A sub-frame service worker navigation preload request + ResourceTypeJson, // a JSON module (import ... with { type: "json" }) #ifndef Q_QDOC - ResourceTypeLast = ResourceTypeNavigationPreloadSubFrame, + ResourceTypeLast = ResourceTypeJson, #endif ResourceTypeWebSocket = 254, ResourceTypeUnknown = 255 diff --git a/src/core/api/qwebengineurlrequestjob.cpp b/src/core/api/qwebengineurlrequestjob.cpp index b3997a49d..5ad22f344 100644 --- a/src/core/api/qwebengineurlrequestjob.cpp +++ b/src/core/api/qwebengineurlrequestjob.cpp @@ -32,7 +32,7 @@ QT_BEGIN_NAMESPACE This enum type holds the type of the error that occurred: \value NoError - The request was successful. + The request was successful. (Deprecated since Qt 6.7) \value UrlNotFound The requested URL was not found. \value UrlInvalid diff --git a/src/core/api/qwebengineurlrequestjob.h b/src/core/api/qwebengineurlrequestjob.h index a0cb48b8b..858c03e6e 100644 --- a/src/core/api/qwebengineurlrequestjob.h +++ b/src/core/api/qwebengineurlrequestjob.h @@ -26,7 +26,10 @@ public: ~QWebEngineUrlRequestJob(); enum Error { - NoError = 0, +#if QT_DEPRECATED_SINCE(6, 7) + NoError Q_DECL_ENUMERATOR_DEPRECATED_X( + "This attribute has no effect.") = 0, +#endif UrlNotFound, UrlInvalid, RequestAborted, diff --git a/src/core/api/qwebengineurlscheme.cpp b/src/core/api/qwebengineurlscheme.cpp index 3093c2b8e..be56a3048 100644 --- a/src/core/api/qwebengineurlscheme.cpp +++ b/src/core/api/qwebengineurlscheme.cpp @@ -372,7 +372,7 @@ void QWebEngineUrlScheme::registerScheme(const QWebEngineUrlScheme &scheme) */ QWebEngineUrlScheme QWebEngineUrlScheme::schemeByName(const QByteArray &name) { - base::StringPiece namePiece{ name.data(), static_cast<size_t>(name.size()) }; + std::string_view namePiece{ name.data(), static_cast<size_t>(name.size()) }; if (const url::CustomScheme *cs = url::CustomScheme::FindScheme(namePiece)) return QWebEngineUrlScheme(new QWebEngineUrlSchemePrivate(*cs)); return QWebEngineUrlScheme(); diff --git a/src/core/api/qwebenginewebauthuxrequest.cpp b/src/core/api/qwebenginewebauthuxrequest.cpp index 6a79daec9..1f09e55bb 100644 --- a/src/core/api/qwebenginewebauthuxrequest.cpp +++ b/src/core/api/qwebenginewebauthuxrequest.cpp @@ -94,6 +94,59 @@ */ /*! + \qmltype WebEngineWebAuthPinRequest + \instantiates QWebEngineWebAuthPinRequest + \inqmlmodule QtWebEngine + \since QtWebEngine 6.8 + \brief Encapsulates the data of a PIN WebAuth UX request. + + This encapsulates the following information related to a PIN request made by an authenticator. + \list + \li The reason for the PIN prompt. + \li The error details for the PIN prompt. + \li The number of attempts remaining before a hard lock. Should be ignored unless + \l{WebEngineWebAuthPinRequest::reason} is + \l{WebEngineWebAuthUxRequest.PinEntryReason.Challenge}. + \li The minimum PIN length that the authenticator will accept for the PIN. + \endlist + Use this structure to update the WebAuth UX dialog when the WebAuth UX state is \l + WebEngineWebAuthUxRequest.WebAuthUxState.CollectPin. +*/ + +/*! + \qmlproperty enumeration WebEngineWebAuthPinRequest::reason + \brief The reason for the PIN prompt. + + \value WebEngineWebAuthUxRequest.PinEntryReason.Set A new PIN is being set. + \value WebEngineWebAuthUxRequest.PinEntryReason.Change The existing PIN must be changed before using this authenticator. + \value WebEngineWebAuthUxRequest.PinEntryReason.Challenge The existing PIN is being collected to prove user verification. +*/ + +/*! + \qmlproperty enumeration WebEngineWebAuthPinRequest::error + \brief The error details for the PIN prompt. + + \value WebEngineWebAuthUxRequest.PinEntryError.NoError No error has occurred. + \value WebEngineWebAuthUxRequest.PinEntryError.InternalUvLocked Internal UV is locked, so we are falling back to PIN. + \value WebEngineWebAuthUxRequest.PinEntryError.WrongPin The PIN the user entered does not match the authenticator PIN. + \value WebEngineWebAuthUxRequest.PinEntryError.TooShort The new PIN the user entered is too short. + \value WebEngineWebAuthUxRequest.PinEntryError.InvalidCharacters The new PIN the user entered contains invalid characters. + \value WebEngineWebAuthUxRequest.PinEntryError.SameAsCurrentPin The new PIN the user entered is the same as the currently set PIN. +*/ + +/*! + \qmlproperty int WebEngineWebAuthPinRequest::remainingAttempts + \brief The number of attempts remaining before a hard lock. Should be ignored unless + \l{WebEngineWebAuthPinRequest::reason} is + \l{WebEngineWebAuthUxRequest.PinEntryReason.Challenge}. +*/ + +/*! + \qmlproperty int WebEngineWebAuthPinRequest::minPinLength + \brief The minimum PIN length that the authenticator will accept for the PIN. +*/ + +/*! \enum QWebEngineWebAuthUxRequest::WebAuthUxState This enum describes the state of the current WebAuth UX request. diff --git a/src/core/autofill_client_qt.cpp b/src/core/autofill_client_qt.cpp index 3bdc62e19..15162e9e9 100644 --- a/src/core/autofill_client_qt.cpp +++ b/src/core/autofill_client_qt.cpp @@ -70,12 +70,10 @@ void AutofillClientQt::ShowAutofillPopup(const autofill::AutofillClient::PopupOp autoSelectFirstSuggestion); } -void AutofillClientQt::UpdateAutofillPopupDataListValues(const std::vector<std::u16string> &values, - const std::vector<std::u16string> &labels) +void AutofillClientQt::UpdateAutofillPopupDataListValues( + base::span<const autofill::SelectOption> datalist) { - Q_UNUSED(labels); - - if (values.empty()) + if (datalist.empty()) HideAutofillPopup(autofill::PopupHidingReason::kNoSuggestions); } @@ -99,12 +97,6 @@ std::vector<autofill::Suggestion> AutofillClientQt::GetPopupSuggestions() const return {}; } -void AutofillClientQt::UpdatePopup(const std::vector<autofill::Suggestion> &, autofill::PopupType, autofill::AutofillSuggestionTriggerSource) -{ - // Called by password_manager component only. - NOTIMPLEMENTED(); -} - void AutofillClientQt::HideAutofillPopup(autofill::PopupHidingReason) { adapterClient()->hideAutofillPopup(); @@ -130,13 +122,6 @@ scoped_refptr<network::SharedURLLoaderFactory> AutofillClientQt::GetURLLoaderFac return nullptr; } -void AutofillClientQt::PropagateAutofillPredictionsDeprecated(autofill::AutofillDriver *, - const std::vector<autofill::FormStructure *> &) -{ - // For testing purposes only. - NOTIMPLEMENTED(); -} - WebContentsAdapterClient *AutofillClientQt::adapterClient() { return WebContentsViewQt::from( diff --git a/src/core/autofill_client_qt.h b/src/core/autofill_client_qt.h index cd38de462..59b728cc7 100644 --- a/src/core/autofill_client_qt.h +++ b/src/core/autofill_client_qt.h @@ -19,9 +19,9 @@ #include <vector> #include "base/memory/weak_ptr.h" +#include "base/containers/span.h" #include "components/autofill/content/browser/content_autofill_client.h" #include "content/public/browser/web_contents_observer.h" -#include "content/public/browser/web_contents_user_data.h" #include <QScopedPointer> @@ -46,20 +46,18 @@ public: void ShowAutofillPopup(const autofill::AutofillClient::PopupOpenArgs &open_args, base::WeakPtr<autofill::AutofillPopupDelegate> delegate) override; - void UpdateAutofillPopupDataListValues(const std::vector<std::u16string> &values, - const std::vector<std::u16string> &labels) override; + void UpdateAutofillPopupDataListValues( + base::span<const autofill::SelectOption> datalist) override; void PinPopupView() override; PopupOpenArgs GetReopenPopupArgs( autofill::AutofillSuggestionTriggerSource trigger_source) const override; std::vector<autofill::Suggestion> GetPopupSuggestions() const override; - void UpdatePopup(const std::vector<autofill::Suggestion>& suggestions, - autofill::PopupType popup_type, - autofill::AutofillSuggestionTriggerSource trigger_source) override; + void UpdatePopup(const std::vector<autofill::Suggestion> &suggestions, + autofill::FillingProduct main_filling_product, + autofill::AutofillSuggestionTriggerSource trigger_source) override{}; void HideAutofillPopup(autofill::PopupHidingReason reason) override; bool IsAutocompleteEnabled() const override; bool IsPasswordManagerEnabled() override; - void PropagateAutofillPredictionsDeprecated(autofill::AutofillDriver *, - const std::vector<autofill::FormStructure *> &) override; bool IsOffTheRecord() override; scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override; diff --git a/src/core/autofill_popup_controller.cpp b/src/core/autofill_popup_controller.cpp index a6baf5fc2..a4ce0b7f8 100644 --- a/src/core/autofill_popup_controller.cpp +++ b/src/core/autofill_popup_controller.cpp @@ -9,6 +9,8 @@ namespace QtWebEngineCore { +using SuggestionPosition = autofill::AutofillPopupDelegate::SuggestionPosition; + AutofillPopupController::AutofillPopupController(AutofillPopupControllerPrivate *dd) { Q_ASSERT(dd); @@ -26,7 +28,7 @@ void AutofillPopupController::setCurrentIndex(const QModelIndex &index) if (m_currentIndex.isValid()) { const autofill::Suggestion &suggestion = d->suggestions[m_currentIndex.row()]; - d->delegate->DidSelectSuggestion(suggestion, autofill::AutofillSuggestionTriggerSource::kFormControlElementClicked); + d->delegate->DidSelectSuggestion(suggestion); } Q_EMIT currentIndexChanged(index); @@ -79,7 +81,7 @@ void AutofillPopupController::acceptSuggestion() const int index = m_currentIndex.row(); const autofill::Suggestion &suggestion = d->suggestions[index]; - d->delegate->DidAcceptSuggestion(suggestion, index, autofill::AutofillSuggestionTriggerSource::kFormControlElementClicked); + d->delegate->DidAcceptSuggestion(suggestion, SuggestionPosition{ .row = index }); } void AutofillPopupController::notifyPopupShown() diff --git a/src/core/browser_accessibility_qt.cpp b/src/core/browser_accessibility_qt.cpp index de3347df3..ff3d21fb7 100644 --- a/src/core/browser_accessibility_qt.cpp +++ b/src/core/browser_accessibility_qt.cpp @@ -617,7 +617,7 @@ QAccessible::Role BrowserAccessibilityInterface::role() const return QAccessible::ComboBox; case ax::mojom::Role::kPortal: return QAccessible::Button; - case ax::mojom::Role::kPre: + case ax::mojom::Role::kPreDeprecated: return QAccessible::Section; case ax::mojom::Role::kProgressIndicator: return QAccessible::ProgressBar; diff --git a/src/core/browser_message_filter_qt.cpp b/src/core/browser_message_filter_qt.cpp index e8fcb994a..8708fc830 100644 --- a/src/core/browser_message_filter_qt.cpp +++ b/src/core/browser_message_filter_qt.cpp @@ -19,6 +19,7 @@ BrowserMessageFilterQt::BrowserMessageFilterQt(int /*render_process_id*/, Profil { } +#if BUILDFLAG(CONTENT_ENABLE_LEGACY_IPC) bool BrowserMessageFilterQt::OnMessageReceived(const IPC::Message& message) { IPC_BEGIN_MESSAGE_MAP(BrowserMessageFilterQt, message) @@ -31,6 +32,7 @@ bool BrowserMessageFilterQt::OnMessageReceived(const IPC::Message& message) IPC_END_MESSAGE_MAP() return true; } +#endif void BrowserMessageFilterQt::OnAllowStorageAccess(int /*render_frame_id*/, const GURL &origin_url, diff --git a/src/core/browser_message_filter_qt.h b/src/core/browser_message_filter_qt.h index 0f5721c82..c19d2f352 100644 --- a/src/core/browser_message_filter_qt.h +++ b/src/core/browser_message_filter_qt.h @@ -5,6 +5,7 @@ #define BROWSER_MESSAGE_FILTER_QT_H #include "base/functional/callback.h" +#include "content/common/buildflags.h" #include "content/public/browser/browser_message_filter.h" class GURL; @@ -20,8 +21,9 @@ public: BrowserMessageFilterQt(int render_process_id, Profile *profile); private: +#if BUILDFLAG(CONTENT_ENABLE_LEGACY_IPC) bool OnMessageReceived(const IPC::Message& message) override; - +#endif void OnAllowStorageAccess(int render_frame_id, const GURL &origin_url, 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/clipboard_qt.cpp b/src/core/clipboard_qt.cpp index 3f49c6e3c..1140164ae 100644 --- a/src/core/clipboard_qt.cpp +++ b/src/core/clipboard_qt.cpp @@ -9,10 +9,12 @@ #include "clipboard_change_observer.h" #include "type_conversion.h" +#include "base/containers/map_util.h" #include "base/logging.h" #include "base/strings/utf_offset_string_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/types/variant_util.h" +#include "base/types/optional_util.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/clipboard/custom_data_helper.h" #include "ui/base/clipboard/clipboard.h" @@ -128,8 +130,10 @@ void ClipboardQt::WriteText(base::StringPiece text) getUncommittedData()->setText(toQString(text)); } -void ClipboardQt::WriteHTML(base::StringPiece markup, absl::optional<base::StringPiece> source_url) +void ClipboardQt::WriteHTML(base::StringPiece markup, absl::optional<base::StringPiece> source_url, + ui::ClipboardContentType /*content_type*/) { + QString markup_string = toQString(markup); #if defined (Q_OS_MACOS) // We need to prepend the charset on macOS to prevent garbled Unicode characters @@ -234,7 +238,8 @@ void ClipboardQt::ReadAvailableTypes(ui::ClipboardBuffer type, if (mimeData->hasFormat(QString::fromLatin1(ui::kMimeTypeWebCustomData))) { const QByteArray customData = mimeData->data(QString::fromLatin1(ui::kMimeTypeWebCustomData)); - ui::ReadCustomDataTypes(customData.constData(), customData.size(), types); + const base::span custom_data(customData.constData(), (unsigned long)customData.size()); + ui::ReadCustomDataTypes(base::as_bytes(custom_data), types); } } @@ -342,7 +347,9 @@ void ClipboardQt::ReadCustomData(ui::ClipboardBuffer clipboard_type, const std:: if (!mimeData) return; const QByteArray customData = mimeData->data(QString::fromLatin1(ui::kMimeTypeWebCustomData)); - ui::ReadCustomDataForType(customData.constData(), customData.size(), type, result); + const base::span custom_data(customData.constData(), (unsigned long)customData.size()); + if (auto maybe_result = ui::ReadCustomDataForType(base::as_bytes(custom_data), type)) + *result = *std::move(maybe_result); } void ClipboardQt::ReadBookmark(const ui::DataTransferEndpoint *data_dst, std::u16string *title, std::string *url) const @@ -387,10 +394,9 @@ const ui::ClipboardSequenceNumberToken &ClipboardQt::GetSequenceNumber(ui::Clipb : clipboardChangeObserver()->getSelectionSequenceNumber(); } -const ui::DataTransferEndpoint *ClipboardQt::GetSource(ui::ClipboardBuffer buffer) const +absl::optional<ui::DataTransferEndpoint> ClipboardQt::GetSource(ui::ClipboardBuffer buffer) const { - auto it = m_dataSrc.find(buffer); - return it == m_dataSrc.end() ? nullptr : it->second.get(); + return base::OptionalFromPtr(base::FindPtrOrNull(m_dataSrc, buffer)); } void ClipboardQt::ReadFilenames(ui::ClipboardBuffer buffer, @@ -420,11 +426,6 @@ void ClipboardQt::WriteFilenames(std::vector<ui::FileInfo> filenames) getUncommittedData()->setUrls(urls); } -void ClipboardQt::WriteUnsanitizedHTML(base::StringPiece markup, absl::optional<base::StringPiece> source_url) -{ - WriteHTML(std::move(markup), std::move(source_url)); -} - #if defined(USE_OZONE) bool ClipboardQt::IsSelectionBufferAvailable() const { diff --git a/src/core/clipboard_qt.h b/src/core/clipboard_qt.h index 22f24cfe5..62dc2fbe6 100644 --- a/src/core/clipboard_qt.h +++ b/src/core/clipboard_qt.h @@ -36,7 +36,8 @@ public: std::vector<std::u16string> GetStandardFormats(ui::ClipboardBuffer buffer, const ui::DataTransferEndpoint *data_dst) const override; - const ui::DataTransferEndpoint *GetSource(ui::ClipboardBuffer buffer) const override; + absl::optional<ui::DataTransferEndpoint> GetSource(ui::ClipboardBuffer buffer) const override; + void ReadFilenames(ui::ClipboardBuffer buffer, const ui::DataTransferEndpoint *data_dst, std::vector<ui::FileInfo> *result) const override; @@ -48,7 +49,8 @@ protected: std::unique_ptr<ui::DataTransferEndpoint> data_src) override; void WriteText(base::StringPiece text) override; - void WriteHTML(base::StringPiece markup, absl::optional<base::StringPiece> source_url) override; + void WriteHTML(base::StringPiece markup, absl::optional<base::StringPiece> source_url, + ui::ClipboardContentType content_type) override; void WriteRTF(base::StringPiece rtf) override; void WriteBookmark(base::StringPiece title, base::StringPiece url) override; void WriteWebSmartPaste() override; @@ -56,7 +58,6 @@ protected: void WriteData(const ui::ClipboardFormatType &format, base::span<const uint8_t> data) override; void WriteSvg(base::StringPiece markup) override; void WriteFilenames(std::vector<ui::FileInfo> filenames) override; - void WriteUnsanitizedHTML(base::StringPiece markup, absl::optional<base::StringPiece> source_url) override; base::flat_map<ui::ClipboardBuffer, std::unique_ptr<ui::DataTransferEndpoint>> m_dataSrc; }; diff --git a/src/core/common/extensions/extensions_api_provider_qt.cpp b/src/core/common/extensions/extensions_api_provider_qt.cpp index 1c8e89747..5a0f6d891 100644 --- a/src/core/common/extensions/extensions_api_provider_qt.cpp +++ b/src/core/common/extensions/extensions_api_provider_qt.cpp @@ -57,7 +57,7 @@ bool ExtensionsAPIProviderQt::IsAPISchemaGenerated(const std::string &name) api::QtWebEngineGeneratedSchemas::IsGenerated(name); } -base::StringPiece ExtensionsAPIProviderQt::GetAPISchema(const std::string &name) +std::string_view ExtensionsAPIProviderQt::GetAPISchema(const std::string &name) { if (!api::GeneratedSchemas::Get(name).empty()) return api::GeneratedSchemas::Get(name); diff --git a/src/core/common/extensions/extensions_api_provider_qt.h b/src/core/common/extensions/extensions_api_provider_qt.h index 34e8bdd9f..b5e67aabf 100644 --- a/src/core/common/extensions/extensions_api_provider_qt.h +++ b/src/core/common/extensions/extensions_api_provider_qt.h @@ -18,7 +18,7 @@ public: void AddPermissionFeatures(FeatureProvider* provider) override; bool IsAPISchemaGenerated(const std::string& name) override; - base::StringPiece GetAPISchema(const std::string& name) override; + std::string_view GetAPISchema(const std::string &name) override; // Adds feature definitions to the given |provider| of the specified type. void AddManifestFeatures(FeatureProvider* provider) override { } diff --git a/src/core/compositor/display_skia_output_device.cpp b/src/core/compositor/display_skia_output_device.cpp index 0ca466fe8..ab891f814 100644 --- a/src/core/compositor/display_skia_output_device.cpp +++ b/src/core/compositor/display_skia_output_device.cpp @@ -31,7 +31,7 @@ public: m_texture = m_parent->m_contextState->gr_context()->createBackendTexture( m_shape.imageInfo.width(), m_shape.imageInfo.height(), colorType, - GrMipMapped::kNo, GrRenderable::kYes); + skgpu::Mipmapped::kNo, GrRenderable::kYes); DCHECK(m_texture.isValid()); DCHECK(m_texture.backend() == GrBackendApi::kOpenGL); diff --git a/src/core/compositor/native_skia_output_device_direct3d11.cpp b/src/core/compositor/native_skia_output_device_direct3d11.cpp index 352fa9f92..2f1ed5f61 100644 --- a/src/core/compositor/native_skia_output_device_direct3d11.cpp +++ b/src/core/compositor/native_skia_output_device_direct3d11.cpp @@ -56,6 +56,7 @@ QSGTexture *NativeSkiaOutputDeviceDirect3D11::texture(QQuickWindow *win, uint32_ status = resource->CreateSharedHandle(NULL, DXGI_SHARED_RESOURCE_READ, NULL, &sharedHandle); Q_ASSERT(status == S_OK); Q_ASSERT(sharedHandle); + resource->Release(); // Pass texture between two D3D devices: ID3D11Device1 *device = static_cast<ID3D11Device1 *>( diff --git a/src/core/compositor/native_skia_output_device_vulkan.cpp b/src/core/compositor/native_skia_output_device_vulkan.cpp index c2ad7a382..b775276f6 100644 --- a/src/core/compositor/native_skia_output_device_vulkan.cpp +++ b/src/core/compositor/native_skia_output_device_vulkan.cpp @@ -4,6 +4,7 @@ #include "native_skia_output_device_vulkan.h" #include "gpu/command_buffer/service/shared_image/shared_image_format_service_utils.h" +#include "ui/base/ozone_buildflags.h" #include <QtGui/qvulkaninstance.h> #include <QtGui/qvulkanfunctions.h> @@ -11,17 +12,17 @@ #include <QtQuick/qsgtexture.h> #if defined(USE_OZONE) -#include "ui/ozone/buildflags.h" -#if BUILDFLAG(OZONE_PLATFORM_X11) +#if BUILDFLAG(IS_OZONE_X11) // We need to define USE_VULKAN_XCB for proper vulkan function pointers. // Avoiding it may lead to call wrong vulkan functions. // This is originally defined in chromium/gpu/vulkan/BUILD.gn. #define USE_VULKAN_XCB -#endif // BUILDFLAG(OZONE_PLATFORM_X11) +#endif // BUILDFLAG(IS_OZONE_X11) #include "gpu/vulkan/vulkan_function_pointers.h" - #include "components/viz/common/gpu/vulkan_context_provider.h" #include "gpu/vulkan/vulkan_device_queue.h" +#include "third_party/skia/include/gpu/vk/GrVkTypes.h" +#include "third_party/skia/include/gpu/ganesh/vk/GrVkBackendSurface.h" #endif // defined(USE_OZONE) namespace QtWebEngineCore { @@ -84,7 +85,8 @@ QSGTexture *NativeSkiaOutputDeviceVulkan::texture(QQuickWindow *win, uint32_t te return nullptr; } - backendTexture.getVkImageInfo(&vkImageInfo); + GrBackendTextures::GetVkImageInfo(backendTexture, &vkImageInfo); + if (vkImageInfo.fAlloc.fMemory == VK_NULL_HANDLE) { qWarning("VULKAN: Unable to access Vulkan memory."); return nullptr; @@ -187,6 +189,7 @@ QSGTexture *NativeSkiaOutputDeviceVulkan::texture(QQuickWindow *win, uint32_t te Q_ASSERT(status == S_OK); status = resource->CreateSharedHandle(NULL, DXGI_SHARED_RESOURCE_READ, NULL, &sharedHandle); Q_ASSERT(status == S_OK); + resource->Release(); if (!sharedHandle) qFatal("VULKAN: Unable to extract shared handle."); @@ -200,7 +203,7 @@ QSGTexture *NativeSkiaOutputDeviceVulkan::texture(QQuickWindow *win, uint32_t te importedImageCreateInfo.pNext = &externalMemoryImageCreateInfo; importedImageCreateInfo.flags = 0; importedImageCreateInfo.imageType = VK_IMAGE_TYPE_2D; - importedImageCreateInfo.format = gpu::ToVkFormat(m_frontBuffer->sharedImageFormat()); + importedImageCreateInfo.format = gpu::ToVkFormatSinglePlanar(m_frontBuffer->sharedImageFormat()); importedImageCreateInfo.extent.width = static_cast<uint32_t>(size().width()); importedImageCreateInfo.extent.height = static_cast<uint32_t>(size().height()); importedImageCreateInfo.extent.depth = 1; diff --git a/src/core/configure/BUILD.root.gn.in b/src/core/configure/BUILD.root.gn.in index 986db5026..0e913f1d4 100644 --- a/src/core/configure/BUILD.root.gn.in +++ b/src/core/configure/BUILD.root.gn.in @@ -92,6 +92,8 @@ config("cpp20_config") { # Chromium is built with C++20 if (is_win) { cflags_cc = [ "/std:c++20" ] + } else if(is_gcc) { + cflags_cc = [ "-std=gnu++20" ] } else { cflags_cc = [ "-std=c++20" ] } @@ -207,6 +209,8 @@ source_set("qtwebengine_spellcheck_sources") { sources = [ "//chrome/browser/spellchecker/spell_check_host_chrome_impl.cc", "//chrome/browser/spellchecker/spell_check_host_chrome_impl.h", + "//chrome/browser/spellchecker/spell_check_initialization_host_impl.cc", + "//chrome/browser/spellchecker/spell_check_initialization_host_impl.h", "//chrome/browser/spellchecker/spellcheck_custom_dictionary.cc", "//chrome/browser/spellchecker/spellcheck_custom_dictionary.h", "//chrome/browser/spellchecker/spellcheck_factory.cc", @@ -233,6 +237,7 @@ source_set("qtwebengine_spellcheck_sources") { source_set("devtools_sources") { configs += [ ":cpp20_config" ] deps = [ + "//chrome/app:generated_resources", "//components/zoom", "//third_party/blink/public/mojom:mojom_platform", ] @@ -278,6 +283,7 @@ source_set("qtwebengine_sources") { "//components/performance_manager", "//components/permissions:permissions_common", "//components/plugins/renderer/", + "//components/compose:buildflags", "//content/browser/resources/quota:resources", "//extensions/buildflags:buildflags", "//pdf:buildflags", @@ -347,12 +353,12 @@ source_set("qtwebengine_sources") { "//chrome/browser/tab_contents/form_interaction_tab_helper.h", "//chrome/browser/tab_contents/web_contents_collection.cc", "//chrome/browser/tab_contents/web_contents_collection.h", - "//chrome/browser/ui/webui/device_log_ui.cc", - "//chrome/browser/ui/webui/device_log_ui.h", - "//chrome/browser/ui/webui/devtools_ui.cc", - "//chrome/browser/ui/webui/devtools_ui.h", - "//chrome/browser/ui/webui/devtools_ui_data_source.cc", - "//chrome/browser/ui/webui/devtools_ui_data_source.h", + "//chrome/browser/ui/webui/device_log/device_log_ui.cc", + "//chrome/browser/ui/webui/device_log/device_log_ui.h", + "//chrome/browser/ui/webui/devtools/devtools_ui.cc", + "//chrome/browser/ui/webui/devtools/devtools_ui.h", + "//chrome/browser/ui/webui/devtools/devtools_ui_data_source.cc", + "//chrome/browser/ui/webui/devtools/devtools_ui_data_source.h", "//chrome/browser/ui/webui/net_internals/net_internals_ui.cc", "//chrome/browser/ui/webui/net_internals/net_internals_ui.h", "//chrome/browser/ui/webui/user_actions/user_actions_ui.cc", @@ -364,7 +370,6 @@ source_set("qtwebengine_sources") { "//chrome/common/chrome_switches.cc", "//chrome/common/chrome_switches.h", "//chrome/common/pref_names.h", - "//chrome/common/url_constants.cc", "//chrome/common/url_constants.h", "//chrome/common/webui_url_constants.cc", "//chrome/common/webui_url_constants.h", @@ -558,6 +563,7 @@ group("qtwebengine_resources") { "//chrome/browser:resources", "//chrome/browser/resources:component_extension_resources", "//chrome/common:resources", + "//chrome/browser/resources/device_log:resources", "//components/resources:components_resources", ":qtwebengine_repack_resources", ":qtwebengine_repack_resources_100", @@ -573,9 +579,11 @@ repack("qtwebengine_repack_resources") { "$root_gen_dir/chrome/accessibility_resources.pak", "$root_gen_dir/chrome/common_resources.pak", "$root_gen_dir/chrome/dev_ui_browser_resources.pak", + "$root_gen_dir/chrome/device_log_resources.pak", "$root_gen_dir/chrome/net_internals_resources.pak", "$root_gen_dir/components/components_resources.pak", "$root_gen_dir/components/dev_ui_components_resources.pak", + "$root_gen_dir/components/ukm_resources.pak", "$root_gen_dir/content/attribution_internals_resources.pak", "$root_gen_dir/content/browser/resources/media/media_internals_resources.pak", "$root_gen_dir/content/browser/tracing/tracing_resources.pak", @@ -599,8 +607,10 @@ repack("qtwebengine_repack_resources") { "//chrome/browser/resources/accessibility:resources", "//chrome/browser/resources/net_internals:resources", "//chrome/common:resources_grit", + "//chrome/browser/resources/device_log:resources_grit", "//components/resources:components_resources_grit", "//components/resources:dev_ui_components_resources_grit", + "//components/ukm/debug:resources", "//content/browser/resources/attribution_reporting:resources", "//content/browser/resources/gpu:resources", "//content/browser/resources/histograms:resources_grit", diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp index 7192edbc2..341c46295 100644 --- a/src/core/content_browser_client_qt.cpp +++ b/src/core/content_browser_client_qt.cpp @@ -16,7 +16,6 @@ #include "components/performance_manager/embedder/performance_manager_registry.h" #include "components/performance_manager/public/performance_manager.h" #include "content/browser/web_contents/web_contents_impl.h" -#include "content/public/browser/browser_main_runner.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/client_certificate_delegate.h" @@ -25,15 +24,12 @@ #include "content/public/browser/navigation_handle.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" -#include "content/public/browser/render_view_host.h" #include "content/public/browser/shared_cors_origin_access_list.h" #include "content/public/browser/url_loader_request_interceptor.h" #include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_user_data.h" #include "content/public/browser/web_contents_view_delegate.h" #include "content/public/browser/web_ui_url_loader_factory.h" #include "content/public/common/content_switches.h" -#include "content/public/common/main_function_params.h" #include "content/public/common/url_constants.h" #include "content/public/common/user_agent.h" #include "extensions/buildflags/buildflags.h" @@ -57,7 +53,6 @@ #include "profile_adapter.h" #include "browser_main_parts_qt.h" -#include "browser_message_filter_qt.h" #include "certificate_error_controller.h" #include "client_cert_select_controller.h" #include "custom_handlers/protocol_handler_registry_factory.h" @@ -70,7 +65,6 @@ #include "net/proxying_restricted_cookie_manager_qt.h" #include "net/proxying_url_loader_factory_qt.h" #include "net/system_network_context_manager.h" -#include "platform_notification_service_qt.h" #include "profile_qt.h" #include "profile_io_data_qt.h" #include "renderer_host/user_resource_controller_host.h" @@ -80,7 +74,6 @@ #include "web_contents_adapter.h" #include "web_contents_delegate_qt.h" #include "web_contents_view_qt.h" -#include "web_engine_context.h" #include "web_engine_library_info.h" #include "web_engine_settings.h" #include "authenticator_request_client_delegate_qt.h" @@ -88,6 +81,10 @@ #include "api/qwebenginecookiestore_p.h" #include "api/qwebengineurlrequestinfo_p.h" +#if BUILDFLAG(CONTENT_ENABLE_LEGACY_IPC) +#include "browser_message_filter_qt.h" +#endif + #if QT_CONFIG(webengine_geolocation) #include "base/memory/ptr_util.h" #include "location_provider_qt.h" @@ -95,6 +92,7 @@ #if QT_CONFIG(webengine_spellchecker) #include "chrome/browser/spellchecker/spell_check_host_chrome_impl.h" +#include "chrome/browser/spellchecker/spell_check_initialization_host_impl.h" #include "chrome/browser/spellchecker/spellcheck_factory.h" #include "chrome/browser/spellchecker/spellcheck_service.h" #include "components/spellcheck/browser/pref_names.h" @@ -147,12 +145,11 @@ #include "components/pdf/browser/pdf_navigation_throttle.h" #include "components/pdf/browser/pdf_url_loader_request_interceptor.h" #include "components/pdf/browser/pdf_document_helper.h" - -#include "printing/pdf_document_helper_client_qt.h" #endif #if BUILDFLAG(ENABLE_PDF) && BUILDFLAG(ENABLE_EXTENSIONS) #include "extensions/pdf_iframe_navigation_throttle_qt.h" +#include "printing/pdf_document_helper_client_qt.h" #endif #include <QGuiApplication> @@ -190,7 +187,7 @@ bool IsHandledProtocol(base::StringPiece scheme) return true; return false; } -} +} // namespace url namespace QtWebEngineCore { @@ -228,7 +225,7 @@ void ContentBrowserClientQt::RenderProcessWillLaunch(content::RenderProcessHost #endif #if QT_CONFIG(webengine_webrtc) && QT_CONFIG(webengine_extensions) - WebRtcLoggingController::AttachToRenderProcessHost(host, WebEngineContext::current()->webRtcLogUploader()); + WebRtcLoggingController::AttachToRenderProcessHost(host); #endif // Allow requesting custom schemes. @@ -240,12 +237,13 @@ void ContentBrowserClientQt::RenderProcessWillLaunch(content::RenderProcessHost // FIXME: Add a settings variable to enable/disable the file scheme. policy->GrantRequestScheme(id, url::kFileScheme); profileAdapter->userResourceController()->renderProcessStartedWithHost(host); +#if BUILDFLAG(CONTENT_ENABLE_LEGACY_IPC) host->AddFilter(new BrowserMessageFilterQt(id, profile)); #if BUILDFLAG(ENABLE_EXTENSIONS) host->AddFilter(new extensions::ExtensionMessageFilter(id, profile)); host->AddFilter(new extensions::MessagingAPIMessageFilter(id, profile)); #endif //ENABLE_EXTENSIONS - +#endif // CONTENT_ENABLE_LEGACY_IPC bool is_incognito_process = profile->IsOffTheRecord(); mojo::AssociatedRemote<qtwebengine::mojom::RendererConfiguration> renderer_configuration; host->GetChannel()->GetRemoteAssociatedInterface(&renderer_configuration); @@ -276,14 +274,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); } @@ -390,8 +388,9 @@ void ContentBrowserClientQt::BindHostReceiverForRenderer(content::RenderProcessH mojo::GenericPendingReceiver receiver) { #if QT_CONFIG(webengine_spellchecker) - if (auto host_receiver = receiver.As<spellcheck::mojom::SpellCheckHost>()) { - SpellCheckHostChromeImpl::Create(render_process_host->GetID(), std::move(host_receiver)); + if (auto host_receiver = receiver.As<spellcheck::mojom::SpellCheckInitializationHost>()) { + SpellCheckInitializationHostImpl::Create(render_process_host->GetID(), + std::move(host_receiver)); return; } #endif @@ -434,6 +433,15 @@ void ContentBrowserClientQt::RegisterBrowserInterfaceBindersForFrame( mojo::BinderMapWithContext<content::RenderFrameHost *> *map) { map->Add<network_hints::mojom::NetworkHintsHandler>(base::BindRepeating(&BindNetworkHintsHandler)); +#if QT_CONFIG(webengine_spellchecker) + map->Add<spellcheck::mojom::SpellCheckHost>(base::BindRepeating( + [](content::RenderFrameHost *frame_host, + mojo::PendingReceiver<spellcheck::mojom::SpellCheckHost> receiver) { + SpellCheckHostChromeImpl::Create(frame_host->GetProcess()->GetID(), + std::move(receiver)); + })); +#endif + #if BUILDFLAG(ENABLE_EXTENSIONS) map->Add<extensions::mime_handler::MimeHandlerService>(base::BindRepeating(&BindMimeHandlerService)); map->Add<extensions::mime_handler::BeforeUnloadControl>(base::BindRepeating(&BindBeforeUnloadControl)); @@ -460,13 +468,9 @@ void ContentBrowserClientQt::ExposeInterfacesToRenderer(service_manager::BinderR { if (auto *manager = performance_manager::PerformanceManagerRegistry::GetInstance()) manager->CreateProcessNodeAndExposeInterfacesToRendererProcess(registry, render_process_host); -#if BUILDFLAG(ENABLE_EXTENSIONS) - associated_registry->AddInterface<extensions::mojom::EventRouter>( - base::BindRepeating(&extensions::EventRouter::BindForRenderer, render_process_host->GetID())); - associated_registry->AddInterface<guest_view::mojom::GuestViewHost>( - base::BindRepeating(&extensions::ExtensionsGuestView::CreateForComponents, render_process_host->GetID())); - associated_registry->AddInterface<extensions::mojom::GuestView>( - base::BindRepeating(&extensions::ExtensionsGuestView::CreateForExtensions, render_process_host->GetID())); +#if BUILDFLAG(ENABLE_EXTENSIONS) && BUILDFLAG(ENABLE_EXTENSIONS_LEGACY_IPC) + associated_registry->AddInterface<extensions::mojom::EventRouter>(base::BindRepeating( + &extensions::EventRouter::BindForRenderer, render_process_host->GetID())); #else Q_UNUSED(associated_registry); #endif @@ -502,13 +506,14 @@ void ContentBrowserClientQt::RegisterAssociatedInterfaceBindersForRenderFrameHos extensions::ExtensionWebContentsObserverQt::BindLocalFrameHost(std::move(receiver), render_frame_host); }, &rfh)); #endif - associated_registry.AddInterface<autofill::mojom::AutofillDriver>( - base::BindRepeating( - [](content::RenderFrameHost *render_frame_host, - mojo::PendingAssociatedReceiver<autofill::mojom::AutofillDriver> receiver) { - autofill::ContentAutofillDriverFactory::BindAutofillDriver(std::move(receiver), render_frame_host); - }, &rfh)); -#if BUILDFLAG(ENABLE_PDF) + associated_registry.AddInterface<autofill::mojom::AutofillDriver>(base::BindRepeating( + [](content::RenderFrameHost *render_frame_host, + mojo::PendingAssociatedReceiver<autofill::mojom::AutofillDriver> receiver) { + autofill::ContentAutofillDriverFactory::BindAutofillDriver(render_frame_host, + std::move(receiver)); + }, + &rfh)); +#if BUILDFLAG(ENABLE_PDF) && BUILDFLAG(ENABLE_EXTENSIONS) associated_registry.AddInterface<pdf::mojom::PdfService>( base::BindRepeating( [](content::RenderFrameHost *render_frame_host, @@ -517,6 +522,12 @@ void ContentBrowserClientQt::RegisterAssociatedInterfaceBindersForRenderFrameHos }, &rfh)); #endif // BUILDFLAG(ENABLE_PDF) ContentBrowserClient::RegisterAssociatedInterfaceBindersForRenderFrameHost(rfh, associated_registry); +#if BUILDFLAG(ENABLE_EXTENSIONS) + associated_registry.AddInterface<guest_view::mojom::GuestViewHost>(base::BindRepeating( + &extensions::ExtensionsGuestView::CreateForComponents, rfh.GetGlobalId())); + associated_registry.AddInterface<extensions::mojom::GuestView>(base::BindRepeating( + &extensions::ExtensionsGuestView::CreateForExtensions, rfh.GetGlobalId())); +#endif } bool ContentBrowserClientQt::CanCreateWindow( @@ -764,7 +775,8 @@ std::vector<std::unique_ptr<blink::URLLoaderThrottle>> ContentBrowserClientQt::CreateURLLoaderThrottles( const network::ResourceRequest &request, content::BrowserContext *browser_context, const base::RepeatingCallback<content::WebContents *()> & /*wc_getter*/, - content::NavigationUIData * /*navigation_ui_data*/, int frame_tree_node_id) + content::NavigationUIData * /*navigation_ui_data*/, int frame_tree_node_id, + absl::optional<int64_t> navigation_id) { std::vector<std::unique_ptr<blink::URLLoaderThrottle>> result; result.push_back(std::make_unique<ProtocolHandlerThrottle>( @@ -883,13 +895,10 @@ bool ContentBrowserClientQt::HasErrorPage(int httpStatusCode, content::WebConten } std::unique_ptr<content::LoginDelegate> ContentBrowserClientQt::CreateLoginDelegate( - const net::AuthChallengeInfo &authInfo, - content::WebContents *web_contents, - const content::GlobalRequestID & /*request_id*/, - bool /*is_main_frame*/, - const GURL &url, - scoped_refptr<net::HttpResponseHeaders> /*response_headers*/, - bool first_auth_attempt, + const net::AuthChallengeInfo &authInfo, content::WebContents *web_contents, + content::BrowserContext *browser_context, const content::GlobalRequestID & /*request_id*/, + bool /*is_main_frame*/, const GURL &url, + scoped_refptr<net::HttpResponseHeaders> /*response_headers*/, bool first_auth_attempt, LoginAuthRequiredCallback auth_required_callback) { auto loginDelegate = std::make_unique<LoginDelegateQt>(authInfo, web_contents, url, first_auth_attempt, std::move(auth_required_callback)); @@ -1029,22 +1038,20 @@ std::vector<base::FilePath> ContentBrowserClientQt::GetNetworkContextsParentDire toFilePath(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)) }; } -void ContentBrowserClientQt::RegisterNonNetworkNavigationURLLoaderFactories(int frame_tree_node_id, - ukm::SourceIdObj ukm_source_id, - NonNetworkURLLoaderFactoryMap *factories) +void ContentBrowserClientQt::RegisterNonNetworkNavigationURLLoaderFactories( + int frame_tree_node_id, NonNetworkURLLoaderFactoryMap *factories) { content::WebContents *web_contents = content::WebContents::FromFrameTreeNodeId(frame_tree_node_id); Profile *profile = Profile::FromBrowserContext(web_contents->GetBrowserContext()); ProfileAdapter *profileAdapter = static_cast<ProfileQt *>(profile)->profileAdapter(); for (const QByteArray &scheme : profileAdapter->customUrlSchemes()) - factories->emplace(scheme.toStdString(), CreateCustomURLLoaderFactory(profileAdapter)); + factories->emplace(scheme.toStdString(), CreateCustomURLLoaderFactory(profileAdapter, web_contents)); #if BUILDFLAG(ENABLE_EXTENSIONS) - factories->emplace( - extensions::kExtensionScheme, - extensions::CreateExtensionNavigationURLLoaderFactory(profile, ukm_source_id, - !!extensions::WebViewGuest::FromWebContents(web_contents))); + factories->emplace(extensions::kExtensionScheme, + extensions::CreateExtensionNavigationURLLoaderFactory( + profile, !!extensions::WebViewGuest::FromWebContents(web_contents))); #endif } @@ -1055,7 +1062,7 @@ void ContentBrowserClientQt::RegisterNonNetworkWorkerMainResourceURLLoaderFactor ProfileAdapter *profileAdapter = static_cast<ProfileQt *>(profile)->profileAdapter(); for (const QByteArray &scheme : profileAdapter->customUrlSchemes()) - factories->emplace(scheme.toStdString(), CreateCustomURLLoaderFactory(profileAdapter)); + factories->emplace(scheme.toStdString(), CreateCustomURLLoaderFactory(profileAdapter, nullptr)); #if BUILDFLAG(ENABLE_EXTENSIONS) factories->emplace( @@ -1073,7 +1080,7 @@ void ContentBrowserClientQt::RegisterNonNetworkServiceWorkerUpdateURLLoaderFacto for (const QByteArray &scheme : profileAdapter->customUrlSchemes()) { if (const url::CustomScheme *cs = url::CustomScheme::FindScheme(scheme.toStdString())) { if (cs->flags & url::CustomScheme::ServiceWorkersAllowed) - factories->emplace(scheme.toStdString(), CreateCustomURLLoaderFactory(profileAdapter)); + factories->emplace(scheme.toStdString(), CreateCustomURLLoaderFactory(profileAdapter, nullptr)); } } @@ -1093,15 +1100,15 @@ void ContentBrowserClientQt::RegisterNonNetworkSubresourceURLLoaderFactories(int Profile *profile = Profile::FromBrowserContext(process_host->GetBrowserContext()); ProfileAdapter *profileAdapter = static_cast<ProfileQt *>(profile)->profileAdapter(); - for (const QByteArray &scheme : profileAdapter->customUrlSchemes()) - factories->emplace(scheme.toStdString(), CreateCustomURLLoaderFactory(profileAdapter)); - content::RenderFrameHost *frame_host = content::RenderFrameHost::FromID(render_process_id, render_frame_id); content::WebContents *web_contents = content::WebContents::FromRenderFrameHost(frame_host); GURL url; if (web_contents) url = web_contents->GetVisibleURL(); + for (const QByteArray &scheme : profileAdapter->customUrlSchemes()) + factories->emplace(scheme.toStdString(), CreateCustomURLLoaderFactory(profileAdapter, web_contents)); + bool is_background_page = false; #if BUILDFLAG(ENABLE_EXTENSIONS) is_background_page = extensions::GetViewType(web_contents) == extensions::mojom::ViewType::kExtensionBackgroundPage; @@ -1309,7 +1316,7 @@ void ContentBrowserClientQt::CreateWebSocket( std::move(factory).Run(to_url, std::move(headers), std::move(handshake_client), mojo::NullRemote(), mojo::NullRemote()); } -void ContentBrowserClientQt::SiteInstanceGotProcess(content::SiteInstance *site_instance) +void ContentBrowserClientQt::SiteInstanceGotProcessAndSite(content::SiteInstance *site_instance) { #if BUILDFLAG(ENABLE_EXTENSIONS) content::BrowserContext *context = site_instance->GetBrowserContext(); diff --git a/src/core/content_browser_client_qt.h b/src/core/content_browser_client_qt.h index 7d8e98028..333b08ea2 100644 --- a/src/core/content_browser_client_qt.h +++ b/src/core/content_browser_client_qt.h @@ -10,17 +10,10 @@ namespace content { class BrowserContext; class BrowserMainParts; - -#if QT_CONFIG(webengine_pepper_plugins) -class BrowserPpapiHost; -#endif - class DevToolsManagerDelegate; class RenderFrameHost; class RenderProcessHost; -class ResourceContext; class WebContents; -struct MainFunctionParams; struct Referrer; } // namespace content @@ -150,15 +143,13 @@ public: void GetAdditionalMappedFilesForChildProcess(const base::CommandLine& command_line, int child_process_id, content::PosixFileDescriptorInfo* mappings) override; #endif - std::unique_ptr<content::LoginDelegate> CreateLoginDelegate( - const net::AuthChallengeInfo &auth_info, - content::WebContents *web_contents, - const content::GlobalRequestID& request_id, - bool is_request_for_main_frame, - const GURL &url, - scoped_refptr<net::HttpResponseHeaders> response_headers, - bool first_auth_attempt, - LoginAuthRequiredCallback auth_required_callback) override; + std::unique_ptr<content::LoginDelegate> + CreateLoginDelegate(const net::AuthChallengeInfo &auth_info, content::WebContents *web_contents, + content::BrowserContext *browser_context, + const content::GlobalRequestID &request_id, bool is_request_for_main_frame, + const GURL &url, scoped_refptr<net::HttpResponseHeaders> response_headers, + bool first_auth_attempt, + LoginAuthRequiredCallback auth_required_callback) override; bool HandleExternalProtocol( const GURL &url, @@ -174,10 +165,12 @@ public: content::RenderFrameHost *initiator_document, mojo::PendingRemote<network::mojom::URLLoaderFactory> *out_factory) override; - std::vector<std::unique_ptr<blink::URLLoaderThrottle>> CreateURLLoaderThrottles( - const network::ResourceRequest &request, content::BrowserContext *browser_context, - const base::RepeatingCallback<content::WebContents *()> &wc_getter, - content::NavigationUIData *navigation_ui_data, int frame_tree_node_id) override; + std::vector<std::unique_ptr<blink::URLLoaderThrottle>> + CreateURLLoaderThrottles(const network::ResourceRequest &request, + content::BrowserContext *browser_context, + const base::RepeatingCallback<content::WebContents *()> &wc_getter, + content::NavigationUIData *navigation_ui_data, int frame_tree_node_id, + absl::optional<int64_t> navigation_id) override; std::vector<std::unique_ptr<content::NavigationThrottle>> CreateThrottlesForNavigation( content::NavigationHandle *navigation_handle) override; @@ -214,9 +207,8 @@ public: cert_verifier::mojom::CertVerifierCreationParams *cert_verifier_creation_params) override; std::vector<base::FilePath> GetNetworkContextsParentDirectory() override; - void RegisterNonNetworkNavigationURLLoaderFactories(int frame_tree_node_id, - ukm::SourceIdObj ukm_source_id, - NonNetworkURLLoaderFactoryMap *factories) override; + void RegisterNonNetworkNavigationURLLoaderFactories( + int frame_tree_node_id, NonNetworkURLLoaderFactoryMap *factories) override; void RegisterNonNetworkSubresourceURLLoaderFactories(int render_process_id, int render_frame_id, const absl::optional<url::Origin>& request_initiator_origin, NonNetworkURLLoaderFactoryMap *factories) override; @@ -224,7 +216,7 @@ public: NonNetworkURLLoaderFactoryMap* factories) override; void RegisterNonNetworkServiceWorkerUpdateURLLoaderFactories(content::BrowserContext* browser_context, NonNetworkURLLoaderFactoryMap* factories) override; - void SiteInstanceGotProcess(content::SiteInstance *site_instance) override; + void SiteInstanceGotProcessAndSite(content::SiteInstance *site_instance) override; base::flat_set<std::string> GetPluginMimeTypesWithExternalHandlers(content::BrowserContext *browser_context) override; std::unique_ptr<content::WebContentsViewDelegate> GetWebContentsViewDelegate(content::WebContents *web_contents) override; diff --git a/src/core/desktop_screen_qt.cpp b/src/core/desktop_screen_qt.cpp index fb68f7b09..2b45e91d1 100644 --- a/src/core/desktop_screen_qt.cpp +++ b/src/core/desktop_screen_qt.cpp @@ -2,7 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "desktop_screen_qt.h" - +#include "ui/base/ozone_buildflags.h" #include "ui/display/display.h" #include "type_conversion.h" @@ -10,14 +10,11 @@ #include <QGuiApplication> #include <QScreen> -#if defined(USE_OZONE) -#include "ui/ozone/buildflags.h" -#if BUILDFLAG(OZONE_PLATFORM_X11) +#if BUILDFLAG(IS_LINUX) && BUILDFLAG(IS_OZONE_X11) #define USE_XSCREENSAVER #include "ui/base/x/x11_screensaver.h" #include "ui/base/x/x11_util.h" #endif -#endif #include <cmath> diff --git a/src/core/doc/src/qtwebengine-overview.qdoc b/src/core/doc/src/qtwebengine-overview.qdoc index 6eccc669e..3a5d30338 100644 --- a/src/core/doc/src/qtwebengine-overview.qdoc +++ b/src/core/doc/src/qtwebengine-overview.qdoc @@ -44,8 +44,13 @@ dedicated profile for a \e {private browsing} mode, where no information is permanently saved. \note The \QWE Widgets module uses the \l{Qt Quick Scene Graph}{Qt Quick scene graph} - to compose the elements of a web page into one view. This means that the UI process - requires OpenGL ES 2.0 or OpenGL 2.0 for its rendering. + to compose the elements of a web page into one view. + + The content is rendered using the graphics card (GPU) capabilities. The scene + graph, in turn, relies on the Qt Rendering Hardware Interface as an abstraction + layer for the different capabilities and APIs a GPU might feature. For more + advice on how to tweak the rendering pipeline, see therefore + \l{Rendering via the Qt Rendering Hardware Interface}. \section2 Qt WebEngine Module diff --git a/src/core/doc/src/qwebengine-licensing.qdoc b/src/core/doc/src/qwebengine-licensing.qdoc index 796a9664d..936ceff97 100644 --- a/src/core/doc/src/qwebengine-licensing.qdoc +++ b/src/core/doc/src/qwebengine-licensing.qdoc @@ -5,20 +5,49 @@ \group qtwebengine-licensing \title Qt WebEngine Licensing -The Qt specific parts of the \QWE module are dual-licensed -under Commercial and GNU Lesser General Public License (LGPLv3). -In addition, the module contains code licensed under LGPLv2. - -The module includes a snapshot of Chromium. As such, users need to -respect the licenses of Chromium, and third-party code included in -Chromium. The arguably most restrictive license to be respected by -all users is LGPLv2.1. +The \QWE module uses Chromium to provide most of its +functionality. During the build process, Chromium becomes +a part of the \l{Qt WebEngine Core} library. +Therefore, when distributing \QWE, users need to comply +to both the licenses of the \QWE part as developed under +the Qt Project, as well as the licenses that are part of +Chromium. + +The Qt specific parts of the \QWE module are available under +commercial licenses from The Qt Company. Alternatively, +they are available under GNU Lesser General Public License v3.0, +or GNU General Public License v3.0, or +GNU General Public License v2.0. + +The Chromium part contains code available under various +licenses, with the most restrictive license being the +\e{GNU Lesser General Public License v2.1} (LGPL 2.1). +For a full list, see \l{Third-Party Licenses} below. + +\section1 Complying with LGPL 2.1 + +The Qt Company allows commercial customers to +distribute the source code of the \QWE module alongside the +\QWE binaries, and allows recipients to customize and build +\QWE from sources. This includes building and using +such a modified \QWE with an application or system using +an otherwise commercially licensed Qt. + +The Qt Company also keeps the Qt specific parts of the \QWE +module available under the GNU Lesser General Public License v3.0, +or the GNU General Public License v3.0, or +the GNU General Public License v2.0, even if WebEngine is released +as part of a commercial-only Long-Term Support release (LTS, see +also \l{Long-Term Support releases}). + +\section1 Third-Party Licenses + +Third party licenses included in the sources as part of Chromium +are found below. \note Any GPL licenses listed below are only used to access Linux system -resources. \QWE does not link to nor distribute GPL binary code, and -it does not affect users of \QWE. - -Third party licenses included in the sources are: +resources. The \QWE libraries and plugins does not link to nor distribute +GPL binary code, and it does not affect users of \QWE. */ /*! diff --git a/src/core/doc/src/qwebenginepage_lgpl.qdoc b/src/core/doc/src/qwebenginepage_lgpl.qdoc index c2515cd13..630ea507e 100644 --- a/src/core/doc/src/qwebenginepage_lgpl.qdoc +++ b/src/core/doc/src/qwebenginepage_lgpl.qdoc @@ -245,6 +245,7 @@ /*! \enum QWebEnginePage::PermissionPolicy + \deprecated [6.8] Replaced by QWebEnginePermission::State. This enum describes the permission policies that the user may set for data or device access: @@ -273,6 +274,7 @@ /*! \enum QWebEnginePage::Feature + \deprecated [6.8] Replaced by QWebEnginePermission::Feature. This enum describes the platform feature access categories that the user may be asked to grant or deny access to: @@ -735,6 +737,8 @@ \brief The zoom factor for the page content. Valid values are within the range from \c{0.25} to \c{5.0}. The default factor is \c{1.0}. + + \sa zoomFactorChanged() */ /*! @@ -772,11 +776,13 @@ during page destruction. When QWebEnginePage is deleted, the callback is triggered with an invalid value and it is not safe to use the corresponding QWebEnginePage or QWebEngineView instance inside it. - \sa scripts(), QWebEngineScript::ScriptWorldId, {Script Injection} + \sa scripts(), QWebEngineScript::ScriptWorldId, QWebEngineFrame::runJavaScript, {Script Injection} */ /*! \fn void QWebEnginePage::setFeaturePermission(const QUrl &securityOrigin, Feature feature, PermissionPolicy policy) + \deprecated [6.8] Use QWebEnginePermission's \l {QWebEnginePermission::grant} {grant}(), + \l {QWebEnginePermission::deny} {deny}(), and \l {QWebEnginePermission::reset} {reset}() functions instead. Sets the permission for the web site identified by \a securityOrigin to use \a feature to \a policy. @@ -790,6 +796,7 @@ /*! \fn void QWebEnginePage::featurePermissionRequested(const QUrl &securityOrigin, Feature feature) + \deprecated [6.8] Use permissionRequested() instead. This signal is emitted when the web site identified by \a securityOrigin requests to make use of the resource or device identified by \a feature. @@ -799,6 +806,7 @@ /*! \fn void QWebEnginePage::featurePermissionRequestCanceled(const QUrl &securityOrigin, Feature feature) + \deprecated [6.8] This signal is no longer emitted. This signal is emitted when the web site identified by \a securityOrigin cancels a previously issued request to make use of \a feature. @@ -808,6 +816,15 @@ */ /*! + \fn void QWebEnginePage::permissionRequested(QWebEnginePermission permission) + \since 6.8 + + This signal is emitted when a web site requests to make use of a feature (e.g. geolocation access, + permission to send notifications). The \a permission object can queried for the requesting URL + and the \c{QWebEnginePermission::Feature} it's asking for, as well as to grant or deny permission. +*/ + +/*! \fn void QWebEnginePage::titleChanged(const QString &title) This signal is emitted whenever the title of the page changes. @@ -836,3 +853,12 @@ \sa QWebEngineWebAuthUxRequest */ + +/*! + \fn void QWebEnginePage::zoomFactorChanged(qreal factor) + \since 6.8 + + This signal is emitted whenever the zoom \a factor for the page changes. + + \sa zoomFactor(), setZoomFactor() +*/ diff --git a/src/core/download_manager_delegate_qt.cpp b/src/core/download_manager_delegate_qt.cpp index c0fd0d3ee..7ccd063ff 100644 --- a/src/core/download_manager_delegate_qt.cpp +++ b/src/core/download_manager_delegate_qt.cpp @@ -47,16 +47,13 @@ download::DownloadItem *DownloadManagerDelegateQt::findDownloadById(quint32 down return dlm->GetDownload(downloadId); } -void DownloadManagerDelegateQt::cancelDownload(content::DownloadTargetCallback callback) +void DownloadManagerDelegateQt::cancelDownload(download::DownloadTargetCallback callback) { - std::move(callback).Run(base::FilePath(), - download::DownloadItem::TARGET_DISPOSITION_PROMPT, - download::DownloadDangerType::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT, - download::DownloadItem::UNKNOWN, - base::FilePath(), - base::FilePath(), - std::string(), - download::DownloadInterruptReason::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED); + download::DownloadTargetInfo target_info; + target_info.target_disposition = download::DownloadItem::TARGET_DISPOSITION_PROMPT; + target_info.danger_type = download::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT; + target_info.interrupt_reason = download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED; + std::move(callback).Run(std::move(target_info)); } bool DownloadManagerDelegateQt::cancelDownload(quint32 downloadId) @@ -87,7 +84,7 @@ void DownloadManagerDelegateQt::removeDownload(quint32 downloadId) } bool DownloadManagerDelegateQt::DetermineDownloadTarget(download::DownloadItem *item, - content::DownloadTargetCallback *callback) + download::DownloadTargetCallback *callback) { m_currentId = item->GetId(); @@ -95,13 +92,15 @@ bool DownloadManagerDelegateQt::DetermineDownloadTarget(download::DownloadItem * // will already return that the file exists. Forced file paths seem to be only used for // store downloads and other special downloads, so they might never end up here anyway. if (!item->GetForcedFilePath().empty()) { - std::move(*callback).Run(item->GetForcedFilePath(), download::DownloadItem::TARGET_DISPOSITION_PROMPT, - download::DownloadDangerType::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, - download::DownloadItem::VALIDATED, - item->GetForcedFilePath(), - item->GetFileNameToReportUser(), - item->GetMimeType(), - download::DownloadInterruptReason::DOWNLOAD_INTERRUPT_REASON_NONE); + download::DownloadTargetInfo target_info; + target_info.target_disposition = download::DownloadItem::TARGET_DISPOSITION_PROMPT; + target_info.danger_type = download::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT; + target_info.insecure_download_status = download::DownloadItem::VALIDATED; + target_info.mime_type = item->GetMimeType(); + target_info.display_name = item->GetFileNameToReportUser(); + target_info.target_path = item->GetForcedFilePath(); + target_info.intermediate_path = item->GetForcedFilePath(); + std::move(*callback).Run(std::move(target_info)); return true; } @@ -211,14 +210,17 @@ bool DownloadManagerDelegateQt::DetermineDownloadTarget(download::DownloadItem * } base::FilePath filePathForCallback(toFilePathString(suggestedFile.absoluteFilePath())); - std::move(*callback).Run(filePathForCallback, - download::DownloadItem::TARGET_DISPOSITION_OVERWRITE, - download::DownloadDangerType::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT, - download::DownloadItem::VALIDATED, - filePathForCallback.AddExtension(toFilePathString("download")), - base::FilePath(), - item->GetMimeType(), - download::DownloadInterruptReason::DOWNLOAD_INTERRUPT_REASON_NONE); + download::DownloadTargetInfo target_info; + target_info.target_disposition = download::DownloadItem::TARGET_DISPOSITION_OVERWRITE; + target_info.danger_type = download::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT; + target_info.insecure_download_status = download::DownloadItem::VALIDATED; + target_info.mime_type = item->GetMimeType(); + target_info.intermediate_path = + filePathForCallback.AddExtension(toFilePathString("download")); + target_info.display_name = base::FilePath(); + target_info.target_path = filePathForCallback; + target_info.interrupt_reason = download::DOWNLOAD_INTERRUPT_REASON_NONE; + std::move(*callback).Run(std::move(target_info)); } else cancelDownload(std::move(*callback)); @@ -306,7 +308,10 @@ void DownloadManagerDelegateQt::ChooseSavePath(content::WebContents *web_content if (!info.accepted) return; - std::move(callback).Run(toFilePath(info.path), static_cast<content::SavePageType>(info.savePageFormat), + content::SavePackagePathPickedParams params; + params.file_path = toFilePath(info.path); + params.save_type = static_cast<content::SavePageType>(info.savePageFormat); + std::move(callback).Run(std::move(params), base::BindOnce(&DownloadManagerDelegateQt::savePackageDownloadCreated, m_weakPtrFactory.GetWeakPtr())); } diff --git a/src/core/download_manager_delegate_qt.h b/src/core/download_manager_delegate_qt.h index cc6d49764..e7dfad29d 100644 --- a/src/core/download_manager_delegate_qt.h +++ b/src/core/download_manager_delegate_qt.h @@ -35,7 +35,7 @@ public: void GetNextId(content::DownloadIdCallback callback) override; bool DetermineDownloadTarget(download::DownloadItem *item, - content::DownloadTargetCallback *callback) override; + download::DownloadTargetCallback *callback) override; void GetSaveDir(content::BrowserContext* browser_context, base::FilePath* website_save_dir, @@ -56,7 +56,7 @@ public: void OnDownloadDestroyed(download::DownloadItem *download) override; private: - void cancelDownload(content::DownloadTargetCallback callback); + void cancelDownload(download::DownloadTargetCallback callback); download::DownloadItem *findDownloadById(quint32 downloadId); void savePackageDownloadCreated(download::DownloadItem *download); ProfileAdapter *m_profileAdapter; diff --git a/src/core/extensions/extension_host_delegate_qt.cpp b/src/core/extensions/extension_host_delegate_qt.cpp index aa408a544..16133a598 100644 --- a/src/core/extensions/extension_host_delegate_qt.cpp +++ b/src/core/extensions/extension_host_delegate_qt.cpp @@ -86,10 +86,9 @@ void ExtensionHostDelegateQt::ProcessMediaAccessRequest(content::WebContents *we }); } -bool ExtensionHostDelegateQt::CheckMediaAccessPermission(content::RenderFrameHost *render_frame_host, - const GURL &security_origin, - blink::mojom::MediaStreamType type, - const Extension *extension) +bool ExtensionHostDelegateQt::CheckMediaAccessPermission( + content::RenderFrameHost *render_frame_host, const url::Origin &security_origin, + blink::mojom::MediaStreamType type, const Extension *extension) { Q_UNUSED(render_frame_host); Q_UNUSED(security_origin); diff --git a/src/core/extensions/extension_host_delegate_qt.h b/src/core/extensions/extension_host_delegate_qt.h index 1c2688933..38b5d4a2f 100644 --- a/src/core/extensions/extension_host_delegate_qt.h +++ b/src/core/extensions/extension_host_delegate_qt.h @@ -27,7 +27,7 @@ public: content::MediaResponseCallback callback, const Extension *extension) override; bool CheckMediaAccessPermission(content::RenderFrameHost *render_frame_host, - const GURL &security_origin, + const url::Origin &security_origin, blink::mojom::MediaStreamType type, const Extension *extension) override; content::PictureInPictureResult EnterPictureInPicture(content::WebContents *web_contents) override; diff --git a/src/core/extensions/extensions_browser_client_qt.cpp b/src/core/extensions/extensions_browser_client_qt.cpp index 19fc6c808..36151cee5 100644 --- a/src/core/extensions/extensions_browser_client_qt.cpp +++ b/src/core/extensions/extensions_browser_client_qt.cpp @@ -542,5 +542,10 @@ media_device_salt::MediaDeviceSaltService *ExtensionsBrowserClientQt::GetMediaDe // Not needed for QWE return nullptr; } - +mojo::PendingRemote<network::mojom::URLLoaderFactory> +ExtensionsBrowserClientQt::GetControlledFrameEmbedderURLLoader( + int frame_tree_node_id, content::BrowserContext *browser_context) +{ + return mojo::PendingRemote<network::mojom::URLLoaderFactory>(); +} } // namespace extensions diff --git a/src/core/extensions/extensions_browser_client_qt.h b/src/core/extensions/extensions_browser_client_qt.h index bcc8f142b..34a846311 100644 --- a/src/core/extensions/extensions_browser_client_qt.h +++ b/src/core/extensions/extensions_browser_client_qt.h @@ -108,6 +108,10 @@ public: media_device_salt::MediaDeviceSaltService *GetMediaDeviceSaltService(content::BrowserContext *context) override; + mojo::PendingRemote<network::mojom::URLLoaderFactory> + GetControlledFrameEmbedderURLLoader(int frame_tree_node_id, + content::BrowserContext *browser_context) override; + private: // Support for extension APIs. std::unique_ptr<ExtensionsAPIClient> api_client_; diff --git a/src/core/extensions/file_system_delegate_qt.cpp b/src/core/extensions/file_system_delegate_qt.cpp index 7c1c5bbd8..6c5b33919 100644 --- a/src/core/extensions/file_system_delegate_qt.cpp +++ b/src/core/extensions/file_system_delegate_qt.cpp @@ -41,36 +41,21 @@ FileEntryPickerQt::FileEntryPickerQt( FileEntryPickerQt::~FileEntryPickerQt() = default; -void FileEntryPickerQt::FileSelected(const base::FilePath &path, - int index, - void *params) +void FileEntryPickerQt::FileSelected(const ui::SelectedFileInfo &file, int index, void *params) { - MultiFilesSelected({path}, params); + MultiFilesSelected({ file }, params); } -void FileEntryPickerQt::FileSelectedWithExtraInfo(const ui::SelectedFileInfo& file, - int index, - void *params) -{ - FileSelected(file.file_path, index, params); -} - -void FileEntryPickerQt::MultiFilesSelected(const std::vector<base::FilePath>& files, - void* params) +void FileEntryPickerQt::MultiFilesSelected(const std::vector<ui::SelectedFileInfo> &files, + void *params) { Q_UNUSED(params); - std::move(m_filesSelectedCallback).Run(files); - delete this; -} - -void FileEntryPickerQt::MultiFilesSelectedWithExtraInfo( - const std::vector<ui::SelectedFileInfo> &files, - void *params) -{ std::vector<base::FilePath> paths; - for (const auto& file : files) + for (const auto &file : files) { paths.push_back(file.file_path); - MultiFilesSelected(paths, params); + } + std::move(m_filesSelectedCallback).Run(paths); + delete this; } void FileEntryPickerQt::FileSelectionCanceled(void *params) diff --git a/src/core/extensions/file_system_delegate_qt.h b/src/core/extensions/file_system_delegate_qt.h index 1e9d87c38..01b56fa56 100644 --- a/src/core/extensions/file_system_delegate_qt.h +++ b/src/core/extensions/file_system_delegate_qt.h @@ -19,6 +19,10 @@ namespace content { class BrowserContext; } // namespace content +namespace ui { +struct SelectedFileInfo; +} + namespace extensions { class FileEntryPickerQt : public ui::SelectFileDialog::Listener { @@ -38,17 +42,8 @@ private: ~FileEntryPickerQt() override; // ui::SelectFileDialog::Listener implementation. - void FileSelected(const base::FilePath &path, - int index, - void *params) override; - void FileSelectedWithExtraInfo(const ui::SelectedFileInfo &file, - int index, - void *params) override; - void MultiFilesSelected(const std::vector<base::FilePath> &files, - void *params) override; - void MultiFilesSelectedWithExtraInfo( - const std::vector<ui::SelectedFileInfo> &files, - void *params) override; + void FileSelected(const ui::SelectedFileInfo &file, int index, void *params) override; + void MultiFilesSelected(const std::vector<ui::SelectedFileInfo> &files, void *params) override; void FileSelectionCanceled(void *params) override; FileSystemDelegate::FilesSelectedCallback m_filesSelectedCallback; diff --git a/src/core/favicon_service_factory_qt.cpp b/src/core/favicon_service_factory_qt.cpp index dd2a1979a..1ed33d559 100644 --- a/src/core/favicon_service_factory_qt.cpp +++ b/src/core/favicon_service_factory_qt.cpp @@ -46,7 +46,7 @@ std::unique_ptr<history::HistoryBackendClient> HistoryClientQt::CreateBackendCli return nullptr; } -void HistoryClientQt::UpdateBookmarkLastUsedTime(const base::Uuid &, base::Time /*time*/) +void HistoryClientQt::UpdateBookmarkLastUsedTime(int64_t /*bookmark_node_id*/, base::Time /*time*/) { } diff --git a/src/core/favicon_service_factory_qt.h b/src/core/favicon_service_factory_qt.h index 55d5f3b33..0c3bfd7b5 100644 --- a/src/core/favicon_service_factory_qt.h +++ b/src/core/favicon_service_factory_qt.h @@ -51,7 +51,7 @@ public: history::CanAddURLCallback GetThreadSafeCanAddURLCallback() const override; void NotifyProfileError(sql::InitStatus init_status, const std::string &diagnostics) override; std::unique_ptr<history::HistoryBackendClient> CreateBackendClient() override; - void UpdateBookmarkLastUsedTime(const base::Uuid &, base::Time) override; + void UpdateBookmarkLastUsedTime(int64_t bookmark_node_id, base::Time time) override; }; class HistoryServiceFactoryQt : public BrowserContextKeyedServiceFactory diff --git a/src/core/file_picker_controller.cpp b/src/core/file_picker_controller.cpp index 9b4521358..9f9789296 100644 --- a/src/core/file_picker_controller.cpp +++ b/src/core/file_picker_controller.cpp @@ -9,6 +9,7 @@ #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/file_select_listener.h" #include "ui/shell_dialogs/select_file_dialog.h" +#include "ui/shell_dialogs/selected_file_info.h" #include <QtCore/qcoreapplication.h> #include <QDir> @@ -214,7 +215,8 @@ void FilePickerController::filesSelectedInChooser(const QStringList &filesList) if (files.empty()) d_ptr->fileSystemAccessDialogListener->FileSelectionCanceled(nullptr); else - d_ptr->fileSystemAccessDialogListener->MultiFilesSelected(files, nullptr); + d_ptr->fileSystemAccessDialogListener->MultiFilesSelected( + ui::FilePathListToSelectedFileInfoList(files), nullptr); } } diff --git a/src/core/file_system_access/file_system_access_permission_context_qt.h b/src/core/file_system_access/file_system_access_permission_context_qt.h index 06fbfae3f..b569c81c0 100644 --- a/src/core/file_system_access/file_system_access_permission_context_qt.h +++ b/src/core/file_system_access/file_system_access_permission_context_qt.h @@ -53,6 +53,8 @@ public: base::FilePath GetWellKnownDirectoryPath(blink::mojom::WellKnownDirectory directory, const url::Origin &origin) override; std::u16string GetPickerTitle(const blink::mojom::FilePickerOptionsPtr &) override; void NotifyEntryMoved(const url::Origin &, const base::FilePath &, const base::FilePath &) override; + void OnFileCreatedFromShowSaveFilePicker(const GURL &file_picker_binding_context, + const storage::FileSystemURL &url) override{}; void NavigatedAwayFromOrigin(const url::Origin &origin); content::BrowserContext *profile() const { return m_profile; } diff --git a/src/core/media_capture_devices_dispatcher.cpp b/src/core/media_capture_devices_dispatcher.cpp index 6dc45c442..73885b6f2 100644 --- a/src/core/media_capture_devices_dispatcher.cpp +++ b/src/core/media_capture_devices_dispatcher.cpp @@ -13,11 +13,13 @@ #include "web_engine_settings.h" #include "base/strings/strcat.h" +#include "blink/public/common/page/page_zoom.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/desktop_media_id.h" #include "content/public/browser/desktop_streams_registry.h" +#include "content/public/browser/host_zoom_map.h" #include "content/public/browser/media_capture_devices.h" #include "content/public/browser/render_process_host.h" #include "media/audio/audio_device_description.h" @@ -107,6 +109,27 @@ media::mojom::CaptureHandlePtr CreateCaptureHandle(content::WebContents *capture return result; } +absl::optional<int> GetZoomLevel(content::WebContents *capturer, + const content::DesktopMediaID &captured_id) +{ + content::RenderFrameHost *const captured_rfh = + content::RenderFrameHost::FromID(captured_id.web_contents_id.render_process_id, + captured_id.web_contents_id.main_render_frame_id); + if (!captured_rfh || !captured_rfh->IsActive()) { + return absl::nullopt; + } + + content::WebContents *const captured_wc = + content::WebContents::FromRenderFrameHost(captured_rfh); + if (!captured_wc) { + return absl::nullopt; + } + + double zoom_level = + blink::PageZoomLevelToZoomFactor(content::HostZoomMap::GetZoomLevel(captured_wc)); + return std::round(100 * zoom_level); +} + // Based on chrome/browser/media/webrtc/desktop_capture_devices_util.cc: media::mojom::DisplayMediaInformationPtr DesktopMediaIDToDisplayMediaInformation(content::WebContents *capturer, const url::Origin &capturer_origin, @@ -122,6 +145,7 @@ media::mojom::DisplayMediaInformationPtr DesktopMediaIDToDisplayMediaInformation #endif // defined(USE_AURA) media::mojom::CaptureHandlePtr capture_handle; + int zoom_level = 100; switch (media_id.type) { case content::DesktopMediaID::TYPE_SCREEN: display_surface = media::mojom::DisplayCaptureSurfaceType::MONITOR; @@ -137,12 +161,16 @@ media::mojom::DisplayMediaInformationPtr DesktopMediaIDToDisplayMediaInformation display_surface = media::mojom::DisplayCaptureSurfaceType::BROWSER; cursor = media::mojom::CursorCaptureType::MOTION; capture_handle = CreateCaptureHandle(capturer, capturer_origin, media_id); + if (base::FeatureList::IsEnabled(features::kCapturedSurfaceControlKillswitch)) { + zoom_level = GetZoomLevel(capturer, media_id).value_or(zoom_level); + } break; case content::DesktopMediaID::TYPE_NONE: break; } - return media::mojom::DisplayMediaInformation::New(display_surface, logical_surface, cursor, std::move(capture_handle)); + return media::mojom::DisplayMediaInformation::New(display_surface, logical_surface, cursor, + std::move(capture_handle), zoom_level); } diff --git a/src/core/net/custom_url_loader_factory.cpp b/src/core/net/custom_url_loader_factory.cpp index 4274def99..b91a1289b 100644 --- a/src/core/net/custom_url_loader_factory.cpp +++ b/src/core/net/custom_url_loader_factory.cpp @@ -4,6 +4,7 @@ #include "custom_url_loader_factory.h" #include "base/strings/stringprintf.h" +#include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "mojo/public/cpp/bindings/pending_receiver.h" @@ -24,7 +25,11 @@ #include "api/qwebengineurlscheme.h" #include "net/url_request_custom_job_proxy.h" #include "profile_adapter.h" +#include "qwebengineloadinginfo.h" #include "type_conversion.h" +#include "web_contents_adapter_client.h" +#include "web_contents_delegate_qt.h" +#include "web_contents_view_qt.h" #include <QtCore/qbytearray.h> #include <QtCore/qfile.h> @@ -46,11 +51,12 @@ public: static void CreateAndStart(const network::ResourceRequest &request, mojo::PendingReceiver<network::mojom::URLLoader> loader, mojo::PendingRemote<network::mojom::URLLoaderClient> client_remote, - QPointer<ProfileAdapter> profileAdapter) + QPointer<ProfileAdapter> profileAdapter, + content::WebContents *webContents) { // CustomURLLoader will handle its own life-cycle, and delete when // the client lets go. - auto *customUrlLoader = new CustomURLLoader(request, std::move(loader), std::move(client_remote), profileAdapter); + auto *customUrlLoader = new CustomURLLoader(request, std::move(loader), std::move(client_remote), profileAdapter, webContents); customUrlLoader->Start(); } @@ -85,10 +91,12 @@ private: CustomURLLoader(const network::ResourceRequest &request, mojo::PendingReceiver<network::mojom::URLLoader> loader, mojo::PendingRemote<network::mojom::URLLoaderClient> client_remote, - QPointer<ProfileAdapter> profileAdapter) + QPointer<ProfileAdapter> profileAdapter, + content::WebContents *webContents) // ### We can opt to run the url-loader on the UI thread instead : m_taskRunner(content::GetIOThreadTaskRunner({})) , m_proxy(new URLRequestCustomJobProxy(this, request.url.scheme(), profileAdapter)) + , m_webContents(webContents) , m_receiver(this, std::move(loader)) , m_client(std::move(client_remote)) , m_request(request) @@ -348,6 +356,14 @@ private: m_client->OnReceiveResponse(std::move(m_head), mojo::ScopedDataPipeConsumerHandle(), absl::nullopt); CompleteWithFailure(net::Error(error)); } + void notifySuccess() override + { + if (m_webContents) { + WebContentsDelegateQt *delegate = + static_cast<WebContentsDelegateQt *>(m_webContents->GetDelegate()); + delegate->emitLoadSucceeded(toQt(m_request.url)); + } + } void notifyReadyRead() override { DCHECK(m_taskRunner->RunsTasksInCurrentSequence()); @@ -432,6 +448,7 @@ private: scoped_refptr<base::SequencedTaskRunner> m_taskRunner; scoped_refptr<URLRequestCustomJobProxy> m_proxy; + content::WebContents *m_webContents; mojo::Receiver<network::mojom::URLLoader> m_receiver; mojo::Remote<network::mojom::URLLoaderClient> m_client; @@ -454,9 +471,10 @@ private: class CustomURLLoaderFactory : public network::mojom::URLLoaderFactory { public: - CustomURLLoaderFactory(ProfileAdapter *profileAdapter, mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver) + CustomURLLoaderFactory(ProfileAdapter *profileAdapter, content::WebContents *webContents, mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver) : m_taskRunner(content::GetIOThreadTaskRunner({})) , m_profileAdapter(profileAdapter) + , m_webContents(webContents) { m_receivers.set_disconnect_handler(base::BindRepeating( &CustomURLLoaderFactory::OnDisconnect, base::Unretained(this))); @@ -480,7 +498,7 @@ public: m_taskRunner->PostTask(FROM_HERE, base::BindOnce(&CustomURLLoader::CreateAndStart, request, std::move(loader), std::move(client), - m_profileAdapter)); + m_profileAdapter, m_webContents)); } @@ -495,24 +513,24 @@ public: delete this; } - static mojo::PendingRemote<network::mojom::URLLoaderFactory> Create(ProfileAdapter *profileAdapter) + static mojo::PendingRemote<network::mojom::URLLoaderFactory> Create(ProfileAdapter *profileAdapter, content::WebContents *webContents) { mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_remote; - new CustomURLLoaderFactory(profileAdapter, pending_remote.InitWithNewPipeAndPassReceiver()); + new CustomURLLoaderFactory(profileAdapter, webContents, pending_remote.InitWithNewPipeAndPassReceiver()); return pending_remote; } const scoped_refptr<base::SequencedTaskRunner> m_taskRunner; mojo::ReceiverSet<network::mojom::URLLoaderFactory> m_receivers; QPointer<ProfileAdapter> m_profileAdapter; + content::WebContents *m_webContents; }; } // namespace -mojo::PendingRemote<network::mojom::URLLoaderFactory> CreateCustomURLLoaderFactory(ProfileAdapter *profileAdapter) +mojo::PendingRemote<network::mojom::URLLoaderFactory> CreateCustomURLLoaderFactory(ProfileAdapter *profileAdapter, content::WebContents *webContents) { - return CustomURLLoaderFactory::Create(profileAdapter); + return CustomURLLoaderFactory::Create(profileAdapter, webContents); } } // namespace QtWebEngineCore - diff --git a/src/core/net/custom_url_loader_factory.h b/src/core/net/custom_url_loader_factory.h index fb0c74627..e4a767c85 100644 --- a/src/core/net/custom_url_loader_factory.h +++ b/src/core/net/custom_url_loader_factory.h @@ -17,6 +17,9 @@ #include "mojo/public/cpp/bindings/pending_remote.h" +namespace content { +class WebContents; +} namespace network { namespace mojom { class URLLoaderFactory; @@ -26,7 +29,7 @@ class URLLoaderFactory; namespace QtWebEngineCore { class ProfileAdapter; -mojo::PendingRemote<network::mojom::URLLoaderFactory> CreateCustomURLLoaderFactory(ProfileAdapter *profileAdapter); +mojo::PendingRemote<network::mojom::URLLoaderFactory> CreateCustomURLLoaderFactory(ProfileAdapter *profileAdapter, content::WebContents *webContents); } // namespace QtWebEngineCore diff --git a/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp b/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp index 159fa28ca..319d3a566 100644 --- a/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp +++ b/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp @@ -30,6 +30,9 @@ #include <tuple> namespace { + +constexpr uint32_t kFullPageMimeHandlerDataPipeSize = 512U; + void ClearAllButFrameAncestors(network::mojom::URLResponseHead *response_head) { response_head->headers->RemoveHeader("Content-Security-Policy"); @@ -121,11 +124,7 @@ void PluginResponseInterceptorURLLoaderThrottle::WillProcessResponse(const GURL if (extension_id == extension_misc::kPdfExtensionId && response_head->headers) ClearAllButFrameAncestors(response_head); - MimeTypesHandler::ReportUsedHandler(extension_id); - - std::string view_id = base::Uuid::GenerateRandomV4().AsLowercaseString(); - // The string passed down to the original client with the response body. - std::string payload = view_id; + const std::string stream_id = base::Uuid::GenerateRandomV4().AsLowercaseString(); mojo::PendingRemote<network::mojom::URLLoader> dummy_new_loader; std::ignore = dummy_new_loader.InitWithNewPipeAndPassReceiver(); @@ -133,20 +132,20 @@ void PluginResponseInterceptorURLLoaderThrottle::WillProcessResponse(const GURL mojo::PendingReceiver<network::mojom::URLLoaderClient> new_client_receiver = new_client.BindNewPipeAndPassReceiver(); - - uint32_t data_pipe_size = 64U; + const std::string internal_id = base::UnguessableToken::Create().ToString(); // Provide the MimeHandlerView code a chance to override the payload. This is // the case where the resource is handled by frame-based MimeHandlerView. - *defer = extensions::MimeHandlerViewAttachHelper::OverrideBodyForInterceptedResponse( - m_frame_tree_node_id, response_url, response_head->mime_type, view_id, - &payload, &data_pipe_size, - base::BindOnce( - &PluginResponseInterceptorURLLoaderThrottle::ResumeLoad, - weak_factory_.GetWeakPtr())); + const std::string payload = + extensions::MimeHandlerViewAttachHelper::OverrideBodyForInterceptedResponse( + m_frame_tree_node_id, response_url, response_head->mime_type, stream_id, + internal_id, + base::BindOnce(&PluginResponseInterceptorURLLoaderThrottle::ResumeLoad, + weak_factory_.GetWeakPtr())); + *defer = true; mojo::ScopedDataPipeProducerHandle producer_handle; mojo::ScopedDataPipeConsumerHandle consumer_handle; - CHECK_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(data_pipe_size, producer_handle, consumer_handle)); + CHECK_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(kFullPageMimeHandlerDataPipeSize, producer_handle, consumer_handle)); uint32_t len = static_cast<uint32_t>(payload.size()); CHECK_EQ(MOJO_RESULT_OK, @@ -186,11 +185,10 @@ void PluginResponseInterceptorURLLoaderThrottle::WillProcessResponse(const GURL bool embedded = m_request_destination != network::mojom::RequestDestination::kDocument; content::GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, - base::BindOnce( - &extensions::StreamsPrivateAPI::SendExecuteMimeTypeHandlerEvent, - extension_id, view_id, embedded, m_frame_tree_node_id, - std::move(transferrable_loader), response_url)); + FROM_HERE, + base::BindOnce(&extensions::StreamsPrivateAPI::SendExecuteMimeTypeHandlerEvent, + extension_id, stream_id, embedded, m_frame_tree_node_id, + std::move(transferrable_loader), response_url, internal_id)); } void PluginResponseInterceptorURLLoaderThrottle::ResumeLoad() diff --git a/src/core/net/proxy_config_service_qt.cpp b/src/core/net/proxy_config_service_qt.cpp index fcce08550..d74ec699d 100644 --- a/src/core/net/proxy_config_service_qt.cpp +++ b/src/core/net/proxy_config_service_qt.cpp @@ -27,7 +27,6 @@ net::ProxyServer ProxyConfigServiceQt::fromQNetworkProxy(const QNetworkProxy &qt return net::ProxyServer::FromSchemeHostAndPort(net::ProxyServer::SCHEME_HTTP, host, port); case QNetworkProxy::NoProxy: case QNetworkProxy::DefaultProxy: - return net::ProxyServer(net::ProxyServer::SCHEME_DIRECT, net::HostPortPair()); default: return net::ProxyServer(net::ProxyServer::SCHEME_INVALID, net::HostPortPair()); } diff --git a/src/core/net/proxying_restricted_cookie_manager_qt.cpp b/src/core/net/proxying_restricted_cookie_manager_qt.cpp index d4d5cc4ab..29e6de968 100644 --- a/src/core/net/proxying_restricted_cookie_manager_qt.cpp +++ b/src/core/net/proxying_restricted_cookie_manager_qt.cpp @@ -67,13 +67,14 @@ void ProxyingRestrictedCookieManagerQt::GetAllForUrl(const GURL &url, const net::SiteForCookies &site_for_cookies, const url::Origin &top_frame_origin, bool has_storage_access, network::mojom::CookieManagerGetOptionsPtr options, + bool is_ad_tagged, GetAllForUrlCallback callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); if (allowCookies(url, site_for_cookies)) { underlying_restricted_cookie_manager_->GetAllForUrl(url, site_for_cookies, top_frame_origin, has_storage_access, - std::move(options), std::move(callback)); + std::move(options), is_ad_tagged, std::move(callback)); } else { std::move(callback).Run(std::vector<net::CookieWithAccessResult>()); } @@ -121,7 +122,7 @@ void ProxyingRestrictedCookieManagerQt::SetCookieFromString(const GURL &url, underlying_restricted_cookie_manager_->SetCookieFromString(url, site_for_cookies, top_frame_origin, has_storage_access, cookie, std::move(callback)); } else { - std::move(callback).Run(false, false); // FIXME: is true, true in aw_proxying_restricted_cookie_manager.cc though.. + std::move(callback).Run(); } } @@ -129,6 +130,7 @@ void ProxyingRestrictedCookieManagerQt::GetCookiesString(const GURL &url, const net::SiteForCookies &site_for_cookies, const url::Origin &top_frame_origin, bool has_storage_access, bool get_version_shared_memory, + bool is_ad_tagged, GetCookiesStringCallback callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); @@ -136,6 +138,7 @@ void ProxyingRestrictedCookieManagerQt::GetCookiesString(const GURL &url, if (allowCookies(url, site_for_cookies)) { underlying_restricted_cookie_manager_->GetCookiesString(url, site_for_cookies, top_frame_origin, has_storage_access, get_version_shared_memory, + is_ad_tagged, std::move(callback)); } else { std::move(callback).Run(network::mojom::kInvalidCookieVersion, base::ReadOnlySharedMemoryRegion(), ""); diff --git a/src/core/net/proxying_restricted_cookie_manager_qt.h b/src/core/net/proxying_restricted_cookie_manager_qt.h index faf0545c3..ba30a448e 100644 --- a/src/core/net/proxying_restricted_cookie_manager_qt.h +++ b/src/core/net/proxying_restricted_cookie_manager_qt.h @@ -29,6 +29,7 @@ public: const url::Origin &top_frame_origin, bool has_storage_access, network::mojom::CookieManagerGetOptionsPtr options, + bool is_ad_tagged, GetAllForUrlCallback callback) override; void SetCanonicalCookie(const net::CanonicalCookie& cookie, @@ -54,6 +55,7 @@ public: const net::SiteForCookies &site_for_cookies, const url::Origin &top_frame_origin, bool has_storage_access, bool get_version_shared_memory, + bool is_ad_tagged, GetCookiesStringCallback callback) override; void CookiesEnabledFor(const GURL &url, const net::SiteForCookies &site_for_cookies, diff --git a/src/core/net/proxying_url_loader_factory_qt.cpp b/src/core/net/proxying_url_loader_factory_qt.cpp index 3a83ed7ea..220f44023 100644 --- a/src/core/net/proxying_url_loader_factory_qt.cpp +++ b/src/core/net/proxying_url_loader_factory_qt.cpp @@ -65,6 +65,7 @@ ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeCspReport, blink::mojom ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypePluginResource, blink::mojom::ResourceType::kPluginResource) ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadMainFrame, blink::mojom::ResourceType::kNavigationPreloadMainFrame) ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadSubFrame, blink::mojom::ResourceType::kNavigationPreloadSubFrame) +ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeJson, blink::mojom::ResourceType::kJson) ASSERT_ENUMS_MATCH(QWebEngineUrlRequestInfo::ResourceTypeLast, blink::mojom::ResourceType::kMaxValue) extern WebContentsAdapterClient::NavigationType pageTransitionToNavigationType(ui::PageTransition transition); diff --git a/src/core/net/ssl_host_state_delegate_qt.cpp b/src/core/net/ssl_host_state_delegate_qt.cpp index 41967f14e..809a95c8d 100644 --- a/src/core/net/ssl_host_state_delegate_qt.cpp +++ b/src/core/net/ssl_host_state_delegate_qt.cpp @@ -127,9 +127,9 @@ void SSLHostStateDelegateQt::SetHttpsEnforcementForHost(const std::string &host, // Intentional no-op see aw_ssl_host_state_delegate } -bool SSLHostStateDelegateQt::IsHttpsEnforcedForHost(const std::string &host, content::StoragePartition *storage_partition) +bool SSLHostStateDelegateQt::IsHttpsEnforcedForUrl(const GURL &url, + content::StoragePartition *storage_partition) { - // Intentional no-op return false; } diff --git a/src/core/net/ssl_host_state_delegate_qt.h b/src/core/net/ssl_host_state_delegate_qt.h index 0b3d7974c..f210f028a 100644 --- a/src/core/net/ssl_host_state_delegate_qt.h +++ b/src/core/net/ssl_host_state_delegate_qt.h @@ -39,11 +39,13 @@ public: bool DidHostRunInsecureContent(const std::string &host, int child_id, InsecureContentType content_type) override; void AllowHttpForHost(const std::string &host, content::StoragePartition *web_contents) override; bool IsHttpAllowedForHost(const std::string &host, content::StoragePartition *web_contents) override; - void SetHttpsEnforcementForHost(const std::string &host, bool enforce, content::StoragePartition *storage_partition) override; - bool IsHttpsEnforcedForHost(const std::string &host, content::StoragePartition *web_contents) override; + void SetHttpsEnforcementForHost(const std::string &host, bool enforce, + content::StoragePartition *storage_partition) override; void RevokeUserAllowExceptions(const std::string &host) override; bool HasAllowException(const std::string &host, content::StoragePartition *web_contents) override; bool HasAllowExceptionForAnyHost(content::StoragePartition *storage_partition) override; + bool IsHttpsEnforcedForUrl(const GURL &url, + content::StoragePartition *storage_partition) override; private: std::map<std::string, CertPolicy> m_certPolicyforHost; diff --git a/src/core/net/system_network_context_manager.cpp b/src/core/net/system_network_context_manager.cpp index 439d1066c..78098529d 100644 --- a/src/core/net/system_network_context_manager.cpp +++ b/src/core/net/system_network_context_manager.cpp @@ -236,10 +236,7 @@ void SystemNetworkContextManager::OnNetworkServiceCreated(network::mojom::Networ log_list_mojo.push_back(std::move(log_info)); } - network_service->UpdateCtLogList( - std::move(log_list_mojo), - certificate_transparency::GetLogListTimestamp(), - base::DoNothing()); + network_service->UpdateCtLogList(std::move(log_list_mojo), base::DoNothing()); // The system NetworkContext is created first network_service_network_context_.reset(); diff --git a/src/core/net/url_request_custom_job_delegate.cpp b/src/core/net/url_request_custom_job_delegate.cpp index c877de669..fb6b605a4 100644 --- a/src/core/net/url_request_custom_job_delegate.cpp +++ b/src/core/net/url_request_custom_job_delegate.cpp @@ -64,12 +64,16 @@ void URLRequestCustomJobDelegate::setAdditionalResponseHeaders( void URLRequestCustomJobDelegate::reply(const QByteArray &contentType, QIODevice *device) { - if (device) + if (!device) + m_proxy->m_ioTaskRunner->PostTask(FROM_HERE, + base::BindOnce(&URLRequestCustomJobProxy::succeed, m_proxy)); + else { QObject::connect(device, &QIODevice::readyRead, this, &URLRequestCustomJobDelegate::slotReadyRead); - m_proxy->m_ioTaskRunner->PostTask(FROM_HERE, - base::BindOnce(&URLRequestCustomJobProxy::reply, m_proxy, - contentType.toStdString(), device, - std::move(m_additionalResponseHeaders))); + m_proxy->m_ioTaskRunner->PostTask(FROM_HERE, + base::BindOnce(&URLRequestCustomJobProxy::reply, m_proxy, + contentType.toStdString(), device, + std::move(m_additionalResponseHeaders))); + } } void URLRequestCustomJobDelegate::slotReadyRead() diff --git a/src/core/net/url_request_custom_job_proxy.cpp b/src/core/net/url_request_custom_job_proxy.cpp index 0f41a3670..54faddc62 100644 --- a/src/core/net/url_request_custom_job_proxy.cpp +++ b/src/core/net/url_request_custom_job_proxy.cpp @@ -118,6 +118,11 @@ void URLRequestCustomJobProxy::fail(int error) // else we fail on the next read, or the read that might already be in progress } +void URLRequestCustomJobProxy::succeed() +{ + m_client->notifySuccess(); +} + void URLRequestCustomJobProxy::readyRead() { DCHECK (m_ioTaskRunner->RunsTasksInCurrentSequence()); diff --git a/src/core/net/url_request_custom_job_proxy.h b/src/core/net/url_request_custom_job_proxy.h index 65c919ed0..c03992411 100644 --- a/src/core/net/url_request_custom_job_proxy.h +++ b/src/core/net/url_request_custom_job_proxy.h @@ -44,6 +44,7 @@ public: virtual void notifyCanceled() = 0; virtual void notifyAborted() = 0; virtual void notifyStartFailure(int) = 0; + virtual void notifySuccess() = 0; virtual void notifyReadyRead() = 0; virtual base::SequencedTaskRunner *taskRunner() = 0; }; @@ -60,6 +61,7 @@ public: void redirect(GURL url); void abort(); void fail(int error); + void succeed(); void release(); void initialize(GURL url, std::string method, absl::optional<url::Origin> initiatorOrigin, std::map<std::string, std::string> headers, diff --git a/src/core/net/version_ui_qt.cpp b/src/core/net/version_ui_qt.cpp index 61a89596a..a49dea62a 100644 --- a/src/core/net/version_ui_qt.cpp +++ b/src/core/net/version_ui_qt.cpp @@ -9,12 +9,14 @@ #include "chrome/browser/profiles/profile.h" #include "qtwebengine/grit/qt_webengine_resources.h" #include "services/network/public/cpp/content_security_policy/content_security_policy.h" +#include "v8/include/v8-version-string.h" namespace { const char kQtWebEngineVersion[] = "qtwebengine_version"; const char kQtWebEngineChromiumVersion[] = "qtwebengine_chromium_version"; const char kQtWebEngineChromiumSecurityPatchVersion[] = "qtwebengine_chromium_security_patch_version"; +const char kQtWebEngineChromiumV8Version[] = "qtwebengine_chromium_v8_version"; const char kCommandLine[] = "command_line"; const char kQtVersionCSS[] = "qt_version.css"; const char kQtLogo[] = "images/qt.png"; @@ -23,7 +25,6 @@ const char kQtWebEngineLogo[] = "images/qtwebengine.png"; VersionUIQt::VersionUIQt(content::WebUI *web_ui) : content::WebUIController(web_ui) { - Profile *profile = Profile::FromWebUI(web_ui); content::WebUIDataSource *html_source = content::WebUIDataSource::CreateAndAdd(profile, chrome::kChromeUIVersionQtHost); @@ -39,6 +40,7 @@ VersionUIQt::VersionUIQt(content::WebUI *web_ui) : content::WebUIController(web_ html_source->AddString(kQtWebEngineChromiumVersion, qWebEngineChromiumVersion()); html_source->AddString(kQtWebEngineChromiumSecurityPatchVersion, qWebEngineChromiumSecurityPatchVersion()); + html_source->AddString(kQtWebEngineChromiumV8Version, V8_VERSION_STRING); #if BUILDFLAG(IS_WIN) html_source->AddString( kCommandLine, diff --git a/src/core/net/webui_controller_factory_qt.cpp b/src/core/net/webui_controller_factory_qt.cpp index ed35a3e36..2acd05cae 100644 --- a/src/core/net/webui_controller_factory_qt.cpp +++ b/src/core/net/webui_controller_factory_qt.cpp @@ -14,8 +14,8 @@ #include "build/build_config.h" #include "chrome/browser/accessibility/accessibility_ui.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/webui/device_log_ui.h" -#include "chrome/browser/ui/webui/devtools_ui.h" +#include "chrome/browser/ui/webui/device_log/device_log_ui.h" +#include "chrome/browser/ui/webui/devtools/devtools_ui.h" #include "chrome/browser/ui/webui/net_internals/net_internals_ui.h" #include "chrome/browser/ui/webui/user_actions/user_actions_ui.h" #include "chrome/common/url_constants.h" diff --git a/src/core/ozone/gl_share_context_qt.cpp b/src/core/ozone/gl_share_context_qt.cpp index b1c5e201f..f2078b597 100644 --- a/src/core/ozone/gl_share_context_qt.cpp +++ b/src/core/ozone/gl_share_context_qt.cpp @@ -43,6 +43,11 @@ QtShareGLContext::QtShareGLContext(QOpenGLContext *context) #endif // QT_CONFIG(opengl) } +QtShareGLContext::~QtShareGLContext() +{ + OnContextWillDestroy(); +} + unsigned int QtShareGLContext::CheckStickyGraphicsResetStatusImpl() { #if QT_CONFIG(opengl) diff --git a/src/core/ozone/gl_share_context_qt.h b/src/core/ozone/gl_share_context_qt.h index 89be00421..6b0546a72 100644 --- a/src/core/ozone/gl_share_context_qt.h +++ b/src/core/ozone/gl_share_context_qt.h @@ -18,10 +18,11 @@ class QtShareGLContext : public gl::GLContext public: QtShareGLContext(QOpenGLContext *qtContext); + ~QtShareGLContext() override; void *GetHandle() override { return m_handle; } unsigned int CheckStickyGraphicsResetStatusImpl() override; // We don't care about the rest, this context shouldn't be used except for its handle. - bool Initialize(gl::GLSurface *, const gl::GLContextAttribs &) override + bool InitializeImpl(gl::GLSurface *, const gl::GLContextAttribs &) override { Q_UNREACHABLE(); return false; diff --git a/src/core/ozone/gl_surface_qt.cpp b/src/core/ozone/gl_surface_qt.cpp index 0cbe75cbd..cebeb8b67 100644 --- a/src/core/ozone/gl_surface_qt.cpp +++ b/src/core/ozone/gl_surface_qt.cpp @@ -128,15 +128,14 @@ bool usingSoftwareDynamicGL() #endif // QT_CONFIG(opengl) } -scoped_refptr<GLSurface> -CreateOffscreenGLSurfaceWithFormat(GLDisplay *display, const gfx::Size& size, GLSurfaceFormat format) +scoped_refptr<GLSurface> CreateOffscreenGLSurface(GLDisplay *display, const gfx::Size &size) { scoped_refptr<GLSurface> surface; switch (GetGLImplementation()) { case kGLImplementationDesktopGLCoreProfile: case kGLImplementationDesktopGL: { surface = new GLSurfaceWGLQt(size); - if (surface->Initialize(format)) + if (surface->Initialize(GLSurfaceFormat())) return surface; break; } @@ -144,8 +143,8 @@ CreateOffscreenGLSurfaceWithFormat(GLDisplay *display, const gfx::Size& size, GL case kGLImplementationEGLGLES2: { GLDisplayEGL *display_egl = display->GetAs<gl::GLDisplayEGL>(); if (display_egl->IsEGLSurfacelessContextSupported() && size.width() == 0 && size.height() == 0) - return InitializeGLSurfaceWithFormat(new SurfacelessEGL(display_egl, size), format); - return InitializeGLSurfaceWithFormat(new PbufferGLSurfaceEGL(display_egl, size), format); + return InitializeGLSurface(new SurfacelessEGL(display_egl, size)); + return InitializeGLSurface(new PbufferGLSurfaceEGL(display_egl, size)); } default: break; diff --git a/src/core/ozone/ozone_platform_qt.cpp b/src/core/ozone/ozone_platform_qt.cpp index 623cf43cf..6384ea2db 100644 --- a/src/core/ozone/ozone_platform_qt.cpp +++ b/src/core/ozone/ozone_platform_qt.cpp @@ -38,7 +38,7 @@ #include <filesystem> #endif // BUILDFLAG(USE_XKBCOMMON) -#if BUILDFLAG(OZONE_PLATFORM_X11) +#if BUILDFLAG(IS_OZONE_X11) #include "ui/gfx/linux/gpu_memory_buffer_support_x11.h" #include "ui/ozone/platform/x11/gl_egl_utility_x11.h" @@ -113,9 +113,6 @@ const ui::OzonePlatform::PlatformProperties &OzonePlatformQt::GetPlatformPropert if (!initialized) { DCHECK(m_supportsNativePixmaps); properties->fetch_buffer_formats_for_gmb_on_gpu = m_supportsNativePixmaps.value(); -#if BUILDFLAG(USE_VAAPI) - properties->supports_vaapi = m_supportsNativePixmaps.value(); -#endif initialized = true; } @@ -238,7 +235,7 @@ void OzonePlatformQt::InitializeGPU(const ui::OzonePlatform::InitParams ¶ms) { surface_factory_ozone_.reset(new QtWebEngineCore::SurfaceFactoryQt()); -#if BUILDFLAG(OZONE_PLATFORM_X11) +#if BUILDFLAG(IS_OZONE_X11) if (params.enable_native_gpu_memory_buffers) { base::ThreadPool::PostTask(FROM_HERE, base::BindOnce([]() @@ -263,7 +260,7 @@ bool OzonePlatformQt::IsNativePixmapConfigSupported(gfx::BufferFormat format, gf PlatformGLEGLUtility *OzonePlatformQt::GetPlatformGLEGLUtility() { if (!gl_egl_utility_) { -#if BUILDFLAG(OZONE_PLATFORM_X11) +#if BUILDFLAG(IS_OZONE_X11) if (GetQtXDisplay()) gl_egl_utility_ = std::make_unique<GLEGLUtilityX11>(); else diff --git a/src/core/ozone/surface_factory_qt.cpp b/src/core/ozone/surface_factory_qt.cpp index 04e6ec28f..1bfa49c60 100644 --- a/src/core/ozone/surface_factory_qt.cpp +++ b/src/core/ozone/surface_factory_qt.cpp @@ -9,16 +9,16 @@ #include "ozone/gl_ozone_egl_qt.h" #include "media/gpu/buildflags.h" +#include "ui/base/ozone_buildflags.h" #include "ui/gfx/linux/drm_util_linux.h" #include "ui/gfx/linux/gbm_buffer.h" #include "ui/gfx/linux/native_pixmap_dmabuf.h" #include "ui/gl/egl_util.h" -#include "ui/ozone/buildflags.h" #include <QDebug> #include <QtGui/qtgui-config.h> -#if BUILDFLAG(OZONE_PLATFORM_X11) +#if BUILDFLAG(IS_OZONE_X11) #include "ozone/gl_ozone_glx_qt.h" #include "ui/gfx/linux/gpu_memory_buffer_support_x11.h" @@ -32,7 +32,7 @@ namespace QtWebEngineCore { SurfaceFactoryQt::SurfaceFactoryQt() { -#if BUILDFLAG(OZONE_PLATFORM_X11) +#if BUILDFLAG(IS_OZONE_X11) if (GLContextHelper::getGlxPlatformInterface()) { m_impl = { gl::GLImplementationParts(gl::kGLImplementationDesktopGL), gl::GLImplementationParts(gl::kGLImplementationDisabled) }; @@ -73,7 +73,7 @@ SurfaceFactoryQt::CreateVulkanImplementation(bool /*allow_protected_memory*/, bool SurfaceFactoryQt::CanCreateNativePixmapForFormat(gfx::BufferFormat format) { -#if BUILDFLAG(OZONE_PLATFORM_X11) +#if BUILDFLAG(IS_OZONE_X11) if (GLContextHelper::getGlxPlatformInterface()) return ui::GpuMemoryBufferSupportX11::GetInstance()->CanCreateNativePixmapForFormat(format); #endif @@ -101,7 +101,7 @@ scoped_refptr<gfx::NativePixmap> SurfaceFactoryQt::CreateNativePixmap( gfx::NativePixmapHandle handle; -#if BUILDFLAG(OZONE_PLATFORM_X11) +#if BUILDFLAG(IS_OZONE_X11) if (GLContextHelper::getGlxPlatformInterface()) { auto gbmBuffer = ui::GpuMemoryBufferSupportX11::GetInstance()->CreateBuffer(format, size, usage); @@ -165,7 +165,7 @@ SurfaceFactoryQt::CreateNativePixmapFromHandle( #if QT_CONFIG(opengl) gfx::NativePixmapHandle bufferHandle; -#if BUILDFLAG(OZONE_PLATFORM_X11) +#if BUILDFLAG(IS_OZONE_X11) if (GLContextHelper::getGlxPlatformInterface()) { auto gbmBuffer = ui::GpuMemoryBufferSupportX11::GetInstance()->CreateBufferFromHandle( size, format, std::move(handle)); @@ -226,7 +226,7 @@ SurfaceFactoryQt::CreateNativePixmapFromHandle( int fd = fds[i]; int stride = strides[i]; int offset = offsets[i]; - int size = handle.planes[i].size; + int planeSize = handle.planes[i].size; if (fd == -1) { fd = fds[0]; @@ -234,7 +234,7 @@ SurfaceFactoryQt::CreateNativePixmapFromHandle( offset = handle.planes[i].offset; } - gfx::NativePixmapPlane plane(stride, offset, size, base::ScopedFD(::dup(fd))); + gfx::NativePixmapPlane plane(stride, offset, planeSize, base::ScopedFD(::dup(fd))); bufferHandle.planes.push_back(std::move(plane)); } @@ -250,10 +250,10 @@ SurfaceFactoryQt::CreateNativePixmapFromHandle( bool SurfaceFactoryQt::SupportsNativePixmaps() { #if QT_CONFIG(opengl) -#if BUILDFLAG(OZONE_PLATFORM_X11) +#if BUILDFLAG(IS_OZONE_X11) if (GLContextHelper::getGlxPlatformInterface()) return ui::GpuMemoryBufferSupportX11::GetInstance()->has_gbm_device(); -#endif // BUILDFLAG(OZONE_PLATFORM_X11) +#endif // BUILDFLAG(IS_OZONE_X11) if (GLContextHelper::getEglPlatformInterface()) return EGLHelper::instance()->isDmaBufSupported(); diff --git a/src/core/permission_manager_qt.cpp b/src/core/permission_manager_qt.cpp index b6e727ef8..2c1c0d3d6 100644 --- a/src/core/permission_manager_qt.cpp +++ b/src/core/permission_manager_qt.cpp @@ -3,41 +3,55 @@ #include "permission_manager_qt.h" +#include "base/threading/thread_restrictions.h" #include "content/browser/renderer_host/render_view_host_delegate.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/permission_controller.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_view_host.h" #include "third_party/blink/public/common/permissions/permission_utils.h" - +#include "chrome/browser/prefs/chrome_command_line_pref_store.h" +#include "components/prefs/pref_member.h" +#include "components/prefs/in_memory_pref_store.h" +#include "components/prefs/json_pref_store.h" +#include "components/prefs/pref_service.h" +#include "components/prefs/pref_service_factory.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/scoped_user_pref_update.h" +#include "components/proxy_config/pref_proxy_config_tracker_impl.h" +#include "components/prefs/pref_service.h" + +#include <QtWebEngineCore/private/qwebenginepermission_p.h> #include "type_conversion.h" #include "web_contents_delegate_qt.h" #include "web_engine_settings.h" namespace QtWebEngineCore { -static ProfileAdapter::PermissionType toQt(blink::PermissionType type) +static QWebEnginePermission::Feature toQt(blink::PermissionType type) { switch (type) { case blink::PermissionType::GEOLOCATION: - return ProfileAdapter::GeolocationPermission; + return QWebEnginePermission::Geolocation; case blink::PermissionType::AUDIO_CAPTURE: - return ProfileAdapter::AudioCapturePermission; + return QWebEnginePermission::MediaAudioCapture; case blink::PermissionType::VIDEO_CAPTURE: - return ProfileAdapter::VideoCapturePermission; + return QWebEnginePermission::MediaVideoCapture; + case blink::PermissionType::DISPLAY_CAPTURE: + return QWebEnginePermission::DesktopAudioVideoCapture; // We treat these both as read/write since we do not currently have a // ClipboardSanitizedWrite feature. case blink::PermissionType::CLIPBOARD_READ_WRITE: case blink::PermissionType::CLIPBOARD_SANITIZED_WRITE: - return ProfileAdapter::ClipboardReadWrite; + return QWebEnginePermission::ClipboardReadWrite; case blink::PermissionType::NOTIFICATIONS: - return ProfileAdapter::NotificationPermission; + return QWebEnginePermission::Notifications; case blink::PermissionType::LOCAL_FONTS: - return ProfileAdapter::LocalFontsPermission; + return QWebEnginePermission::LocalFontsAccess; case blink::PermissionType::ACCESSIBILITY_EVENTS: case blink::PermissionType::CAMERA_PAN_TILT_ZOOM: case blink::PermissionType::WINDOW_MANAGEMENT: - return ProfileAdapter::UnsupportedPermission; + return QWebEnginePermission::Unsupported; case blink::PermissionType::MIDI_SYSEX: case blink::PermissionType::PROTECTED_MEDIA_IDENTIFIER: case blink::PermissionType::MIDI: @@ -54,41 +68,92 @@ static ProfileAdapter::PermissionType toQt(blink::PermissionType type) case blink::PermissionType::AR: case blink::PermissionType::VR: case blink::PermissionType::STORAGE_ACCESS_GRANT: - case blink::PermissionType::DISPLAY_CAPTURE: case blink::PermissionType::TOP_LEVEL_STORAGE_ACCESS: case blink::PermissionType::NUM: - LOG(INFO) << "Unexpected unsupported permission type: " << static_cast<int>(type); + LOG(INFO) << "Unexpected unsupported Blink permission type: " << static_cast<int>(type); break; } - return ProfileAdapter::UnsupportedPermission; + return QWebEnginePermission::Unsupported; } -static bool canRequestPermissionFor(ProfileAdapter::PermissionType type) +static blink::PermissionType toBlink(QWebEnginePermission::Feature feature) { - switch (type) { - case ProfileAdapter::GeolocationPermission: - case ProfileAdapter::NotificationPermission: - case ProfileAdapter::ClipboardReadWrite: - case ProfileAdapter::LocalFontsPermission: - return true; - default: - break; + switch (feature) { + case QWebEnginePermission::Notifications: + return blink::PermissionType::NOTIFICATIONS; + case QWebEnginePermission::Geolocation: + return blink::PermissionType::GEOLOCATION; + case QWebEnginePermission::MediaAudioCapture: + return blink::PermissionType::AUDIO_CAPTURE; + case QWebEnginePermission::MediaVideoCapture: + return blink::PermissionType::VIDEO_CAPTURE; + case QWebEnginePermission::DesktopVideoCapture: + case QWebEnginePermission::DesktopAudioVideoCapture: + return blink::PermissionType::DISPLAY_CAPTURE; + case QWebEnginePermission::ClipboardReadWrite: + return blink::PermissionType::CLIPBOARD_READ_WRITE; + case QWebEnginePermission::LocalFontsAccess: + return blink::PermissionType::LOCAL_FONTS; + case QWebEnginePermission::MediaAudioVideoCapture: + case QWebEnginePermission::Unsupported: + LOG(INFO) << "Unexpected unsupported WebEngine permission type: " << static_cast<int>(feature); + return blink::PermissionType::NUM; } - return false; + + Q_UNREACHABLE(); } -static blink::mojom::PermissionStatus toBlink(ProfileAdapter::PermissionState reply) +static QWebEnginePermission::State toQt(blink::mojom::PermissionStatus state) { - switch (reply) { - case ProfileAdapter::AskPermission: + switch (state) { + case blink::mojom::PermissionStatus::ASK: + return QWebEnginePermission::Ask; + case blink::mojom::PermissionStatus::GRANTED: + return QWebEnginePermission::Granted; + case blink::mojom::PermissionStatus::DENIED: + return QWebEnginePermission::Denied; + } +} + +static blink::mojom::PermissionStatus toBlink(QWebEnginePermission::State state) +{ + switch (state) { + case QWebEnginePermission::Invalid: + case QWebEnginePermission::Ask: return blink::mojom::PermissionStatus::ASK; - case ProfileAdapter::AllowedPermission: + case QWebEnginePermission::Granted: return blink::mojom::PermissionStatus::GRANTED; - case ProfileAdapter::DeniedPermission: + case QWebEnginePermission::Denied: return blink::mojom::PermissionStatus::DENIED; } } +std::string featureString(QWebEnginePermission::Feature feature) +{ + // This is separate from blink::featureString() for the sake of future-proofing; + // e.g. in case we add extra Features that do not correspond to a PermissionType, and + // we need to store them. + switch (feature) { + case QWebEnginePermission::Notifications: + return "Notifications"; + case QWebEnginePermission::Geolocation: + return "Geolocation"; + case QWebEnginePermission::ClipboardReadWrite: + return "ClipboardReadWrite"; + case QWebEnginePermission::LocalFontsAccess: + return "LocalFontsAccess"; + case QWebEnginePermission::MediaAudioCapture: + return "MediaAudioCapture"; + case QWebEnginePermission::MediaVideoCapture: + return "MediaVideoCapture"; + case QWebEnginePermission::DesktopAudioVideoCapture: + return "DesktopAudioVideoCapture"; + default: + Q_UNREACHABLE(); + return nullptr; + } +} + static blink::mojom::PermissionStatus getStatusFromSettings(blink::PermissionType type, WebEngineSettings *settings) { switch (type) { @@ -103,44 +168,87 @@ static blink::mojom::PermissionStatus getStatusFromSettings(blink::PermissionTyp } } -PermissionManagerQt::PermissionManagerQt() +PermissionManagerQt::PermissionManagerQt(ProfileAdapter *profileAdapter) : m_requestIdCount(0) + , m_persistence(true) + , m_profileAdapter(profileAdapter) { + PrefServiceFactory factory; + factory.set_async(false); + factory.set_command_line_prefs(base::MakeRefCounted<ChromeCommandLinePrefStore>( + base::CommandLine::ForCurrentProcess())); + + QString userPrefStorePath = profileAdapter->dataPath(); + auto prefRegistry = base::MakeRefCounted<PrefRegistrySimple>(); + + auto policy = profileAdapter->persistentPermissionsPolicy(); + if (!profileAdapter->isOffTheRecord() && policy == ProfileAdapter::PersistentPermissionsOnDisk && + !userPrefStorePath.isEmpty() && profileAdapter->ensureDataPathExists()) { + userPrefStorePath += QDir::separator(); + userPrefStorePath += QStringLiteral("permissions.json"); + factory.set_user_prefs(base::MakeRefCounted<JsonPrefStore>(toFilePath(userPrefStorePath))); + } else { + factory.set_user_prefs(new InMemoryPrefStore); + } + + m_featureTypes.push_back(QWebEnginePermission::Notifications); + m_featureTypes.push_back(QWebEnginePermission::Geolocation); + m_featureTypes.push_back(QWebEnginePermission::ClipboardReadWrite); + m_featureTypes.push_back(QWebEnginePermission::LocalFontsAccess); + + // Transient, but the implementation relies on them being written to storage + m_featureTypes.push_back(QWebEnginePermission::MediaAudioCapture); + m_featureTypes.push_back(QWebEnginePermission::MediaVideoCapture); + + // Register all preference types as keys prior to doing anything else + for (auto &type : m_featureTypes) { + prefRegistry->RegisterDictionaryPref(featureString(type)); + } + PrefProxyConfigTrackerImpl::RegisterPrefs(prefRegistry.get()); + + if (policy == ProfileAdapter::NoPersistentPermissions) + m_persistence = false; + + { + base::ScopedAllowBlocking allowBlock; + m_prefService = factory.Create(prefRegistry); + } } PermissionManagerQt::~PermissionManagerQt() { + commit(); } -void PermissionManagerQt::permissionRequestReply(const QUrl &url, ProfileAdapter::PermissionType type, ProfileAdapter::PermissionState reply) +void PermissionManagerQt::setPermission(const QUrl &url, QWebEnginePermission::Feature feature, QWebEnginePermission::State state) { // Normalize the QUrl to Chromium origin form. const GURL gorigin = toGurl(url).DeprecatedGetOriginAsURL(); const QUrl origin = gorigin.is_empty() ? url : toQt(gorigin); if (origin.isEmpty()) return; - QPair<QUrl, ProfileAdapter::PermissionType> key(origin, type); - if (reply == ProfileAdapter::AskPermission) - m_permissions.remove(key); + if (state == QWebEnginePermission::Ask) + ResetPermission(toBlink(feature), gorigin, gorigin); else - m_permissions[key] = (reply == ProfileAdapter::AllowedPermission); - blink::mojom::PermissionStatus status = toBlink(reply); - if (reply != ProfileAdapter::AskPermission) { + setPermission(toBlink(feature), gorigin, state == QWebEnginePermission::Granted); + blink::mojom::PermissionStatus status = toBlink(state); + if (state != QWebEnginePermission::Ask) { auto it = m_requests.begin(); while (it != m_requests.end()) { - if (it->origin == origin && it->type == type) { + if (it->origin == origin && it->type == feature) { std::move(it->callback).Run(status); it = m_requests.erase(it); } else ++it; } } + for (const auto &it: m_subscribers) { - if (it.second.origin == origin && it.second.type == type) + if (it.second.origin == origin && it.second.type == feature) it.second.callback.Run(status); } - if (reply == ProfileAdapter::AskPermission) + if (state == QWebEnginePermission::Ask) return; auto it = m_multiRequests.begin(); @@ -150,21 +258,23 @@ void PermissionManagerQt::permissionRequestReply(const QUrl &url, ProfileAdapter std::vector<blink::mojom::PermissionStatus> result; result.reserve(it->types.size()); for (blink::PermissionType permission : it->types) { - const ProfileAdapter::PermissionType permissionType = toQt(permission); - if (permissionType == ProfileAdapter::UnsupportedPermission) { + if (toQt(permission) == QWebEnginePermission::Unsupported) { result.push_back(blink::mojom::PermissionStatus::DENIED); continue; } - QPair<QUrl, ProfileAdapter::PermissionType> key(origin, permissionType); - if (!m_permissions.contains(key)) { - answerable = false; - break; + blink::mojom::PermissionStatus permissionStatus = GetPermissionStatus(permission, gorigin, GURL()); + if (permissionStatus == toBlink(state)) { + if (permissionStatus == blink::mojom::PermissionStatus::ASK) { + answerable = false; + break; + } + + result.push_back(permissionStatus); + } else { + // Reached when the PersistentPermissionsPolicy is set to NoPersistentPermissions + result.push_back(toBlink(state)); } - if (m_permissions[key]) - result.push_back(blink::mojom::PermissionStatus::GRANTED); - else - result.push_back(blink::mojom::PermissionStatus::DENIED); } if (answerable) { std::move(it->callback).Run(result); @@ -176,10 +286,57 @@ void PermissionManagerQt::permissionRequestReply(const QUrl &url, ProfileAdapter } } -bool PermissionManagerQt::checkPermission(const QUrl &origin, ProfileAdapter::PermissionType type) +QWebEnginePermission::State PermissionManagerQt::getPermissionState(const QUrl &origin, QWebEnginePermission::Feature feature) { - QPair<QUrl, ProfileAdapter::PermissionType> key(origin, type); - return m_permissions.contains(key) && m_permissions[key]; + return toQt(GetPermissionStatus(toBlink(feature), toGurl(origin), GURL())); +} + +QList<QWebEnginePermission> PermissionManagerQt::listPermissions(const QUrl &origin, QWebEnginePermission::Feature feature) +{ + Q_ASSERT(origin.isEmpty() || feature == QWebEnginePermission::Unsupported); + QList<QWebEnginePermission> returnList; + GURL gorigin = toGurl(origin).DeprecatedGetOriginAsURL(); + std::string originSpec = gorigin.spec(); + + if (!origin.isEmpty() && !gorigin.is_valid()) + return returnList; + + std::vector<QWebEnginePermission::Feature> types; + if (feature == QWebEnginePermission::Unsupported) + types = m_featureTypes; + else + types.push_back(feature); + + for (auto &type : types) { + // Transient types may end up in the permission store as an implementation detail, + // but we do not want to expose them to callers. + if (QWebEnginePermission::isTransient(type)) + continue; + + auto *pref = m_prefService->FindPreference(featureString(type)); + if (!pref) + continue; + + auto *prefDict = pref->GetValue()->GetIfDict(); + Q_ASSERT(prefDict); + + for (const auto &entry : *prefDict) { + if (!originSpec.empty() && entry.first != originSpec) + continue; + + auto *pvt = new QWebEnginePermissionPrivate(toQt(GURL(std::string_view(entry.first))), type, nullptr, m_profileAdapter.get()); + returnList.push_back(QWebEnginePermission(pvt)); + } + } + + return returnList; +} + +void PermissionManagerQt::commit() +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + // Make sure modified permissions are written to disk + m_prefService->CommitPendingWrite(); } void PermissionManagerQt::RequestPermissions(content::RenderFrameHost *frameHost, @@ -199,19 +356,28 @@ void PermissionManagerQt::RequestPermissions(content::RenderFrameHost *frameHost std::vector<content::PermissionStatus> result; result.reserve(requestDescription.permissions.size()); for (blink::PermissionType permission : requestDescription.permissions) { - const ProfileAdapter::PermissionType permissionType = toQt(permission); - if (permissionType == ProfileAdapter::UnsupportedPermission) { + const QWebEnginePermission::Feature feature = toQt(permission); + if (feature == QWebEnginePermission::Unsupported) { result.push_back(blink::mojom::PermissionStatus::DENIED); continue; } - auto status = getStatusFromSettings(permission, contentsDelegate->webEngineSettings()); - if (status == blink::mojom::PermissionStatus::ASK) { - answerable = false; - break; - } else - result.push_back(status); + blink::mojom::PermissionStatus permissionStatus = getStatusFromSettings(permission, contentsDelegate->webEngineSettings()); + if (permissionStatus == blink::mojom::PermissionStatus::ASK) { + permissionStatus = GetPermissionStatus(permission, requestDescription.requesting_origin, GURL()); + if (m_persistence && permissionStatus != blink::mojom::PermissionStatus::ASK) { + // Automatically grant/deny without prompt if already asked once + result.push_back(permissionStatus); + } else { + answerable = false; + break; + } + } else { + // Reached when clipboard settings have been set + result.push_back(permissionStatus); + } } + if (answerable) { std::move(callback).Run(result); return; @@ -221,9 +387,9 @@ void PermissionManagerQt::RequestPermissions(content::RenderFrameHost *frameHost auto requestOrigin = toQt(requestDescription.requesting_origin); m_multiRequests.push_back({ request_id, requestDescription.permissions, requestOrigin, std::move(callback) }); for (blink::PermissionType permission : requestDescription.permissions) { - const ProfileAdapter::PermissionType permissionType = toQt(permission); - if (canRequestPermissionFor(permissionType)) - contentsDelegate->requestFeaturePermission(permissionType, requestOrigin); + const QWebEnginePermission::Feature feature = toQt(permission); + if (!QWebEnginePermission::isTransient(feature)) + contentsDelegate->requestFeaturePermission(feature, requestOrigin); } } @@ -231,7 +397,6 @@ void PermissionManagerQt::RequestPermissionsFromCurrentDocument(content::RenderF const content::PermissionRequestDescription &requestDescription, base::OnceCallback<void(const std::vector<blink::mojom::PermissionStatus>&)> callback) { - RequestPermissions(frameHost, requestDescription, std::move(callback)); } @@ -240,14 +405,30 @@ blink::mojom::PermissionStatus PermissionManagerQt::GetPermissionStatus( const GURL& requesting_origin, const GURL& /*embedding_origin*/) { - const ProfileAdapter::PermissionType permissionType = toQt(permission); - if (permissionType == ProfileAdapter::UnsupportedPermission) + const QWebEnginePermission::Feature feature = toQt(permission); + if (feature == QWebEnginePermission::Unsupported) return blink::mojom::PermissionStatus::DENIED; - QPair<QUrl, ProfileAdapter::PermissionType> key(toQt(requesting_origin), permissionType); - if (!m_permissions.contains(key)) + permission = toBlink(toQt(permission)); // Filter out merged/unsupported permissions (e.g. clipboard) + auto *pref = m_prefService->FindPreference(featureString(toQt(permission))); + if (!pref) + return blink::mojom::PermissionStatus::ASK; // Permission type not in database + + const auto *permissions = pref->GetValue()->GetIfDict(); + Q_ASSERT(permissions); + + auto requestedPermission = permissions->FindBool(requesting_origin.DeprecatedGetOriginAsURL().spec()); + if (!requestedPermission) + return blink::mojom::PermissionStatus::ASK; // Origin is not in the current permission type's database + + // Workaround: local fonts are entirely managed by Chromium, which only calls RequestPermission() _after_ + // it's checked whether the permission has been granted. By always returning ASK, we force the request to + // come through every time. + if (permission == blink::PermissionType::LOCAL_FONTS + && m_profileAdapter->persistentPermissionsPolicy() == ProfileAdapter::NoPersistentPermissions) return blink::mojom::PermissionStatus::ASK; - if (m_permissions[key]) + + if (requestedPermission.value()) return blink::mojom::PermissionStatus::GRANTED; return blink::mojom::PermissionStatus::DENIED; } @@ -305,20 +486,19 @@ void PermissionManagerQt::ResetPermission( const GURL& requesting_origin, const GURL& /*embedding_origin*/) { - const ProfileAdapter::PermissionType permissionType = toQt(permission); - if (permissionType == ProfileAdapter::UnsupportedPermission) + const QWebEnginePermission::Feature feature = toQt(permission); + if (feature == QWebEnginePermission::Unsupported) return; - QPair<QUrl, ProfileAdapter::PermissionType> key(toQt(requesting_origin), permissionType); - m_permissions.remove(key); + ScopedDictPrefUpdate updater(m_prefService.get(), featureString(feature)); + updater.Get().Remove(requesting_origin.spec()); } -content::PermissionControllerDelegate::SubscriptionId PermissionManagerQt::SubscribePermissionStatusChange( - blink::PermissionType permission, - content::RenderProcessHost * /*render_process_host*/, - content::RenderFrameHost * /* render_frame_host */, - const GURL& requesting_origin, - base::RepeatingCallback<void(blink::mojom::PermissionStatus)> callback) +content::PermissionControllerDelegate::SubscriptionId +PermissionManagerQt::SubscribeToPermissionStatusChange( + blink::PermissionType permission, content::RenderProcessHost * /*render_process_host*/, + content::RenderFrameHost * /* render_frame_host */, const GURL &requesting_origin, + base::RepeatingCallback<void(blink::mojom::PermissionStatus)> callback) { auto subscriber_id = subscription_id_generator_.GenerateNextId(); m_subscribers.insert( { subscriber_id, @@ -326,10 +506,27 @@ content::PermissionControllerDelegate::SubscriptionId PermissionManagerQt::Subsc return subscriber_id; } -void PermissionManagerQt::UnsubscribePermissionStatusChange(content::PermissionControllerDelegate::SubscriptionId subscription_id) +void PermissionManagerQt::UnsubscribeFromPermissionStatusChange( + content::PermissionControllerDelegate::SubscriptionId subscription_id) { if (!m_subscribers.erase(subscription_id)) LOG(WARNING) << "PermissionManagerQt::UnsubscribePermissionStatusChange called on unknown subscription id" << subscription_id; } +void PermissionManagerQt::setPermission( + blink::PermissionType permission, + const GURL& requesting_origin, + bool granted) +{ + const QWebEnginePermission::Feature feature = toQt(permission); + if (feature == QWebEnginePermission::Unsupported) + return; + + if (!m_prefService->FindPreference(featureString(feature))) + return; + + ScopedDictPrefUpdate updater(m_prefService.get(), featureString(feature)); + updater.Get().Set(requesting_origin.spec(), granted); +} + } // namespace QtWebEngineCore diff --git a/src/core/permission_manager_qt.h b/src/core/permission_manager_qt.h index b91498d3d..6a4df2efa 100644 --- a/src/core/permission_manager_qt.h +++ b/src/core/permission_manager_qt.h @@ -7,20 +7,26 @@ #include "base/functional/callback.h" #include "content/public/browser/permission_controller_delegate.h" +#include <QtWebEngineCore/qwebenginepermission.h> #include "profile_adapter.h" #include <map> +class PrefService; + namespace QtWebEngineCore { class PermissionManagerQt : public content::PermissionControllerDelegate { public: - PermissionManagerQt(); + PermissionManagerQt(ProfileAdapter *adapter); ~PermissionManagerQt(); - void permissionRequestReply(const QUrl &origin, ProfileAdapter::PermissionType type, ProfileAdapter::PermissionState reply); - bool checkPermission(const QUrl &origin, ProfileAdapter::PermissionType type); + void setPermission(const QUrl &origin, QWebEnginePermission::Feature feature, QWebEnginePermission::State state); + QWebEnginePermission::State getPermissionState(const QUrl &origin, QWebEnginePermission::Feature feature); + QList<QWebEnginePermission> listPermissions(const QUrl &origin, QWebEnginePermission::Feature feature); + + void commit(); // content::PermissionManager implementation: blink::mojom::PermissionStatus GetPermissionStatus( @@ -51,20 +57,18 @@ public: const content::PermissionRequestDescription &request_description, base::OnceCallback<void(const std::vector<blink::mojom::PermissionStatus> &)> callback) override; - content::PermissionControllerDelegate::SubscriptionId SubscribePermissionStatusChange( - blink::PermissionType permission, - content::RenderProcessHost* render_process_host, - content::RenderFrameHost* render_frame_host, - const GURL& requesting_origin, - const base::RepeatingCallback<void(blink::mojom::PermissionStatus)> callback) override; + content::PermissionControllerDelegate::SubscriptionId SubscribeToPermissionStatusChange( + blink::PermissionType permission, content::RenderProcessHost *render_process_host, + content::RenderFrameHost *render_frame_host, const GURL &requesting_origin, + const base::RepeatingCallback<void(blink::mojom::PermissionStatus)> callback) override; - void UnsubscribePermissionStatusChange(content::PermissionControllerDelegate::SubscriptionId subscription_id) override; + void UnsubscribeFromPermissionStatusChange( + content::PermissionControllerDelegate::SubscriptionId subscription_id) override; private: - QHash<QPair<QUrl, ProfileAdapter::PermissionType>, bool> m_permissions; struct Request { int id; - ProfileAdapter::PermissionType type; + QWebEnginePermission::Feature type; QUrl origin; base::OnceCallback<void(blink::mojom::PermissionStatus)> callback; }; @@ -75,16 +79,24 @@ private: base::OnceCallback<void(const std::vector<blink::mojom::PermissionStatus>&)> callback; }; struct Subscription { - ProfileAdapter::PermissionType type; + QWebEnginePermission::Feature type; QUrl origin; base::RepeatingCallback<void(blink::mojom::PermissionStatus)> callback; }; + + void setPermission(blink::PermissionType permission, + const GURL& requesting_origin, + bool granted); + std::vector<Request> m_requests; std::vector<MultiRequest> m_multiRequests; + std::vector<QWebEnginePermission::Feature> m_featureTypes; std::map<content::PermissionControllerDelegate::SubscriptionId, Subscription> m_subscribers; content::PermissionControllerDelegate::SubscriptionId::Generator subscription_id_generator_; int m_requestIdCount; - + std::unique_ptr<PrefService> m_prefService; + QPointer<QtWebEngineCore::ProfileAdapter> m_profileAdapter; + bool m_persistence; }; } // namespace QtWebEngineCore diff --git a/src/core/platform_notification_service_qt.cpp b/src/core/platform_notification_service_qt.cpp index 182a5ad84..2c0a39a67 100644 --- a/src/core/platform_notification_service_qt.cpp +++ b/src/core/platform_notification_service_qt.cpp @@ -8,6 +8,8 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_event_dispatcher.h" #include "ui/message_center/public/cpp/notification_delegate.h" +#include "url/gurl.h" +#include "url/origin.h" #include "profile_adapter.h" #include "profile_adapter_client.h" @@ -153,6 +155,24 @@ void PlatformNotificationServiceQt::GetDisplayedNotifications(DisplayedNotificat std::move(callback).Run(std::move(movableStdStringSet), true /* supports_synchronization */); } +void PlatformNotificationServiceQt::GetDisplayedNotificationsForOrigin(const GURL &url, DisplayedNotificationsCallback callback) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + ProfileQt *profile = static_cast<ProfileQt *>(browser_context); + + const url::Origin origin = url::Origin::Create(url); + std::set<std::string> movableStdStringSet; + auto it = profile->profileAdapter()->persistentNotifications().constBegin(); + const auto end = profile->profileAdapter()->persistentNotifications().constEnd(); + while (it != end) { + if (it.value()->isShown() && origin.IsSameOriginWith(toGurl(it.value()->origin()))) + movableStdStringSet.insert(it.key().toStdString()); + ++it; + } + + std::move(callback).Run(std::move(movableStdStringSet), true /* supports_synchronization */); +} + int64_t PlatformNotificationServiceQt::ReadNextPersistentNotificationId() { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); diff --git a/src/core/platform_notification_service_qt.h b/src/core/platform_notification_service_qt.h index bf8fcca04..1435f79e9 100644 --- a/src/core/platform_notification_service_qt.h +++ b/src/core/platform_notification_service_qt.h @@ -56,6 +56,8 @@ public: // Records a given notification to UKM. void RecordNotificationUkmEvent(const content::NotificationDatabaseData&) override { } + void GetDisplayedNotificationsForOrigin(const GURL&, DisplayedNotificationsCallback callback) override; + content::BrowserContext *browser_context; }; diff --git a/src/core/pref_service_adapter.cpp b/src/core/pref_service_adapter.cpp index 544a84de1..d561cab4f 100644 --- a/src/core/pref_service_adapter.cpp +++ b/src/core/pref_service_adapter.cpp @@ -19,9 +19,12 @@ #include "components/prefs/pref_service_factory.h" #include "components/prefs/pref_registry_simple.h" #include "components/signin/internal/identity_manager/account_tracker_service.h" -#include "components/signin/public/base/signin_pref_names.h" +#include "components/signin/internal/identity_manager/gaia_cookie_manager_service.h" +#include "components/signin/internal/identity_manager/primary_account_manager.h" +#include "components/signin/internal/identity_manager/profile_oauth2_token_service.h" #include "components/user_prefs/user_prefs.h" #include "components/proxy_config/pref_proxy_config_tracker_impl.h" +#include "chrome/browser/gcm/gcm_product_util.h" #include "chrome/common/pref_names.h" #include "extensions/buildflags/buildflags.h" #include "content/public/browser/browser_context.h" @@ -84,17 +87,20 @@ void PrefServiceAdapter::setup(const ProfileAdapter &profileAdapter) #endif // QT_CONFIG(webengine_spellchecker) registry->RegisterBooleanPref(prefs::kShowInternalAccessibilityTree, false); registry->RegisterBooleanPref(prefs::kAccessibilityImageLabelsEnabled, false); + + // chrome/browser/notifications registry->RegisterIntegerPref(prefs::kNotificationNextPersistentId, 10000); + // chrome/browser/push_messaging registry->RegisterDictionaryPref(prefs::kPushMessagingAppIdentifierMap); - registry->RegisterListPref(prefs::kAccountInfo); - registry->RegisterStringPref(prefs::kGoogleServicesLastUsername, - std::string()); - registry->RegisterStringPref(prefs::kGoogleServicesAccountId, std::string()); - registry->RegisterBooleanPref(prefs::kGoogleServicesConsentedToSync, false); - registry->RegisterBooleanPref(prefs::kAutologinEnabled, true); - registry->RegisterListPref(prefs::kReverseAutologinRejectedEmailList); - registry->RegisterBooleanPref(prefs::kSigninAllowed, true); - registry->RegisterBooleanPref(prefs::kSignedInWithCredentialProvider, false); + // chrome/browser/gcm + gcm::RegisterPrefs(registry.get()); + + // signin + PrimaryAccountManager::RegisterProfilePrefs(registry.get()); + ProfileOAuth2TokenService::RegisterProfilePrefs(registry.get()); + GaiaCookieManagerService::RegisterPrefs(registry.get()); + AccountTrackerService::RegisterPrefs(registry.get()); + #if defined(Q_OS_WIN) OSCrypt::RegisterLocalPrefs(registry.get()); #endif @@ -134,10 +140,6 @@ void PrefServiceAdapter::setup(const ProfileAdapter &profileAdapter) registry->RegisterDictionaryPref(prefs::kDevToolsSyncedPreferencesSyncDisabled); registry->RegisterDictionaryPref(prefs::kDevToolsSyncedPreferencesSyncEnabled); - registry->RegisterStringPref(prefs::kGoogleServicesSigninScopedDeviceId, std::string()); - registry->RegisterStringPref(prefs::kGaiaCookieLastListAccountsData, std::string()); - registry->RegisterStringPref(prefs::kGCMProductCategoryForSubtypes, std::string()); - { base::ScopedAllowBlocking allowBlock; m_prefService = factory.Create(registry); diff --git a/src/core/printing/print_view_manager_base_qt.cpp b/src/core/printing/print_view_manager_base_qt.cpp index b2b8e34fc..a691bc2b6 100644 --- a/src/core/printing/print_view_manager_base_qt.cpp +++ b/src/core/printing/print_view_manager_base_qt.cpp @@ -17,7 +17,6 @@ #include "base/task/thread_pool.h" #include "base/timer/timer.h" #include "base/values.h" -#include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/printing/print_job.h" #include "chrome/browser/printing/print_job_manager.h" #include "chrome/browser/printing/printer_query.h" diff --git a/src/core/printing/print_view_manager_qt.cpp b/src/core/printing/print_view_manager_qt.cpp index 1d21c2fb9..42bade52b 100644 --- a/src/core/printing/print_view_manager_qt.cpp +++ b/src/core/printing/print_view_manager_qt.cpp @@ -11,6 +11,7 @@ #include "pdf_util_qt.h" #include "type_conversion.h" #include "web_contents_adapter_client.h" +#include "web_contents_adapter.h" #include "web_contents_view_qt.h" #include "web_engine_context.h" @@ -173,8 +174,8 @@ PrintViewManagerQt::~PrintViewManagerQt() void PrintViewManagerQt::PrintToPDFFileWithCallback(const QPageLayout &pageLayout, const QPageRanges &pageRanges, - bool printInColor, - const QString &filePath, + bool printInColor, const QString &filePath, + quint64 frameId, PrintToPDFFileCallback callback) { if (callback.is_null()) @@ -188,7 +189,8 @@ void PrintViewManagerQt::PrintToPDFFileWithCallback(const QPageLayout &pageLayou m_pdfOutputPath = toFilePath(filePath); m_pdfSaveCallback = std::move(callback); - if (!PrintToPDFInternal(pageLayout, pageRanges, printInColor)) { + if (!PrintToPDFInternal(pageLayout, pageRanges, printInColor, /*useCustomMargins*/ true, + frameId)) { content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE, base::BindOnce(std::move(m_pdfSaveCallback), false)); resetPdfState(); @@ -196,9 +198,8 @@ void PrintViewManagerQt::PrintToPDFFileWithCallback(const QPageLayout &pageLayou } void PrintViewManagerQt::PrintToPDFWithCallback(const QPageLayout &pageLayout, - const QPageRanges &pageRanges, - bool printInColor, - bool useCustomMargins, + const QPageRanges &pageRanges, bool printInColor, + bool useCustomMargins, quint64 frameId, PrintToPDFCallback callback) { if (callback.is_null()) @@ -212,7 +213,7 @@ void PrintViewManagerQt::PrintToPDFWithCallback(const QPageLayout &pageLayout, } m_pdfPrintCallback = std::move(callback); - if (!PrintToPDFInternal(pageLayout, pageRanges, printInColor, useCustomMargins)) { + if (!PrintToPDFInternal(pageLayout, pageRanges, printInColor, useCustomMargins, frameId)) { content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE, base::BindOnce(std::move(m_pdfPrintCallback), QSharedPointer<QByteArray>())); @@ -221,9 +222,8 @@ void PrintViewManagerQt::PrintToPDFWithCallback(const QPageLayout &pageLayout, } bool PrintViewManagerQt::PrintToPDFInternal(const QPageLayout &pageLayout, - const QPageRanges &pageRanges, - const bool printInColor, - const bool useCustomMargins) + const QPageRanges &pageRanges, const bool printInColor, + const bool useCustomMargins, quint64 frameId) { if (!pageLayout.isValid()) return false; @@ -239,11 +239,22 @@ bool PrintViewManagerQt::PrintToPDFInternal(const QPageLayout &pageLayout, if (web_contents()->IsCrashed()) return false; - content::RenderFrameHost *rfh = web_contents()->GetPrimaryMainFrame(); - // Use the plugin frame for printing if web_contents() is a PDF viewer guest - content::RenderFrameHost *full_page_plugin = GetFullPagePlugin(web_contents()); - if (content::RenderFrameHost *pdf_rfh = FindPdfChildFrame(full_page_plugin ? full_page_plugin : rfh)) - rfh = pdf_rfh; + content::RenderFrameHost *rfh = nullptr; + if (frameId == WebContentsAdapter::kInvalidFrameId) { + return false; + } else if (frameId == WebContentsAdapter::kUseMainFrameId) { + rfh = web_contents()->GetPrimaryMainFrame(); + // Use the plugin frame for printing if web_contents() is a PDF viewer guest + content::RenderFrameHost *full_page_plugin = GetFullPagePlugin(web_contents()); + if (content::RenderFrameHost *pdf_rfh = + FindPdfChildFrame(full_page_plugin ? full_page_plugin : rfh)) + rfh = pdf_rfh; + } else { + auto *ftn = content::FrameTreeNode::GloballyFindByID(static_cast<int>(frameId)); + if (!ftn) + return false; + rfh = ftn->current_frame_host(); + } GetPrintRenderFrame(rfh)->InitiatePrintPreview(false); DCHECK(!m_printPreviewRfh); @@ -333,7 +344,10 @@ void PrintViewManagerQt::SetupScriptedPrintPreview(SetupScriptedPrintPreviewCall if (rfh) GetPrintRenderFrame(rfh)->OnPrintPreviewDialogClosed(); - client->printRequested(); + if (web_contents()->GetPrimaryMainFrame() == rfh) + client->printRequested(); + else + client->printRequestedByFrame(static_cast<quint64>(rfh->GetFrameTreeNodeId())); } void PrintViewManagerQt::ShowScriptedPrintPreview(bool /*source_is_modifiable*/) diff --git a/src/core/printing/print_view_manager_qt.h b/src/core/printing/print_view_manager_qt.h index 956849ef9..879a89ef0 100644 --- a/src/core/printing/print_view_manager_qt.h +++ b/src/core/printing/print_view_manager_qt.h @@ -41,21 +41,18 @@ public: typedef base::OnceCallback<void(bool success)> PrintToPDFFileCallback; // Method to print a page to a Pdf document with page size \a pageSize in location \a filePath. - void PrintToPDFFileWithCallback(const QPageLayout &pageLayout, - const QPageRanges &pageRanges, - bool printInColor, - const QString &filePath, + void PrintToPDFFileWithCallback(const QPageLayout &pageLayout, const QPageRanges &pageRanges, + bool printInColor, const QString &filePath, quint64 frameId, PrintToPDFFileCallback callback); - void PrintToPDFWithCallback(const QPageLayout &pageLayout, - const QPageRanges &pageRanges, - bool printInColor, - bool useCustomMargins, + void PrintToPDFWithCallback(const QPageLayout &pageLayout, const QPageRanges &pageRanges, + bool printInColor, bool useCustomMargins, quint64 frameId, PrintToPDFCallback callback); protected: explicit PrintViewManagerQt(content::WebContents*); - bool PrintToPDFInternal(const QPageLayout &, const QPageRanges &, bool printInColor, bool useCustomMargins = true); + bool PrintToPDFInternal(const QPageLayout &, const QPageRanges &, bool printInColor, + bool useCustomMargins, quint64 frameId); // content::WebContentsObserver implementation. // Cancels the print job. diff --git a/src/core/profile_adapter.cpp b/src/core/profile_adapter.cpp index b26f9b1de..1f0062953 100644 --- a/src/core/profile_adapter.cpp +++ b/src/core/profile_adapter.cpp @@ -6,7 +6,6 @@ #include "base/files/file_util.h" #include "base/task/cancelable_task_tracker.h" #include "base/threading/thread_restrictions.h" -#include "base/time/time_to_iso8601.h" #include "components/embedder_support/user_agent_utils.h" #include "components/favicon/core/favicon_service.h" #include "components/history/content/browser/history_database_helper.h" @@ -64,6 +63,7 @@ ProfileAdapter::ProfileAdapter(const QString &storageName): , m_downloadPath(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation)) , m_httpCacheType(DiskHttpCache) , m_persistentCookiesPolicy(AllowPersistentCookies) + , m_persistentPermissionsPolicy(PersistentPermissionsOnDisk) , m_visitedLinksPolicy(TrackVisitedLinksOnDisk) , m_clientHintsEnabled(true) , m_pushServiceEnabled(false) @@ -72,6 +72,8 @@ ProfileAdapter::ProfileAdapter(const QString &storageName): WebEngineContext::current()->addProfileAdapter(this); // creation of profile requires webengine context m_profile.reset(new ProfileQt(this)); + // initialize permissions store + profile()->GetPermissionControllerDelegate(); // fixme: this should not be here m_profile->m_profileIOData->initializeOnUIThread(); m_customUrlSchemeHandlers.insert(QByteArrayLiteral("qrc"), &m_qrcHandler); @@ -109,6 +111,7 @@ void ProfileAdapter::setStorageName(const QString &storageName) m_name = storageName; if (!m_offTheRecord) { m_profile->setupPrefService(); + m_profile->setupPermissionsManager(); if (!m_profile->m_profileIOData->isClearHttpCacheInProgress()) m_profile->m_profileIOData->resetNetworkContext(); if (m_visitedLinksManager) @@ -124,6 +127,7 @@ void ProfileAdapter::setOffTheRecord(bool offTheRecord) return; m_offTheRecord = offTheRecord; m_profile->setupPrefService(); + m_profile->setupPermissionsManager(); if (!m_profile->m_profileIOData->isClearHttpCacheInProgress()) m_profile->m_profileIOData->resetNetworkContext(); if (m_visitedLinksManager) @@ -329,9 +333,9 @@ void ProfileAdapter::setHttpUserAgent(const QString &userAgent) } m_profile->ForEachLoadedStoragePartition( - base::BindRepeating([](const std::string &user_agent, content::StoragePartition *storage_partition) { - storage_partition->GetNetworkContext()->SetUserAgent(user_agent); - }, stdUserAgent)); + [stdUserAgent](content::StoragePartition *storage_partition) { + storage_partition->GetNetworkContext()->SetUserAgent(stdUserAgent); + }); } ProfileAdapter::HttpCacheType ProfileAdapter::httpCacheType() const @@ -371,6 +375,24 @@ void ProfileAdapter::setPersistentCookiesPolicy(ProfileAdapter::PersistentCookie m_profile->m_profileIOData->resetNetworkContext(); } +ProfileAdapter::PersistentPermissionsPolicy ProfileAdapter::persistentPermissionsPolicy() const +{ + if (m_persistentPermissionsPolicy == NoPersistentPermissions) + return NoPersistentPermissions; + if (isOffTheRecord() || m_name.isEmpty()) + return PersistentPermissionsInMemory; + return m_persistentPermissionsPolicy; +} + +void ProfileAdapter::setPersistentPermissionsPolicy(ProfileAdapter::PersistentPermissionsPolicy newPersistentPermissionsPolicy) +{ + ProfileAdapter::PersistentPermissionsPolicy oldPolicy = persistentPermissionsPolicy(); + m_persistentPermissionsPolicy = newPersistentPermissionsPolicy; + if (oldPolicy == persistentPermissionsPolicy()) + return; + m_profile->setupPermissionsManager(); +} + ProfileAdapter::VisitedLinksPolicy ProfileAdapter::visitedLinksPolicy() const { if (isOffTheRecord() || m_visitedLinksPolicy == DoNotTrackVisitedLinks) @@ -468,10 +490,9 @@ const QList<QByteArray> ProfileAdapter::customUrlSchemes() const void ProfileAdapter::updateCustomUrlSchemeHandlers() { - m_profile->ForEachLoadedStoragePartition( - base::BindRepeating([](content::StoragePartition *storage_partition) { - storage_partition->ResetURLLoaderFactories(); - })); + m_profile->ForEachLoadedStoragePartition([](content::StoragePartition *storage_partition) { + storage_partition->ResetURLLoaderFactories(); + }); } void ProfileAdapter::removeUrlSchemeHandler(QWebEngineUrlSchemeHandler *handler) @@ -546,14 +567,25 @@ UserResourceControllerHost *ProfileAdapter::userResourceController() return m_userResourceController.data(); } -void ProfileAdapter::permissionRequestReply(const QUrl &origin, PermissionType type, PermissionState reply) +void ProfileAdapter::setPermission(const QUrl &origin, QWebEnginePermission::Feature feature, QWebEnginePermission::State state) +{ + static_cast<PermissionManagerQt*>(profile()->GetPermissionControllerDelegate())->setPermission(origin, feature, state); +} + +QWebEnginePermission::State ProfileAdapter::getPermissionState(const QUrl &origin, QWebEnginePermission::Feature feature) { - static_cast<PermissionManagerQt*>(profile()->GetPermissionControllerDelegate())->permissionRequestReply(origin, type, reply); + if (persistentPermissionsPolicy() == ProfileAdapter::NoPersistentPermissions) + return QWebEnginePermission::Ask; + + return static_cast<PermissionManagerQt*>(profile()->GetPermissionControllerDelegate())->getPermissionState(origin, feature); } -bool ProfileAdapter::checkPermission(const QUrl &origin, PermissionType type) +QList<QWebEnginePermission> ProfileAdapter::listPermissions(const QUrl &origin, QWebEnginePermission::Feature feature) { - return static_cast<PermissionManagerQt*>(profile()->GetPermissionControllerDelegate())->checkPermission(origin, type); + if (persistentPermissionsPolicy() == ProfileAdapter::NoPersistentPermissions) + return QList<QWebEnginePermission>(); + + return static_cast<PermissionManagerQt*>(profile()->GetPermissionControllerDelegate())->listPermissions(origin, feature); } QString ProfileAdapter::httpAcceptLanguageWithoutQualities() const @@ -591,9 +623,9 @@ void ProfileAdapter::setHttpAcceptLanguage(const QString &httpAcceptLanguage) } m_profile->ForEachLoadedStoragePartition( - base::BindRepeating([](std::string accept_language, content::StoragePartition *storage_partition) { - storage_partition->GetNetworkContext()->SetAcceptLanguage(accept_language); - }, http_accept_language)); + [http_accept_language](content::StoragePartition *storage_partition) { + storage_partition->GetNetworkContext()->SetAcceptLanguage(http_accept_language); + }); } QVariant ProfileAdapter::clientHint(ClientHint clientHint) const diff --git a/src/core/profile_adapter.h b/src/core/profile_adapter.h index 4be0ea51e..6550e6176 100644 --- a/src/core/profile_adapter.h +++ b/src/core/profile_adapter.h @@ -28,6 +28,7 @@ #include <QtWebEngineCore/qwebenginecookiestore.h> #include <QtWebEngineCore/qwebengineurlrequestinterceptor.h> #include <QtWebEngineCore/qwebengineurlschemehandler.h> +#include <QtWebEngineCore/qwebenginepermission.h> #include "net/qrc_url_scheme_handler.h" QT_FORWARD_DECLARE_CLASS(QObject) @@ -127,20 +128,10 @@ public: TrackVisitedLinksOnDisk, }; - enum PermissionType { - UnsupportedPermission = 0, - GeolocationPermission = 1, - NotificationPermission = 2, - AudioCapturePermission = 3, - VideoCapturePermission = 4, - ClipboardReadWrite = 5, - LocalFontsPermission = 6, - }; - - enum PermissionState { - AskPermission = 0, - AllowedPermission = 1, - DeniedPermission = 2 + enum PersistentPermissionsPolicy { + NoPersistentPermissions = 0, + PersistentPermissionsInMemory, + PersistentPermissionsOnDisk, }; enum ClientHint : uchar { @@ -161,6 +152,9 @@ public: PersistentCookiesPolicy persistentCookiesPolicy() const; void setPersistentCookiesPolicy(ProfileAdapter::PersistentCookiesPolicy); + PersistentPermissionsPolicy persistentPermissionsPolicy() const; + void setPersistentPermissionsPolicy(ProfileAdapter::PersistentPermissionsPolicy); + VisitedLinksPolicy visitedLinksPolicy() const; void setVisitedLinksPolicy(ProfileAdapter::VisitedLinksPolicy); @@ -178,8 +172,9 @@ public: const QList<QByteArray> customUrlSchemes() const; UserResourceControllerHost *userResourceController(); - void permissionRequestReply(const QUrl &origin, PermissionType type, PermissionState reply); - bool checkPermission(const QUrl &origin, PermissionType type); + void setPermission(const QUrl &origin, QWebEnginePermission::Feature feature, QWebEnginePermission::State state); + QWebEnginePermission::State getPermissionState(const QUrl &origin, QWebEnginePermission::Feature feature); + QList<QWebEnginePermission> listPermissions(const QUrl &origin = QUrl(), QWebEnginePermission::Feature feature = QWebEnginePermission::Unsupported); QString httpAcceptLanguageWithoutQualities() const; QString httpAcceptLanguage() const; @@ -191,6 +186,7 @@ public: void setClientHintsEnabled(bool enabled); void resetClientHints(); + void clearHttpCache(); #if QT_CONFIG(ssl) @@ -235,6 +231,7 @@ private: HttpCacheType m_httpCacheType; QString m_httpAcceptLanguage; PersistentCookiesPolicy m_persistentCookiesPolicy; + PersistentPermissionsPolicy m_persistentPermissionsPolicy; VisitedLinksPolicy m_visitedLinksPolicy; QHash<QByteArray, QPointer<QWebEngineUrlSchemeHandler>> m_customUrlSchemeHandlers; QHash<QByteArray, QWeakPointer<UserNotificationController>> m_ephemeralNotifications; diff --git a/src/core/profile_io_data_qt.cpp b/src/core/profile_io_data_qt.cpp index 859aff8d4..31a85a534 100644 --- a/src/core/profile_io_data_qt.cpp +++ b/src/core/profile_io_data_qt.cpp @@ -37,8 +37,6 @@ ProfileIODataQt::~ProfileIODataQt() { if (content::BrowserThread::IsThreadInitialized(content::BrowserThread::IO)) DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - - m_resourceContext.reset(); } QPointer<ProfileAdapter> ProfileIODataQt::profileAdapter() @@ -69,11 +67,6 @@ void ProfileIODataQt::shutdownOnUIThread() } } -content::ResourceContext *ProfileIODataQt::resourceContext() -{ - return m_resourceContext.get(); -} - #if BUILDFLAG(ENABLE_EXTENSIONS) extensions::ExtensionSystemQt* ProfileIODataQt::GetExtensionSystem() { @@ -91,7 +84,6 @@ void ProfileIODataQt::initializeOnUIThread() { m_profileAdapter = m_profile->profileAdapter(); DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - m_resourceContext.reset(new content::ResourceContext()); m_cookieDelegate = new CookieMonsterDelegateQt(); m_cookieDelegate->setClient(m_profile->profileAdapter()->cookieStore()); m_proxyConfigMonitor.reset(new ProxyConfigMonitor(m_profile->GetPrefs())); @@ -152,15 +144,12 @@ void ProfileIODataQt::resetNetworkContext() Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); Q_ASSERT(m_clearHttpCacheState != Removing); setFullConfiguration(); - m_profile->ForEachLoadedStoragePartition( - base::BindRepeating([](ProfileIODataQt *profileData, - content::StoragePartition *storage) { - storage->SetNetworkContextCreatedObserver(profileData); - - auto storage_impl = static_cast<content::StoragePartitionImpl *>(storage); - storage_impl->ResetURLLoaderFactories(); - storage_impl->ResetNetworkContext(); - }, this)); + m_profile->ForEachLoadedStoragePartition([this](content::StoragePartition *storage) { + storage->SetNetworkContextCreatedObserver(this); + auto storage_impl = static_cast<content::StoragePartitionImpl *>(storage); + storage_impl->ResetURLLoaderFactories(); + storage_impl->ResetNetworkContext(); + }); } void ProfileIODataQt::OnNetworkContextCreated(content::StoragePartition *storage) @@ -174,12 +163,10 @@ void ProfileIODataQt::OnNetworkContextCreated(content::StoragePartition *storage bool pendingReset = false; m_profile->ForEachLoadedStoragePartition( - base::BindRepeating([](bool *pendingReset, - ProfileIODataQt *profileData, - content::StoragePartition *storage) { - if (storage->GetNetworkContextCreatedObserver() == profileData) - *pendingReset = true; - }, &pendingReset, this)); + [&pendingReset, this](content::StoragePartition *storage) { + if (storage->GetNetworkContextCreatedObserver() == this) + pendingReset = true; + }); if (pendingReset) return; diff --git a/src/core/profile_io_data_qt.h b/src/core/profile_io_data_qt.h index 0d032e4dc..a871307d7 100644 --- a/src/core/profile_io_data_qt.h +++ b/src/core/profile_io_data_qt.h @@ -20,10 +20,6 @@ namespace mojom { class CertVerifierCreationParams; }} -namespace content { -class ResourceContext; -} - namespace extensions { class ExtensionSystemQt; } @@ -66,7 +62,6 @@ public: virtual ~ProfileIODataQt(); QPointer<ProfileAdapter> profileAdapter(); - content::ResourceContext *resourceContext(); #if BUILDFLAG(ENABLE_EXTENSIONS) extensions::ExtensionSystemQt* GetExtensionSystem(); #endif // BUILDFLAG(ENABLE_EXTENSIONS) @@ -104,7 +99,6 @@ private: void removeBrowsingDataRemoverObserver(); ProfileQt *m_profile; - std::unique_ptr<content::ResourceContext> m_resourceContext; scoped_refptr<CookieMonsterDelegateQt> m_cookieDelegate; QPointer<ProfileAdapter> m_profileAdapter; // never dereferenced in IO thread and it is passed by qpointer ProfileAdapter::PersistentCookiesPolicy m_persistentCookiesPolicy; diff --git a/src/core/profile_qt.cpp b/src/core/profile_qt.cpp index 293e8d557..ffb1297a5 100644 --- a/src/core/profile_qt.cpp +++ b/src/core/profile_qt.cpp @@ -15,7 +15,6 @@ #include "qtwebenginecoreglobal_p.h" #include "type_conversion.h" #include "web_engine_library_info.h" -#include "web_engine_context.h" #include "base/base_paths.h" #include "base/files/file_util.h" @@ -116,11 +115,6 @@ bool ProfileQt::IsOffTheRecord() return m_profileAdapter->isOffTheRecord(); } -content::ResourceContext *ProfileQt::GetResourceContext() -{ - return m_profileIOData->resourceContext(); -} - content::DownloadManagerDelegate *ProfileQt::GetDownloadManagerDelegate() { return m_profileAdapter->downloadManagerDelegate(); @@ -181,7 +175,7 @@ content::BrowsingDataRemoverDelegate *ProfileQt::GetBrowsingDataRemoverDelegate( content::PermissionControllerDelegate *ProfileQt::GetPermissionControllerDelegate() { if (!m_permissionManager) - m_permissionManager.reset(new PermissionManagerQt()); + setupPermissionsManager(); return m_permissionManager.get(); } @@ -260,6 +254,11 @@ void ProfileQt::setupPrefService() #endif } +void ProfileQt::setupPermissionsManager() +{ + m_permissionManager.reset(new PermissionManagerQt(profileAdapter())); +} + PrefServiceAdapter &ProfileQt::prefServiceAdapter() { return m_prefServiceAdapter; diff --git a/src/core/profile_qt.h b/src/core/profile_qt.h index b5cd08db1..5394182e4 100644 --- a/src/core/profile_qt.h +++ b/src/core/profile_qt.h @@ -11,10 +11,6 @@ class PrefService; -namespace content { -class ResourceContext; -} - namespace extensions { class ExtensionSystemQt; } @@ -40,7 +36,6 @@ public: base::FilePath GetPath() override; bool IsOffTheRecord() override; - content::ResourceContext *GetResourceContext() override; content::DownloadManagerDelegate *GetDownloadManagerDelegate() override; content::BrowserPluginGuestManager *GetGuestManager() override; storage::SpecialStoragePolicy *GetSpecialStoragePolicy() override; @@ -77,6 +72,7 @@ public: // Build/Re-build the preference service. Call when updating the storage // data path. void setupPrefService(); + void setupPermissionsManager(); PrefServiceAdapter &prefServiceAdapter(); const PrefServiceAdapter &prefServiceAdapter() const; diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index 888043fda..98d0471c1 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -21,7 +21,6 @@ #include "content/browser/renderer_host/frame_tree.h" #include "content/browser/renderer_host/frame_tree_node.h" #include "content/browser/renderer_host/cursor_manager.h" -#include "content/browser/renderer_host/input/synthetic_gesture_target.h" #include "content/browser/renderer_host/render_frame_host_impl.h" #include "content/browser/renderer_host/render_view_host_delegate.h" #include "content/browser/renderer_host/render_view_host_impl.h" @@ -29,6 +28,7 @@ #include "content/browser/renderer_host/ui_events_helper.h" #include "content/common/content_switches_internal.h" #include "content/common/cursors/webcursor.h" +#include "content/common/input/synthetic_gesture_target.h" #include "content/public/browser/web_contents.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/base/cursor/cursor.h" @@ -160,6 +160,8 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost *widget &m_delegatedFrameHostClient, true /* should_register_frame_sink_id */)); + m_delegatedFrameHost->SetIsFrameSinkIdOwner(true); + content::ImageTransportFactory *imageTransportFactory = content::ImageTransportFactory::GetInstance(); ui::ContextFactory *contextFactory = imageTransportFactory->GetContextFactory(); m_uiCompositor.reset(new FlingingCompositor( @@ -298,6 +300,12 @@ content::WebContentsAccessibility *RenderWidgetHostViewQt::GetWebContentsAccessi return m_webContentsAccessibility.get(); } +void RenderWidgetHostViewQt::OnRendererWidgetCreated() +{ + if (m_adapterClient) + SetBackgroundColor(toSk(m_adapterClient->backgroundColor())); +} + QObject *WebContentsAccessibilityQt::accessibilityParentObject() const { return m_rwhv->m_adapterClient->accessibilityParentObject(); @@ -910,8 +918,7 @@ void RenderWidgetHostViewQt::WheelEventAck(const blink::WebMouseWheelEvent &even } void RenderWidgetHostViewQt::GestureEventAck(const blink::WebGestureEvent &event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) + blink::mojom::InputEventResultState ack_result) { // Forward unhandled scroll events back as wheel events if (event.GetType() != blink::WebInputEvent::Type::kGestureScrollUpdate) diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index a55e04dd8..49c1125fc 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -95,8 +95,7 @@ public: void WheelEventAck(const blink::WebMouseWheelEvent &event, blink::mojom::InputEventResultState ack_result) override; void GestureEventAck(const blink::WebGestureEvent &event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) override; + blink::mojom::InputEventResultState ack_result) override; content::MouseWheelPhaseHandler *GetMouseWheelPhaseHandler() override; viz::ScopedSurfaceIdAllocator DidUpdateVisualProperties(const cc::RenderFrameMetadata &metadata) override; void OnDidUpdateVisualPropertiesComplete(const cc::RenderFrameMetadata &metadata); @@ -137,6 +136,7 @@ public: void RequestSuccessfulPresentationTimeFromHostOrDelegate(blink::mojom::RecordContentToVisibleTimeRequestPtr) override {} void CancelSuccessfulPresentationTimeRequestForHostAndDelegate() override {} void InvalidateLocalSurfaceIdAndAllocationGroup() override {} + void OnRendererWidgetCreated() override; // Overridden from ui::GestureProviderClient. void OnGestureEvent(const ui::GestureEventData& gesture) override; diff --git a/src/core/renderer/content_renderer_client_qt.cpp b/src/core/renderer/content_renderer_client_qt.cpp index cc127e55f..0622fc27e 100644 --- a/src/core/renderer/content_renderer_client_qt.cpp +++ b/src/core/renderer/content_renderer_client_qt.cpp @@ -11,7 +11,6 @@ #include "web_engine_library_info.h" #include "base/task/sequenced_task_runner.h" -#include "components/autofill/content/renderer/autofill_agent.h" #include "components/autofill/content/renderer/password_autofill_agent.h" #include "components/autofill/content/renderer/password_generation_agent.h" #include "components/cdm/renderer/external_clear_key_key_system_info.h" @@ -37,6 +36,7 @@ #include "third_party/blink/public/platform/web_url_error.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/webui/jstemplate_builder.h" +#include "ui/base/webui/web_ui_util.h" #if QT_CONFIG(webengine_spellchecker) #include "components/spellcheck/renderer/spellcheck.h" @@ -178,7 +178,7 @@ void ContentRendererClientQt::RenderFrameCreated(content::RenderFrame *render_fr new QtWebEngineCore::ContentSettingsObserverQt(render_frame); #if QT_CONFIG(webengine_spellchecker) - new SpellCheckProvider(render_frame, m_spellCheck.data(), this); + new SpellCheckProvider(render_frame, m_spellCheck.data()); #endif #if QT_CONFIG(webengine_printing_and_pdf) new printing::PrintRenderFrameHelper(render_frame, base::WrapUnique(new PrintWebViewHelperDelegateQt())); @@ -188,22 +188,24 @@ void ContentRendererClientQt::RenderFrameCreated(content::RenderFrame *render_fr #if BUILDFLAG(ENABLE_EXTENSIONS) associated_interfaces->AddInterface<extensions::mojom::MimeHandlerViewContainerManager>( - base::BindRepeating( - &extensions::MimeHandlerViewContainerManager::BindReceiver, - render_frame->GetRoutingID())); + base::BindRepeating(&extensions::MimeHandlerViewContainerManager::BindReceiver, + base::Unretained(render_frame))); auto registry = std::make_unique<service_manager::BinderRegistry>(); ExtensionsRendererClientQt::GetInstance()->RenderFrameCreated(render_frame, render_frame_observer->registry()); #endif - autofill::PasswordAutofillAgent *password_autofill_agent = - new autofill::PasswordAutofillAgent(render_frame, associated_interfaces); - autofill::PasswordGenerationAgent *password_generation_agent = - new autofill::PasswordGenerationAgent(render_frame, password_autofill_agent, - associated_interfaces); - - new autofill::AutofillAgent(render_frame, password_autofill_agent, password_generation_agent, - associated_interfaces); + auto password_autofill_agent = + std::make_unique<autofill::PasswordAutofillAgent>(render_frame, associated_interfaces); + auto password_generation_agent = + std::make_unique<autofill::PasswordGenerationAgent>(render_frame, password_autofill_agent.get(), associated_interfaces); + + new autofill::AutofillAgent( + render_frame, + { autofill::AutofillAgent::UsesKeyboardAccessoryForSuggestions(false), + autofill::AutofillAgent::ExtractAllDatalists(false) }, + std::move(password_autofill_agent), std::move(password_generation_agent), + associated_interfaces); } void ContentRendererClientQt::WebViewCreated(blink::WebView *web_view, @@ -303,13 +305,13 @@ void ContentRendererClientQt::GetNavigationErrorStringsInternal(content::RenderF if (template_html.empty()) NOTREACHED() << "unable to load template. ID: " << resourceId; else // "t" is the id of the templates root node. - *errorHtml = webui::GetTemplatesHtml(template_html, errorPageState.strings, "t"); + *errorHtml = webui::GetLocalizedHtml(template_html, errorPageState.strings); } } -uint64_t ContentRendererClientQt::VisitedLinkHash(const char *canonicalUrl, size_t length) +uint64_t ContentRendererClientQt::VisitedLinkHash(std::string_view canonicalUrl) { - return m_visitedLinkReader->ComputeURLFingerprint(canonicalUrl, length); + return m_visitedLinkReader->ComputeURLFingerprint(canonicalUrl); } bool ContentRendererClientQt::IsLinkVisited(uint64_t linkHash) @@ -355,8 +357,8 @@ void AppendParams(const std::vector<content::WebPluginMimeType::Param> &addition values[existing_size + i] = blink::WebString::FromUTF16(additional_params[i].value); } - existing_names->Swap(names); - existing_values->Swap(values); + existing_names->swap(names); + existing_values->swap(values); } #endif // BUILDFLAG(ENABLE_PLUGINS) diff --git a/src/core/renderer/content_renderer_client_qt.h b/src/core/renderer/content_renderer_client_qt.h index b2231f00a..8151c9710 100644 --- a/src/core/renderer/content_renderer_client_qt.h +++ b/src/core/renderer/content_renderer_client_qt.h @@ -66,7 +66,7 @@ public: int http_status, content::mojom::AlternativeErrorPageOverrideInfoPtr alternative_error_page_info, std::string *error_html) override; - uint64_t VisitedLinkHash(const char *canonical_url, size_t length) override; + uint64_t VisitedLinkHash(std::string_view canonical_url) override; bool IsLinkVisited(uint64_t linkHash) override; std::unique_ptr<blink::WebPrescientNetworking> CreatePrescientNetworking(content::RenderFrame *render_frame) override; void GetSupportedKeySystems(media::GetSupportedKeySystemsCB cb) override; diff --git a/src/core/renderer/content_settings_observer_qt.cpp b/src/core/renderer/content_settings_observer_qt.cpp index 3e3c159f5..c78f53d8a 100644 --- a/src/core/renderer/content_settings_observer_qt.cpp +++ b/src/core/renderer/content_settings_observer_qt.cpp @@ -39,6 +39,7 @@ ContentSettingsObserverQt::ContentSettingsObserverQt(content::RenderFrame *rende ContentSettingsObserverQt::~ContentSettingsObserverQt() {} +#if BUILDFLAG(CONTENT_ENABLE_LEGACY_IPC) bool ContentSettingsObserverQt::OnMessageReceived(const IPC::Message &message) { bool handled = true; @@ -49,6 +50,7 @@ bool ContentSettingsObserverQt::OnMessageReceived(const IPC::Message &message) return handled; } +#endif void ContentSettingsObserverQt::DidCommitProvisionalLoad(ui::PageTransition /*transition*/) { @@ -83,11 +85,12 @@ void ContentSettingsObserverQt::AllowStorageAccess(StorageType storage_type, // Verify there are no duplicate insertions. DCHECK(inserted); - +#if BUILDFLAG(CONTENT_ENABLE_LEGACY_IPC) Send(new QtWebEngineHostMsg_RequestStorageAccessAsync(routing_id(), m_currentRequestId, url::Origin(frame->GetSecurityOrigin()).GetURL(), url::Origin(frame->Top()->GetSecurityOrigin()).GetURL(), int(storage_type))); +#endif } bool ContentSettingsObserverQt::AllowStorageAccessSync(StorageType storage_type) @@ -105,9 +108,11 @@ bool ContentSettingsObserverQt::AllowStorageAccessSync(StorageType storage_type) } bool result = false; +#if BUILDFLAG(CONTENT_ENABLE_LEGACY_IPC) Send(new QtWebEngineHostMsg_AllowStorageAccess(routing_id(), url::Origin(frame->GetSecurityOrigin()).GetURL(), url::Origin(frame->Top()->GetSecurityOrigin()).GetURL(), int(storage_type), &result)); +#endif if (sameOrigin) m_cachedStoragePermissions[key] = result; return result; diff --git a/src/core/renderer/content_settings_observer_qt.h b/src/core/renderer/content_settings_observer_qt.h index 415d0b6b7..f843c61ee 100644 --- a/src/core/renderer/content_settings_observer_qt.h +++ b/src/core/renderer/content_settings_observer_qt.h @@ -9,6 +9,7 @@ #define CONTENT_SETTINGS_OBSERVER_QT_H #include "base/containers/flat_map.h" +#include "content/common/buildflags.h" #include "content/public/renderer/render_frame_observer.h" #include "content/public/renderer/render_frame_observer_tracker.h" #include "third_party/blink/public/platform/web_content_settings_client.h" @@ -33,7 +34,9 @@ public: private: // RenderFrameObserver implementation: +#if BUILDFLAG(CONTENT_ENABLE_LEGACY_IPC) bool OnMessageReceived(const IPC::Message &message) override; +#endif void DidCommitProvisionalLoad(ui::PageTransition transition) override; void OnDestruct() override; diff --git a/src/core/renderer/extensions/extensions_renderer_client_qt.cpp b/src/core/renderer/extensions/extensions_renderer_client_qt.cpp index b36ed9e8b..9db6bbe36 100644 --- a/src/core/renderer/extensions/extensions_renderer_client_qt.cpp +++ b/src/core/renderer/extensions/extensions_renderer_client_qt.cpp @@ -31,6 +31,7 @@ #include "extensions/renderer/extensions_render_frame_observer.h" #include "extensions/renderer/renderer_extension_registry.h" #include "extensions/renderer/script_context.h" +#include "extensions/renderer/extensions_renderer_api_provider.h" #include "third_party/blink/public/platform/web_url.h" #include "third_party/blink/public/web/web_plugin_params.h" @@ -108,7 +109,9 @@ void ExtensionsRendererClientQt::RenderThreadStarted() { content::RenderThread *thread = content::RenderThread::Get(); if (!extension_dispatcher_) - extension_dispatcher_.reset(new extensions::Dispatcher(std::make_unique<ExtensionsDispatcherDelegateQt>())); + extension_dispatcher_.reset(new extensions::Dispatcher( + std::make_unique<ExtensionsDispatcherDelegateQt>(), + std::vector<std::unique_ptr<extensions::ExtensionsRendererAPIProvider>>())); extension_dispatcher_->OnRenderThreadStarted(thread); permissions_policy_delegate_.reset(new RendererPermissionsPolicyDelegateQt(extension_dispatcher_.get())); resource_request_policy_.reset(new extensions::ResourceRequestPolicyQt(extension_dispatcher_.get())); @@ -149,7 +152,7 @@ void ExtensionsRendererClientQt::WillSendRequest(blink::WebLocalFrame *frame, if (url.ProtocolIs(extensions::kExtensionScheme) && !resource_request_policy_->CanRequestResource(url, frame, transition_type, - base::OptionalFromPtr(initiator_origin))) { + initiator_origin)) { *new_url = GURL(chrome::kExtensionInvalidRequestURL); } } diff --git a/src/core/renderer/extensions/resource_request_policy_qt.cpp b/src/core/renderer/extensions/resource_request_policy_qt.cpp index a61e53310..2e4eea771 100644 --- a/src/core/renderer/extensions/resource_request_policy_qt.cpp +++ b/src/core/renderer/extensions/resource_request_policy_qt.cpp @@ -51,7 +51,7 @@ void ResourceRequestPolicyQt::OnExtensionUnloaded(const ExtensionId &extension_i bool ResourceRequestPolicyQt::CanRequestResource(const GURL &resource_url, blink::WebLocalFrame *frame, ui::PageTransition transition_type, - const absl::optional<url::Origin>& initiator_origin) + const url::Origin *initiator_origin) { CHECK(resource_url.SchemeIs(kExtensionScheme)); diff --git a/src/core/renderer/extensions/resource_request_policy_qt.h b/src/core/renderer/extensions/resource_request_policy_qt.h index ec108519f..6807f5091 100644 --- a/src/core/renderer/extensions/resource_request_policy_qt.h +++ b/src/core/renderer/extensions/resource_request_policy_qt.h @@ -39,7 +39,7 @@ public: bool CanRequestResource(const GURL &resource_url, blink::WebLocalFrame *frame, ui::PageTransition transition_type, - const absl::optional<url::Origin> &initiator_origin); + const url::Origin *initiator_origin); private: Dispatcher *m_dispatcher; diff --git a/src/core/renderer/plugins/loadable_plugin_placeholder_qt.cpp b/src/core/renderer/plugins/loadable_plugin_placeholder_qt.cpp index 06fd4f71f..4d25be12a 100644 --- a/src/core/renderer/plugins/loadable_plugin_placeholder_qt.cpp +++ b/src/core/renderer/plugins/loadable_plugin_placeholder_qt.cpp @@ -22,11 +22,11 @@ namespace QtWebEngineCore { // static gin::WrapperInfo LoadablePluginPlaceholderQt::kWrapperInfo = {gin::kEmbedderNativeGin}; -LoadablePluginPlaceholderQt::LoadablePluginPlaceholderQt(content::RenderFrame* render_frame, - const blink::WebPluginParams& params, - const std::string& html_data, - const std::u16string& title) - : plugins::LoadablePluginPlaceholder(render_frame, params, html_data) +LoadablePluginPlaceholderQt::LoadablePluginPlaceholderQt(content::RenderFrame *render_frame, + const blink::WebPluginParams ¶ms, + const std::string &html_data, + const std::u16string &title) + : plugins::LoadablePluginPlaceholder(render_frame, params) {} LoadablePluginPlaceholderQt::~LoadablePluginPlaceholderQt() diff --git a/src/core/renderer/render_frame_observer_qt.cpp b/src/core/renderer/render_frame_observer_qt.cpp index e6489eefb..03fb0d9e8 100644 --- a/src/core/renderer/render_frame_observer_qt.cpp +++ b/src/core/renderer/render_frame_observer_qt.cpp @@ -51,7 +51,7 @@ bool RenderFrameObserverQt::OnAssociatedInterfaceRequestForFrame(const std::stri return m_associated_interfaces.TryBindInterface(interface_name, handle); } -void RenderFrameObserverQt::WillDetach() +void RenderFrameObserverQt::WillDetach(blink::DetachReason reason) { m_isFrameDetached = true; } diff --git a/src/core/renderer/render_frame_observer_qt.h b/src/core/renderer/render_frame_observer_qt.h index 8cab3bd9a..c3a1dd8ba 100644 --- a/src/core/renderer/render_frame_observer_qt.h +++ b/src/core/renderer/render_frame_observer_qt.h @@ -34,7 +34,7 @@ public: const std::string &interface_name, mojo::ScopedInterfaceEndpointHandle *handle) override; void OnDestruct() override; - void WillDetach() override; + void WillDetach(blink::DetachReason detach_reason) override; bool isFrameDetached() const; diff --git a/src/core/renderer/user_resource_controller.cpp b/src/core/renderer/user_resource_controller.cpp index eff304981..82579ea7d 100644 --- a/src/core/renderer/user_resource_controller.cpp +++ b/src/core/renderer/user_resource_controller.cpp @@ -110,7 +110,7 @@ private: void DidCommitProvisionalLoad(ui::PageTransition transition) override; void DidDispatchDOMContentLoadedEvent() override; void DidFinishLoad() override; - void WillDetach() override; + void WillDetach(blink::DetachReason detach_reason) override; void OnDestruct() override; void AddScript(const QtWebEngineCore::UserScriptData &data) override; void RemoveScript(const QtWebEngineCore::UserScriptData &data) override; @@ -231,7 +231,8 @@ void UserResourceController::RenderFrameObserverHelper::DidFinishLoad() QtWebEngineCore::UserScriptData::AfterLoad)); } -void UserResourceController::RenderFrameObserverHelper::WillDetach() +void UserResourceController::RenderFrameObserverHelper::WillDetach( + blink::DetachReason detach_reason) { m_runner.reset(); } diff --git a/src/core/tools/qwebengine_convert_dict/CMakeLists.txt b/src/core/tools/qwebengine_convert_dict/CMakeLists.txt index 5e8a1de14..fcc11bdcb 100644 --- a/src/core/tools/qwebengine_convert_dict/CMakeLists.txt +++ b/src/core/tools/qwebengine_convert_dict/CMakeLists.txt @@ -11,6 +11,9 @@ if(QT_FEATURE_webengine_spellchecker AND NOT CMAKE_CROSSCOMPILING) INCLUDE_DIRECTORIES ../../../3rdparty/chromium/third_party/abseil-cpp ) + if(MSVC AND NOT CLANG) + target_compile_options(${dict_target_name} PRIVATE "/Zc:preprocessor") + endif() if(COMMAND qt_internal_return_unless_building_tools) qt_internal_return_unless_building_tools() endif() diff --git a/src/core/type_conversion.h b/src/core/type_conversion.h index 0da8a6931..688ea014d 100644 --- a/src/core/type_conversion.h +++ b/src/core/type_conversion.h @@ -209,11 +209,11 @@ QIcon toQIcon(const std::vector<SkBitmap> &bitmaps); inline QDateTime toQt(base::Time time) { - return QDateTime::fromMSecsSinceEpoch(time.ToJavaTime()); + return QDateTime::fromMSecsSinceEpoch(time.InMillisecondsSinceUnixEpoch()); } inline base::Time toTime(const QDateTime &dateTime) { - return base::Time::FromJavaTime(dateTime.toMSecsSinceEpoch()); + return base::Time::FromMillisecondsSinceUnixEpoch(dateTime.toMSecsSinceEpoch()); } inline QNetworkCookie toQt(const net::CanonicalCookie & cookie) diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index 6decf8780..e73eca7f3 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -174,19 +174,16 @@ 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) -static void callbackOnPrintingFinished(WebContentsAdapterClient *adapterClient, - int requestId, +static void callbackOnPrintingFinished(WebContentsAdapter *adapter, quint64 requestId, QSharedPointer<QByteArray> result) { - if (requestId) - adapterClient->didPrintPage(requestId, result); + adapter->didPrintPage(requestId, result); } static void callbackOnPdfSavingFinished(WebContentsAdapterClient *adapterClient, @@ -993,6 +990,9 @@ void WebContentsAdapter::setZoomFactor(qreal factor) const content::GlobalRenderFrameHostId global_id = m_webContents->GetPrimaryMainFrame()->GetGlobalId(); zoomMap->SetTemporaryZoomLevel(global_id, zoomLevel); } + + if (m_adapterClient) + m_adapterClient->zoomFactorChanged(currentZoomFactor()); } qreal WebContentsAdapter::currentZoomFactor() const @@ -1039,36 +1039,67 @@ QAccessibleInterface *WebContentsAdapter::browserAccessible() } #endif // QT_CONFIG(accessibility) -void WebContentsAdapter::runJavaScript(const QString &javaScript, quint32 worldId) +content::RenderFrameHost *WebContentsAdapter::renderFrameHostFromFrameId(quint64 frameId) const { - CHECK_INITIALIZED(); - content::RenderFrameHost *rfh = m_webContents->GetPrimaryMainFrame(); - Q_ASSERT(rfh); - if (!static_cast<content::RenderFrameHostImpl*>(rfh)->GetAssociatedLocalFrame()) { - qWarning() << "Local frame is gone, not running script"; - return; + content::RenderFrameHost *result; + if (frameId == kUseMainFrameId) { + result = m_webContents->GetPrimaryMainFrame(); + } else { + auto *ftn = content::FrameTreeNode::GloballyFindByID(static_cast<int>(frameId)); + if (!ftn) + return nullptr; + + result = ftn->current_frame_host(); } - if (worldId == 0) - rfh->ExecuteJavaScript(toString16(javaScript), base::NullCallback()); - else - rfh->ExecuteJavaScriptInIsolatedWorld(toString16(javaScript), base::NullCallback(), worldId); + Q_ASSERT(result); + return result; } -quint64 WebContentsAdapter::runJavaScriptCallbackResult(const QString &javaScript, quint32 worldId) +void WebContentsAdapter::runJavaScript(const QString &javaScript, quint32 worldId, quint64 frameId, + const std::function<void(const QVariant &)> &callback) { - CHECK_INITIALIZED(0); - content::RenderFrameHost *rfh = m_webContents->GetPrimaryMainFrame(); - Q_ASSERT(rfh); + auto exit = [&] { + if (callback) + callback(QVariant()); + }; + + if (!isInitialized()) + return exit(); + auto *rfh = renderFrameHostFromFrameId(frameId); + if (!rfh) + return exit(); if (!static_cast<content::RenderFrameHostImpl*>(rfh)->GetAssociatedLocalFrame()) { qWarning() << "Local frame is gone, not running script"; - return 0; + return exit(); + } + + content::RenderFrameHost::JavaScriptResultCallback internalCallback = base::NullCallback(); + if (callback) { + internalCallback = base::BindOnce(&callbackOnEvaluateJS, this, m_nextRequestId); + m_javaScriptCallbacks.insert(m_nextRequestId, callback); + ++m_nextRequestId; } - content::RenderFrameHost::JavaScriptResultCallback callback = base::BindOnce(&callbackOnEvaluateJS, m_adapterClient, m_nextRequestId); if (worldId == 0) - rfh->ExecuteJavaScript(toString16(javaScript), std::move(callback)); + rfh->ExecuteJavaScript(toString16(javaScript), std::move(internalCallback)); else - rfh->ExecuteJavaScriptInIsolatedWorld(toString16(javaScript), std::move(callback), worldId); - return m_nextRequestId++; + rfh->ExecuteJavaScriptInIsolatedWorld(toString16(javaScript), std::move(internalCallback), + worldId); +} + +void WebContentsAdapter::didRunJavaScript(quint64 requestId, const base::Value &result) +{ + Q_ASSERT(requestId); + auto callback = m_javaScriptCallbacks.take(requestId); + Q_ASSERT(callback); + callback(fromJSValue(&result)); +} + +// Called when QWebEnginePage is deleted +void WebContentsAdapter::clearJavaScriptCallbacks() +{ + for (auto varFun : std::as_const(m_javaScriptCallbacks)) + varFun(QVariant()); + m_javaScriptCallbacks.clear(); } quint64 WebContentsAdapter::fetchDocumentMarkup() @@ -1315,7 +1346,8 @@ void WebContentsAdapter::wasHidden() m_webContents->WasHidden(); } -void WebContentsAdapter::printToPDF(const QPageLayout &pageLayout, const QPageRanges &pageRanges, const QString &filePath) +void WebContentsAdapter::printToPDF(const QPageLayout &pageLayout, const QPageRanges &pageRanges, + const QString &filePath, quint64 frameId) { #if QT_CONFIG(webengine_printing_and_pdf) CHECK_INITIALIZED(); @@ -1325,40 +1357,44 @@ void WebContentsAdapter::printToPDF(const QPageLayout &pageLayout, const QPageRa content::WebContents *webContents = m_webContents.get(); if (content::WebContents *guest = guestWebContents()) webContents = guest; - PrintViewManagerQt::FromWebContents(webContents)->PrintToPDFFileWithCallback(pageLayout, - pageRanges, - true, - filePath, - std::move(callback)); + PrintViewManagerQt::FromWebContents(webContents) + ->PrintToPDFFileWithCallback(pageLayout, pageRanges, true, filePath, frameId, + std::move(callback)); #endif // QT_CONFIG(webengine_printing_and_pdf) } -quint64 WebContentsAdapter::printToPDFCallbackResult(const QPageLayout &pageLayout, - const QPageRanges &pageRanges, - bool colorMode, - bool useCustomMargins) +void WebContentsAdapter::printToPDFCallbackResult( + std::function<void(QSharedPointer<QByteArray>)> &&callback, const QPageLayout &pageLayout, + const QPageRanges &pageRanges, bool colorMode, bool useCustomMargins, quint64 frameId) { #if QT_CONFIG(webengine_printing_and_pdf) - CHECK_INITIALIZED(0); - PrintViewManagerQt::PrintToPDFCallback callback = base::BindOnce(&callbackOnPrintingFinished, - m_adapterClient, - m_nextRequestId); + CHECK_INITIALIZED(); + Q_ASSERT(callback); + PrintViewManagerQt::PrintToPDFCallback internalCallback = + base::BindOnce(&callbackOnPrintingFinished, this, m_nextRequestId); content::WebContents *webContents = m_webContents.get(); if (content::WebContents *guest = guestWebContents()) webContents = guest; - PrintViewManagerQt::FromWebContents(webContents)->PrintToPDFWithCallback(pageLayout, - pageRanges, - colorMode, - useCustomMargins, - std::move(callback)); - return m_nextRequestId++; + PrintViewManagerQt::FromWebContents(webContents) + ->PrintToPDFWithCallback(pageLayout, pageRanges, colorMode, useCustomMargins, frameId, + std::move(internalCallback)); + m_printCallbacks.emplace(m_nextRequestId++, std::move(callback)); #else Q_UNUSED(pageLayout); Q_UNUSED(colorMode); - return 0; #endif // QT_CONFIG(webengine_printing_and_pdf) } +void WebContentsAdapter::didPrintPage(quint64 requestId, QSharedPointer<QByteArray> result) +{ + Q_ASSERT(requestId); + auto mapIt = m_printCallbacks.find(requestId); + Q_ASSERT(mapIt != m_printCallbacks.end()); + Q_ASSERT(mapIt->second); + mapIt->second(std::move(result)); + m_printCallbacks.erase(mapIt); +} + QPointF WebContentsAdapter::lastScrollOffset() const { CHECK_INITIALIZED(QPointF()); @@ -1375,21 +1411,92 @@ QSizeF WebContentsAdapter::lastContentsSize() const return QSizeF(); } -void WebContentsAdapter::grantMediaAccessPermission(const QUrl &securityOrigin, WebContentsAdapterClient::MediaRequestFlags flags) +void WebContentsAdapter::setFeaturePermission(const QUrl &origin, QWebEnginePermission::Feature feature, QWebEnginePermission::State state) +{ + if (!QWebEnginePermission::isTransient(feature)) { + // Do not check for initialization in this path so permissions can be set before first navigation + Q_ASSERT(m_profileAdapter); + m_profileAdapter->setPermission(origin, feature, state); + return; + } + + CHECK_INITIALIZED(); + if (feature == QWebEnginePermission::MouseLock) { + switch (state) { + case QWebEnginePermission::Ask: + // Do nothing + break; + case QWebEnginePermission::Denied: + grantMouseLockPermission(origin, false); + break; + case QWebEnginePermission::Granted: + grantMouseLockPermission(origin, true); + break; + } + + return; + } + + const WebContentsAdapterClient::MediaRequestFlags audioVideoCaptureFlags( + WebContentsAdapterClient::MediaVideoCapture | + WebContentsAdapterClient::MediaAudioCapture); + const WebContentsAdapterClient::MediaRequestFlags desktopAudioVideoCaptureFlags( + WebContentsAdapterClient::MediaDesktopVideoCapture | + WebContentsAdapterClient::MediaDesktopAudioCapture); + + switch (state) { + case QWebEnginePermission::Ask: + // Do nothing + return; + case QWebEnginePermission::Denied: + // Deny all media access + grantMediaAccessPermission(origin, WebContentsAdapterClient::MediaNone); + return; + case QWebEnginePermission::Granted: + // Enable only the requested capture type + break; + } + + switch (feature) { + case QWebEnginePermission::MediaAudioVideoCapture: + grantMediaAccessPermission(origin, audioVideoCaptureFlags); + break; + case QWebEnginePermission::MediaAudioCapture: + grantMediaAccessPermission(origin, WebContentsAdapterClient::MediaAudioCapture); + break; + case QWebEnginePermission::MediaVideoCapture: + grantMediaAccessPermission(origin, WebContentsAdapterClient::MediaVideoCapture); + break; + case QWebEnginePermission::DesktopAudioVideoCapture: + grantMediaAccessPermission(origin, desktopAudioVideoCaptureFlags); + break; + case QWebEnginePermission::DesktopVideoCapture: + grantMediaAccessPermission(origin, WebContentsAdapterClient::MediaDesktopVideoCapture); + break; + default: + Q_UNREACHABLE(); + break; + } +} + +QWebEnginePermission::State WebContentsAdapter::getPermissionState(const QUrl &origin, QWebEnginePermission::Feature feature) +{ + // For now, we just return Ask for transient Features + if (QWebEnginePermission::isTransient(feature)) + return QWebEnginePermission::Ask; + + return m_profileAdapter->getPermissionState(origin, feature); +} + +void WebContentsAdapter::grantMediaAccessPermission(const QUrl &origin, WebContentsAdapterClient::MediaRequestFlags flags) { CHECK_INITIALIZED(); // Let the permission manager remember the reply. if (flags & WebContentsAdapterClient::MediaAudioCapture) - m_profileAdapter->permissionRequestReply(securityOrigin, ProfileAdapter::AudioCapturePermission, ProfileAdapter::AllowedPermission); + m_profileAdapter->setPermission(origin, QWebEnginePermission::MediaAudioCapture, QWebEnginePermission::Granted); if (flags & WebContentsAdapterClient::MediaVideoCapture) - m_profileAdapter->permissionRequestReply(securityOrigin, ProfileAdapter::VideoCapturePermission, ProfileAdapter::AllowedPermission); - MediaCaptureDevicesDispatcher::GetInstance()->handleMediaAccessPermissionResponse(m_webContents.get(), securityOrigin, flags); -} - -void WebContentsAdapter::grantFeaturePermission(const QUrl &securityOrigin, ProfileAdapter::PermissionType feature, ProfileAdapter::PermissionState allowed) -{ - Q_ASSERT(m_profileAdapter); - m_profileAdapter->permissionRequestReply(securityOrigin, feature, allowed); + m_profileAdapter->setPermission(origin, QWebEnginePermission::MediaVideoCapture, QWebEnginePermission::Granted); + MediaCaptureDevicesDispatcher::GetInstance()->handleMediaAccessPermissionResponse(m_webContents.get(), origin, flags); } void WebContentsAdapter::grantMouseLockPermission(const QUrl &securityOrigin, bool granted) @@ -1629,8 +1736,12 @@ static void fillDropDataFromMimeData(content::DropData *dropData, const QMimeDat if (mimeData->hasText()) dropData->text = toOptionalString16(mimeData->text()); if (mimeData->hasFormat(QLatin1String(ui::kMimeTypeWebCustomData))) { - QByteArray customData = mimeData->data(QLatin1String(ui::kMimeTypeWebCustomData)); - ui::ReadCustomDataIntoMap(customData.constData(), customData.length(), &dropData->custom_data); + const QByteArray customData = mimeData->data(QLatin1String(ui::kMimeTypeWebCustomData)); + const base::span custom_data(customData.constData(), (long unsigned)customData.length()); + if (auto maybe_data = ui::ReadCustomDataIntoMap(base::as_bytes(custom_data))) + dropData->custom_data = *std::move(maybe_data); + else + dropData->custom_data.clear(); } } diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h index a5cad8664..66736dd21 100644 --- a/src/core/web_contents_adapter.h +++ b/src/core/web_contents_adapter.h @@ -16,17 +16,21 @@ #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 <QtWebEngineCore/qwebenginepermission.h> #include "web_contents_adapter_client.h" +#include <functional> #include <memory> #include <optional> @@ -36,9 +40,14 @@ struct WebPreferences; } } +namespace base { +class Value; +} + namespace content { class WebContents; class SiteInstance; +class RenderFrameHost; } QT_BEGIN_NAMESPACE @@ -64,6 +73,8 @@ class WebChannelIPCTransportHost; class Q_WEBENGINECORE_EXPORT WebContentsAdapter : public QEnableSharedFromThis<WebContentsAdapter> { public: + // Sentinel to indicate that a behavior should happen on the main frame + static constexpr quint64 kUseMainFrameId = -2; // Sentinel to indicate a frame doesn't exist, for example with `findFrameByName` static constexpr quint64 kInvalidFrameId = -3; @@ -129,8 +140,10 @@ public: void serializeNavigationHistory(QDataStream &output); void setZoomFactor(qreal); qreal currentZoomFactor() const; - void runJavaScript(const QString &javaScript, quint32 worldId); - quint64 runJavaScriptCallbackResult(const QString &javaScript, quint32 worldId); + void runJavaScript(const QString &javaScript, quint32 worldId, quint64 frameId, + const std::function<void(const QVariant &)> &callback); + void didRunJavaScript(quint64 requestId, const base::Value &result); + void clearJavaScriptCallbacks(); quint64 fetchDocumentMarkup(); quint64 fetchDocumentInnerText(); void updateWebPreferences(const blink::web_pref::WebPreferences &webPreferences); @@ -166,10 +179,12 @@ public: void devToolsFrontendDestroyed(DevToolsFrontendQt *frontend); QString devToolsId(); - void grantMediaAccessPermission(const QUrl &securityOrigin, WebContentsAdapterClient::MediaRequestFlags flags); - void grantMouseLockPermission(const QUrl &securityOrigin, bool granted); + void setFeaturePermission(const QUrl &origin, QWebEnginePermission::Feature feature, QWebEnginePermission::State state); + QWebEnginePermission::State getPermissionState(const QUrl &origin, QWebEnginePermission::Feature feature); + + void grantMediaAccessPermission(const QUrl &origin, WebContentsAdapterClient::MediaRequestFlags flags); + void grantMouseLockPermission(const QUrl &origin, bool granted); void handlePendingMouseLockPermission(); - void grantFeaturePermission(const QUrl &securityOrigin, ProfileAdapter::PermissionType feature, ProfileAdapter::PermissionState allowed); void setBackgroundColor(const QColor &color); QAccessibleInterface *browserAccessible(); @@ -194,10 +209,11 @@ public: void endDragging(QDropEvent *e, const QPointF &screenPos); void leaveDrag(); #endif // QT_CONFIG(draganddrop) - void printToPDF(const QPageLayout&, const QPageRanges &, const QString&); - quint64 printToPDFCallbackResult(const QPageLayout &, const QPageRanges &, - bool colorMode = true, - bool useCustomMargins = true); + void printToPDF(const QPageLayout &, const QPageRanges &, const QString &, quint64 frameId); + void printToPDFCallbackResult(std::function<void(QSharedPointer<QByteArray>)> &&, + const QPageLayout &, const QPageRanges &, bool colorMode, + bool useCustomMargins, quint64 frameId); + void didPrintPage(quint64 requestId, QSharedPointer<QByteArray> result); void replaceMisspelling(const QString &word); void viewSource(); @@ -230,6 +246,7 @@ private: Q_DISABLE_COPY(WebContentsAdapter) void waitForUpdateDragActionCalled(); bool handleDropDataFileContents(const content::DropData &dropData, QMimeData *mimeData); + content::RenderFrameHost *renderFrameHostFromFrameId(quint64 frameId) const; void wasShown(); void wasHidden(); @@ -255,6 +272,8 @@ private: WebContentsAdapterClient *m_adapterClient; quint64 m_nextRequestId; QMap<QUrl, bool> m_pendingMouseLockPermissions; + QMap<quint64, std::function<void(const QVariant &)>> m_javaScriptCallbacks; + std::map<quint64, std::function<void(QSharedPointer<QByteArray>)>> m_printCallbacks; std::unique_ptr<content::DropData> m_currentDropData; uint m_currentDropAction; bool m_updateDragActionCalled; diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h index a1ad301ed..ca162833c 100644 --- a/src/core/web_contents_adapter_client.h +++ b/src/core/web_contents_adapter_client.h @@ -16,6 +16,7 @@ #define WEB_CONTENTS_ADAPTER_CLIENT_H #include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h> +#include <QtWebEngineCore/qwebenginepermission.h> #include "profile_adapter.h" @@ -26,6 +27,8 @@ #include <QUrl> QT_FORWARD_DECLARE_CLASS(QKeyEvent) +QT_FORWARD_DECLARE_CLASS(QPageLayout) +QT_FORWARD_DECLARE_CLASS(QPageRanges) QT_FORWARD_DECLARE_CLASS(QVariant) QT_FORWARD_DECLARE_CLASS(QWebEngineFileSystemAccessRequest) QT_FORWARD_DECLARE_CLASS(QWebEngineFindTextResult) @@ -147,6 +150,7 @@ public: virtual void titleChanged(const QString&) = 0; virtual void urlChanged() = 0; virtual void iconChanged(const QUrl&) = 0; + virtual void zoomFactorChanged(qreal factor) = 0; virtual void loadProgressChanged(int progress) = 0; virtual void didUpdateTargetURL(const QUrl&) = 0; virtual void selectionChanged() = 0; @@ -175,10 +179,15 @@ public: virtual void javascriptDialog(QSharedPointer<JavaScriptDialogController>) = 0; virtual void runFileChooser(QSharedPointer<FilePickerController>) = 0; virtual void showColorDialog(QSharedPointer<ColorChooserController>) = 0; - virtual void didRunJavaScript(quint64 requestId, const QVariant& result) = 0; + virtual void runJavaScript(const QString &script, quint32 worldId, quint64 frameId, + const std::function<void(const QVariant &)> &callback) = 0; virtual void didFetchDocumentMarkup(quint64 requestId, const QString& result) = 0; virtual void didFetchDocumentInnerText(quint64 requestId, const QString& result) = 0; - virtual void didPrintPage(quint64 requestId, QSharedPointer<QByteArray>) = 0; + virtual void printToPdf(const QString &filePath, const QPageLayout &layout, + const QPageRanges &ranges, quint64 frameId) = 0; + virtual void printToPdf(std::function<void(QSharedPointer<QByteArray>)> &&callback, + const QPageLayout &layout, const QPageRanges &ranges, + quint64 frameId) = 0; virtual void didPrintPageToPdf(const QString &filePath, bool success) = 0; virtual bool passOnFocus(bool reverse) = 0; // returns the last QObject (QWidget/QQuickItem) based object in the accessibility @@ -186,7 +195,7 @@ public: virtual QObject *accessibilityParentObject() = 0; virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID) = 0; virtual void authenticationRequired(QSharedPointer<AuthenticationDialogController>) = 0; - virtual void runFeaturePermissionRequest(ProfileAdapter::PermissionType, const QUrl &securityOrigin) = 0; + virtual void runFeaturePermissionRequest(QWebEnginePermission::Feature, const QUrl &securityOrigin) = 0; virtual void runMediaAccessPermissionRequest(const QUrl &securityOrigin, MediaRequestFlags requestFlags) = 0; virtual void runMouseLockPermissionRequest(const QUrl &securityOrigin) = 0; virtual void runRegisterProtocolHandlerRequest(QWebEngineRegisterProtocolHandlerRequest) = 0; @@ -207,6 +216,7 @@ public: virtual void setToolTip(const QString& toolTipText) = 0; virtual ClientType clientType() = 0; virtual void printRequested() = 0; + virtual void printRequestedByFrame(quint64 frameId) = 0; virtual TouchHandleDrawableDelegate * createTouchHandleDelegate(const QMap<int, QImage> &images) = 0; virtual void showTouchSelectionMenu(TouchSelectionMenuController *menuController, const QRect &bounds, const QSize &handleSize) = 0; virtual void hideTouchSelectionMenu() = 0; @@ -219,6 +229,7 @@ public: virtual WebContentsAdapter* webContentsAdapter() = 0; virtual void releaseProfile() = 0; virtual void showWebAuthDialog(QWebEngineWebAuthUxRequest *request) = 0; + virtual QWebEnginePermission createFeaturePermissionObject(const QUrl &securityOrigin, QWebEnginePermission::Feature feature) = 0; }; } // namespace QtWebEngineCore diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index 4df73fb69..c2cd6981a 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -479,6 +479,14 @@ void WebContentsDelegateQt::DidStopLoading() m_loadingInfo.clear(); } +void WebContentsDelegateQt::emitLoadSucceeded(const QUrl &url) +{ + // Used by CustomURLLoader to emit LoadSucceeded bypassing the inner state of this delegate + m_viewClient->loadFinished( + QWebEngineLoadingInfo(url, QWebEngineLoadingInfo::LoadSucceededStatus)); + m_viewClient->updateNavigationActions(); +} + void WebContentsDelegateQt::didFailLoad(const QUrl &url, int errorCode, const QString &errorDescription) { m_viewClient->iconChanged(QUrl()); @@ -733,7 +741,7 @@ void WebContentsDelegateQt::selectClientCert(const QSharedPointer<ClientCertSele m_viewClient->selectClientCert(selectController); } -void WebContentsDelegateQt::requestFeaturePermission(ProfileAdapter::PermissionType feature, const QUrl &requestingOrigin) +void WebContentsDelegateQt::requestFeaturePermission(QWebEnginePermission::Feature feature, const QUrl &requestingOrigin) { m_viewClient->runFeaturePermissionRequest(feature, requestingOrigin); } @@ -786,13 +794,15 @@ void WebContentsDelegateQt::BeforeUnloadFired(content::WebContents *tab, bool pr m_viewClient->windowCloseRejected(); } -bool WebContentsDelegateQt::CheckMediaAccessPermission(content::RenderFrameHost *, const GURL& security_origin, blink::mojom::MediaStreamType type) +bool WebContentsDelegateQt::CheckMediaAccessPermission(content::RenderFrameHost *, + const url::Origin &security_origin, + blink::mojom::MediaStreamType type) { switch (type) { case blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE: - return m_viewClient->profileAdapter()->checkPermission(toQt(security_origin), ProfileAdapter::AudioCapturePermission); + return m_viewClient->profileAdapter()->getPermissionState(toQt(security_origin), QWebEnginePermission::MediaAudioCapture); case blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE: - return m_viewClient->profileAdapter()->checkPermission(toQt(security_origin), ProfileAdapter::VideoCapturePermission); + return m_viewClient->profileAdapter()->getPermissionState(toQt(security_origin), QWebEnginePermission::MediaVideoCapture); default: LOG(INFO) << "WebContentsDelegateQt::CheckMediaAccessPermission: " << "Unsupported media stream type checked " << type; diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h index 51004878d..899d46cd0 100644 --- a/src/core/web_contents_delegate_qt.h +++ b/src/core/web_contents_delegate_qt.h @@ -106,7 +106,9 @@ public: void UpdateTargetURL(content::WebContents* source, const GURL& url) override; void RequestToLockMouse(content::WebContents *web_contents, bool user_gesture, bool last_unlocked_by_target) override; void BeforeUnloadFired(content::WebContents* tab, bool proceed, bool* proceed_to_fire_unload) override; - bool CheckMediaAccessPermission(content::RenderFrameHost* render_frame_host, const GURL& security_origin, blink::mojom::MediaStreamType type) override; + bool CheckMediaAccessPermission(content::RenderFrameHost *render_frame_host, + const url::Origin &security_origin, + blink::mojom::MediaStreamType type) override; void RegisterProtocolHandler(content::RenderFrameHost* frame_host, const std::string& protocol, const GURL& url, bool user_gesture) override; void UnregisterProtocolHandler(content::RenderFrameHost* frame_host, const std::string& protocol, const GURL& url, bool user_gesture) override; bool TakeFocus(content::WebContents *source, bool reverse) override; @@ -132,11 +134,12 @@ public: content::RenderFrameHost *render_frame_host, bool is_full_page) override; + void emitLoadSucceeded(const QUrl &url); void didFailLoad(const QUrl &url, int errorCode, const QString &errorDescription); void overrideWebPreferences(content::WebContents *, blink::web_pref::WebPreferences*); void allowCertificateError(const QSharedPointer<CertificateErrorController> &); void selectClientCert(const QSharedPointer<ClientCertSelectController> &); - void requestFeaturePermission(ProfileAdapter::PermissionType feature, const QUrl &requestingOrigin); + void requestFeaturePermission(QWebEnginePermission::Feature feature, const QUrl &requestingOrigin); void launchExternalURL(const QUrl &url, ui::PageTransition page_transition, bool is_main_frame, bool has_user_gesture); FindTextHelper *findTextHelper(); diff --git a/src/core/web_contents_view_qt.cpp b/src/core/web_contents_view_qt.cpp index 023f9e99f..50d964de7 100644 --- a/src/core/web_contents_view_qt.cpp +++ b/src/core/web_contents_view_qt.cpp @@ -227,6 +227,7 @@ static Qt::DropActions toQtDropActions(blink::DragOperationsMask ops) } void WebContentsViewQt::StartDragging(const content::DropData &drop_data, + const url::Origin& source_origin, blink::DragOperationsMask allowed_ops, const gfx::ImageSkia &image, const gfx::Vector2d &image_offset, @@ -256,10 +257,11 @@ void WebContentsViewQt::StartDragging(const content::DropData &drop_data, #endif // QT_CONFIG(draganddrop) } -void WebContentsViewQt::UpdateDragCursor(ui::mojom::DragOperation dragOperation) +void WebContentsViewQt::UpdateDragOperation(ui::mojom::DragOperation dragOperation, bool isDrag) { #if QT_CONFIG(draganddrop) - m_client->webContentsAdapter()->updateDragAction(int(dragOperation)); + if (isDrag) + m_client->webContentsAdapter()->updateDragAction(int(dragOperation)); #endif // QT_CONFIG(draganddrop) } diff --git a/src/core/web_contents_view_qt.h b/src/core/web_contents_view_qt.h index 8754250e6..78041a150 100644 --- a/src/core/web_contents_view_qt.h +++ b/src/core/web_contents_view_qt.h @@ -80,13 +80,17 @@ public: #endif // content::RenderViewHostDelegateView overrides: - void StartDragging(const content::DropData& drop_data, blink::DragOperationsMask allowed_ops, + void StartDragging(const content::DropData& drop_data, + const url::Origin& source_origin, + blink::DragOperationsMask allowed_ops, const gfx::ImageSkia& image, const gfx::Vector2d& image_offset, const gfx::Rect& drag_obj_rect, const blink::mojom::DragEventSourceInfo &event_info, content::RenderWidgetHostImpl *source_rwh) override; - void UpdateDragCursor(ui::mojom::DragOperation dragOperation) override; + void UpdateDragOperation(ui::mojom::DragOperation dragOperation, bool document_is_handling_drag) override; + + void TransferDragSecurityInfo(content::WebContentsView *) override {} void ShowContextMenu(content::RenderFrameHost &, const content::ContextMenuParams ¶ms) override; diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index faf9bd542..74453d199 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -11,6 +11,7 @@ #include "base/functional/bind.h" #include "base/command_line.h" #include "base/files/file_path.h" +#include "base/metrics/field_trial.h" #include "base/power_monitor/power_monitor.h" #include "base/power_monitor/power_monitor_device_source.h" #include "base/run_loop.h" @@ -19,9 +20,6 @@ #include "base/task/thread_pool/thread_pool_instance.h" #include "base/threading/thread_restrictions.h" #include "cc/base/switches.h" -#if QT_CONFIG(webengine_webrtc) && QT_CONFIG(webengine_extensions) -#include "chrome/browser/media/webrtc/webrtc_log_uploader.h" -#endif #include "chrome/common/chrome_switches.h" #include "content/common/process_visibility_tracker.h" #include "content/gpu/gpu_child_thread.h" @@ -657,11 +655,6 @@ void WebEngineContext::destroy() if (m_devtoolsServer) m_devtoolsServer->stop(); -#if QT_CONFIG(webengine_webrtc) && QT_CONFIG(webengine_extensions) - if (m_webrtcLogUploader) - m_webrtcLogUploader->Shutdown(); -#endif - // Normally the GPU thread is shut down when the GpuProcessHost is destroyed // on IO thread (triggered by ~BrowserMainRunner). But by that time the UI // task runner is not working anymore so we need to do this earlier. @@ -709,10 +702,6 @@ void WebEngineContext::destroy() // Drop the false reference. m_handle->Release(); - -#if QT_CONFIG(webengine_webrtc) && QT_CONFIG(webengine_extensions) - m_webrtcLogUploader.reset(); -#endif } WebEngineContext::~WebEngineContext() @@ -836,7 +825,7 @@ static void initializeFeatureList(base::CommandLine *commandLine, std::vector<st commandLine->AppendSwitchASCII(switches::kEnableFeatures, enableFeaturesString); commandLine->AppendSwitchASCII(switches::kDisableFeatures, disableFeaturesString); - base::FeatureList::InitializeInstance(enableFeaturesString, disableFeaturesString); + base::FeatureList::InitInstance(enableFeaturesString, disableFeaturesString); } WebEngineContext::WebEngineContext() @@ -902,9 +891,6 @@ WebEngineContext::WebEngineContext() enableFeatures.push_back(features::kNetworkServiceInProcess.name); enableFeatures.push_back(features::kTracingServiceInProcess.name); - // When enabled, event.movement is calculated in blink instead of in browser. - disableFeatures.push_back(features::kConsolidatedMovementXY.name); - // Avoid crashing when websites tries using this feature (since 83) disableFeatures.push_back(features::kInstalledApp.name); @@ -970,6 +956,10 @@ WebEngineContext::WebEngineContext() parsedCommandLine->AppendSwitchASCII(switches::kUseAdapterLuid, luid.toStdString()); } #endif + // We need the FieldTrialList to make sure Chromium features are provided to child processes + if (!base::FieldTrialList::GetInstance()) { + m_fieldTrialList.reset(new base::FieldTrialList()); + } initializeFeatureList(parsedCommandLine, enableFeatures, disableFeatures); @@ -1107,16 +1097,6 @@ printing::PrintJobManager* WebEngineContext::getPrintJobManager() } #endif -#if QT_CONFIG(webengine_webrtc) && QT_CONFIG(webengine_extensions) -WebRtcLogUploader *WebEngineContext::webRtcLogUploader() -{ - if (!m_webrtcLogUploader) - m_webrtcLogUploader = std::make_unique<WebRtcLogUploader>(); - return m_webrtcLogUploader.get(); -} -#endif - - base::CommandLine *WebEngineContext::initCommandLine(bool &useEmbeddedSwitches, bool &enableGLSoftwareRendering) { @@ -1216,7 +1196,7 @@ const char *qWebEngineChromiumVersion() noexcept const char *qWebEngineChromiumSecurityPatchVersion() noexcept { - return "122.0.6261.128"; // FIXME: Remember to update + return "124.0.6367.202"; // FIXME: Remember to update } QT_END_NAMESPACE diff --git a/src/core/web_engine_context.h b/src/core/web_engine_context.h index 50b080db1..7a36fd001 100644 --- a/src/core/web_engine_context.h +++ b/src/core/web_engine_context.h @@ -16,6 +16,7 @@ namespace base { class RunLoop; class CommandLine; +class FieldTrialList; } namespace content { @@ -47,7 +48,6 @@ struct SandboxInterfaceInfo; #endif QT_FORWARD_DECLARE_CLASS(QObject) -class WebRtcLogUploader; namespace QtWebEngineCore { @@ -74,9 +74,6 @@ public: #if QT_CONFIG(webengine_printing_and_pdf) printing::PrintJobManager* getPrintJobManager(); #endif -#if QT_CONFIG(webengine_webrtc) && QT_CONFIG(webengine_extensions) - WebRtcLogUploader *webRtcLogUploader(); -#endif void destroyProfileAdapter(); void addProfileAdapter(ProfileAdapter *profileAdapter); void removeProfileAdapter(ProfileAdapter *profileAdapter); @@ -102,6 +99,7 @@ private: std::unique_ptr<ProfileAdapter> m_defaultProfileAdapter; std::unique_ptr<DevToolsServerQt> m_devtoolsServer; QList<ProfileAdapter*> m_profileAdapters; + std::unique_ptr<base::FieldTrialList> m_fieldTrialList; #if QT_CONFIG(accessibility) std::unique_ptr<AccessibilityActivationObserver> m_accessibilityActivationObserver; #endif @@ -109,9 +107,6 @@ private: #if QT_CONFIG(webengine_printing_and_pdf) std::unique_ptr<printing::PrintJobManager> m_printJobManager; #endif -#if QT_CONFIG(webengine_webrtc) && QT_CONFIG(webengine_extensions) - std::unique_ptr<WebRtcLogUploader> m_webrtcLogUploader; -#endif static scoped_refptr<QtWebEngineCore::WebEngineContext> m_handle; static bool m_destroyed; static bool m_closingDown; diff --git a/src/pdf/CMakeLists.txt b/src/pdf/CMakeLists.txt index 4a54b816e..41018e7da 100644 --- a/src/pdf/CMakeLists.txt +++ b/src/pdf/CMakeLists.txt @@ -38,7 +38,6 @@ qt_internal_add_module(Pdf PUBLIC_LIBRARIES Qt::Core Qt::Gui - GENERATE_CPP_EXPORTS ) add_subdirectory(plugins/imageformats/pdf) diff --git a/src/pdfquick/qquickpdfpageimage.cpp b/src/pdfquick/qquickpdfpageimage.cpp index f2da067f1..9ff0337a5 100644 --- a/src/pdfquick/qquickpdfpageimage.cpp +++ b/src/pdfquick/qquickpdfpageimage.cpp @@ -42,7 +42,7 @@ QQuickPdfPageImage::~QQuickPdfPageImage() { Q_D(QQuickPdfPageImage); // cancel any async rendering job that is running on my behalf - d->pix.clear(); + d->pendingPix->clear(); } /*! @@ -97,21 +97,23 @@ void QQuickPdfPageImage::load() thisRequestFinished = QQuickImageBase::staticMetaObject.indexOfSlot("requestFinished()"); } + static QMetaMethod requestFinishedSlot = staticMetaObject.method(thisRequestFinished); - d->pix.loadImageFromDevice(qmlEngine(this), carrierFile, url, + d->pendingPix->loadImageFromDevice(qmlEngine(this), carrierFile, url, d->sourceClipRect.toRect(), d->sourcesize * d->devicePixelRatio, QQuickImageProviderOptions(), d->currentFrame, d->frameCount); qCDebug(qLcImg) << "loading page" << d->currentFrame << "of" << d->frameCount - << "from" << carrierFile->fileName() << "status" << d->pix.status(); + << "from" << carrierFile->fileName() << "status" << d->pendingPix->status(); - switch (d->pix.status()) { + switch (d->pendingPix->status()) { case QQuickPixmap::Ready: + requestFinishedSlot.invoke(this); pixmapChange(); break; case QQuickPixmap::Loading: - d->pix.connectFinished(this, thisRequestFinished); - d->pix.connectDownloadProgress(this, thisRequestProgress); + d->pendingPix->connectFinished(this, thisRequestFinished); + d->pendingPix->connectDownloadProgress(this, thisRequestProgress); if (d->progress != 0.0) { d->progress = 0.0; emit progressChanged(d->progress); @@ -122,7 +124,7 @@ void QQuickPdfPageImage::load() } break; default: - qCDebug(qLcImg) << "unexpected status" << d->pix.status(); + qCDebug(qLcImg) << "unexpected status" << d->pendingPix->status(); break; } } diff --git a/src/pdfquick/qquickpdfselection.cpp b/src/pdfquick/qquickpdfselection.cpp index 4776cb8b4..5a9aa0025 100644 --- a/src/pdfquick/qquickpdfselection.cpp +++ b/src/pdfquick/qquickpdfselection.cpp @@ -470,9 +470,10 @@ void QQuickPdfSelection::setHold(bool hold) } /*! - \qmlproperty string PdfSelection::string + \qmlproperty string PdfSelection::text - The string found. + The text that was found in the rectangular area between \l from and \l to, + or all text on the \l page if selectAll() was called. */ QString QQuickPdfSelection::text() const { @@ -483,7 +484,7 @@ QString QQuickPdfSelection::text() const /*! \qmlmethod void PdfSelection::copyToClipboard() - Copies plain text from the \l string property to the system clipboard. + Copies plain text from the \l text property to the system clipboard. */ void QQuickPdfSelection::copyToClipboard() const { diff --git a/src/webenginequick/api/qquickwebengineforeigntypes_p.h b/src/webenginequick/api/qquickwebengineforeigntypes_p.h index 2d205254e..58dee066f 100644 --- a/src/webenginequick/api/qquickwebengineforeigntypes_p.h +++ b/src/webenginequick/api/qquickwebengineforeigntypes_p.h @@ -32,6 +32,7 @@ #include <QtWebEngineCore/qwebengineregisterprotocolhandlerrequest.h> #include <QtWebEngineCore/qwebenginefilesystemaccessrequest.h> #include <QtWebEngineCore/qwebenginewebauthuxrequest.h> +#include <QtWebEngineCore/qwebenginepermission.h> QT_BEGIN_NAMESPACE @@ -231,6 +232,39 @@ struct ForeignWebEngineWebAuthUxRequest QML_UNCREATABLE("") }; +struct ForeginWebEngineWebAuthPinRequest +{ + Q_GADGET + QML_FOREIGN(QWebEngineWebAuthPinRequest) + QML_NAMED_ELEMENT(WebEngineWebAuthPinRequest) + QML_ADDED_IN_VERSION(6, 8) + QML_UNCREATABLE("") +}; + +// To prevent the same type from being exported twice into qmltypes +// (for value type and for the enums) +class QWebEnginePermissionDerived : public QWebEnginePermission +{ + Q_GADGET +}; + +namespace ForeignWebEnginePermissionNamespace +{ + Q_NAMESPACE + QML_FOREIGN_NAMESPACE(QWebEnginePermissionDerived) + QML_NAMED_ELEMENT(WebEnginePermission) + QML_ADDED_IN_VERSION(6, 8) +} + +struct ForeignWebEnginePermission +{ + Q_GADGET + QML_FOREIGN(QWebEnginePermission) + QML_VALUE_TYPE(webEnginePermission) + QML_ADDED_IN_VERSION(6, 8) + QML_UNCREATABLE("") +}; + QT_END_NAMESPACE #endif // QQUICKWEBENGINEFOREIGNTYPES_H diff --git a/src/webenginequick/api/qquickwebengineprofile.cpp b/src/webenginequick/api/qquickwebengineprofile.cpp index edca5e99c..0246eb645 100644 --- a/src/webenginequick/api/qquickwebengineprofile.cpp +++ b/src/webenginequick/api/qquickwebengineprofile.cpp @@ -19,6 +19,7 @@ #include <QtWebEngineCore/qwebenginenotification.h> #include <QtWebEngineCore/private/qwebenginedownloadrequest_p.h> #include <QtWebEngineCore/qwebengineurlscheme.h> +#include <QtWebEngineCore/private/qwebenginepermission_p.h> #include <QtCore/qdir.h> #include <QtCore/qfileinfo.h> @@ -95,6 +96,28 @@ QT_BEGIN_NAMESPACE */ /*! + \enum QQuickWebEngineProfile::PersistentPermissionsPolicy + + \since 6.8 + + This enum describes the policy for permission persistence: + + \value NoPersistentPermissions + The application will ask for permissions every time they're needed, regardless of + whether they've been granted before or not. This is intended for backwards compatibility + with existing applications, and otherwise not recommended. + \value PersistentPermissionsInMemory + A request will be made only the first time a permission is needed. Any subsequent + requests will be automatically granted or denied, depending on the initial user choice. + This carries over to all pages that use the same QQuickWebEngineProfile instance, until the + application is shut down. This is the setting applied if \c off-the-record is set + or no persistent data path is available. + \value PersistentPermissionsOnDisk + Works the same way as \c PersistentPermissionsInMemory, but the permissions are saved to + and restored from disk. This is the default setting. +*/ + +/*! \fn QQuickWebEngineProfile::downloadRequested(QQuickWebEngineDownloadRequest *download) This signal is emitted whenever a download has been triggered. @@ -342,7 +365,7 @@ QQuickWebEngineScriptCollection *QQuickWebEngineProfilePrivate::getUserScripts() whether a profile is off-the-record. Each web engine view has an associated profile. Views that do not have a specific profile set - share a common default one. + share a common one, which is off-the-record by default. */ /*! @@ -381,7 +404,12 @@ QQuickWebEngineScriptCollection *QQuickWebEngineProfilePrivate::getUserScripts() */ /*! - Constructs a new profile with the parent \a parent. + Constructs a new off-the-record profile with the parent \a parent. + + An off-the-record profile leaves no record on the local machine, and has no + persistent data or cache. Thus, the HTTP cache can only be in memory and the + cookies can only be non-persistent. Trying to change these settings will + have no effect. */ QQuickWebEngineProfile::QQuickWebEngineProfile(QObject *parent) : QObject(parent), @@ -435,15 +463,18 @@ void QQuickWebEngineProfile::setStorageName(const QString &name) if (d->profileAdapter()->storageName() == name) return; ProfileAdapter::HttpCacheType oldCacheType = d->profileAdapter()->httpCacheType(); - ProfileAdapter::PersistentCookiesPolicy oldPolicy = d->profileAdapter()->persistentCookiesPolicy(); + ProfileAdapter::PersistentCookiesPolicy oldCookiePolicy = d->profileAdapter()->persistentCookiesPolicy(); + ProfileAdapter::PersistentPermissionsPolicy oldPermissionsPolicy = d->profileAdapter()->persistentPermissionsPolicy(); d->profileAdapter()->setStorageName(name); emit storageNameChanged(); emit persistentStoragePathChanged(); emit cachePathChanged(); if (d->profileAdapter()->httpCacheType() != oldCacheType) emit httpCacheTypeChanged(); - if (d->profileAdapter()->persistentCookiesPolicy() != oldPolicy) + if (d->profileAdapter()->persistentCookiesPolicy() != oldCookiePolicy) emit persistentCookiesPolicyChanged(); + if (d->profileAdapter()->persistentPermissionsPolicy() != oldPermissionsPolicy) + emit persistentPermissionsPolicyChanged(); } /*! @@ -452,6 +483,11 @@ void QQuickWebEngineProfile::setStorageName(const QString &name) Whether the web engine profile is \e off-the-record. An off-the-record profile forces cookies, the HTTP cache, and other normally persistent data to be stored only in memory. Profile is off-the-record by default. + + Changing a profile from \e off-the-record to disk-based behavior also requires setting a + proper storageName. + + \sa storageName() */ @@ -461,6 +497,11 @@ void QQuickWebEngineProfile::setStorageName(const QString &name) Whether the web engine profile is \e off-the-record. An off-the-record profile forces cookies, the HTTP cache, and other normally persistent data to be stored only in memory. Profile is off-the-record by default. + + Changing a profile from \e off-the-record to disk-based behavior also requires setting a + proper storageName. + + \sa setStorageName() */ bool QQuickWebEngineProfile::isOffTheRecord() const @@ -475,13 +516,16 @@ void QQuickWebEngineProfile::setOffTheRecord(bool offTheRecord) if (d->profileAdapter()->isOffTheRecord() == offTheRecord) return; ProfileAdapter::HttpCacheType oldCacheType = d->profileAdapter()->httpCacheType(); - ProfileAdapter::PersistentCookiesPolicy oldPolicy = d->profileAdapter()->persistentCookiesPolicy(); + ProfileAdapter::PersistentCookiesPolicy oldCookiePolicy = d->profileAdapter()->persistentCookiesPolicy(); + ProfileAdapter::PersistentPermissionsPolicy oldPermissionsPolicy = d->profileAdapter()->persistentPermissionsPolicy(); d->profileAdapter()->setOffTheRecord(offTheRecord); emit offTheRecordChanged(); if (d->profileAdapter()->httpCacheType() != oldCacheType) emit httpCacheTypeChanged(); - if (d->profileAdapter()->persistentCookiesPolicy() != oldPolicy) + if (d->profileAdapter()->persistentCookiesPolicy() != oldCookiePolicy) emit persistentCookiesPolicyChanged(); + if (d->profileAdapter()->persistentPermissionsPolicy() != oldPermissionsPolicy) + emit persistentPermissionsPolicyChanged(); } /*! @@ -628,7 +672,7 @@ void QQuickWebEngineProfile::setHttpCacheType(QQuickWebEngineProfile::HttpCacheT /*! \qmlproperty enumeration WebEngineProfile::persistentCookiesPolicy - This enumeration describes the policy of cookie persistency: + This enumeration describes the policy of cookie persistence: \value WebEngineProfile.NoPersistentCookies Both session and persistent cookies are stored in memory. This is the only setting @@ -664,6 +708,51 @@ void QQuickWebEngineProfile::setPersistentCookiesPolicy(QQuickWebEngineProfile:: } /*! + \qmlproperty enumeration WebEngineProfile::persistentPermissionsPolicy + + \since 6.8 + + This enumeration describes the policy for permission persistence: + + \value WebEngineProfile.NoPersistentPermissions + The application will ask for permissions every time they're needed, regardless of + whether they've been granted before or not. This is intended for backwards compatibility + with existing applications, and otherwise not recommended. + \value WebEngineProfile.PersistentPermissionsInMemory + A request will be made only the first time a permission is needed. Any subsequent + requests will be automatically granted or denied, depending on the initial user choice. + This carries over to all pages using the same QWebEngineProfile instance, until the + application is shut down. This is the setting applied if \c off-the-record is set + or no persistent data path is available. + \value WebEngineProfile.PersistentPermissionsOnDisk + Works the same way as \c PersistentPermissionsInMemory, but the permissions are saved to + and restored from disk. This is the default setting. +*/ + +/*! + \property QQuickWebEngineProfile::persistentPermissionsPolicy + \since 6.8 + + Describes the policy of permission persistence. + If the profile is off-the-record, NoPersistentCookies is returned. +*/ + +QQuickWebEngineProfile::PersistentPermissionsPolicy QQuickWebEngineProfile::persistentPermissionsPolicy() const +{ + Q_D(const QQuickWebEngineProfile); + return QQuickWebEngineProfile::PersistentPermissionsPolicy(d->profileAdapter()->persistentPermissionsPolicy()); +} + +void QQuickWebEngineProfile::setPersistentPermissionsPolicy(QQuickWebEngineProfile::PersistentPermissionsPolicy newPersistentPermissionsPolicy) +{ + Q_D(QQuickWebEngineProfile); + ProfileAdapter::PersistentPermissionsPolicy oldPolicy = d->profileAdapter()->persistentPermissionsPolicy(); + d->profileAdapter()->setPersistentPermissionsPolicy(ProfileAdapter::PersistentPermissionsPolicy(newPersistentPermissionsPolicy)); + if (d->profileAdapter()->persistentPermissionsPolicy() != oldPolicy) + emit persistentPermissionsPolicyChanged(); +} + +/*! \qmlproperty int WebEngineProfile::httpCacheMaximumSize The maximum size of the HTTP cache. If \c 0, the size will be controlled automatically by @@ -1040,6 +1129,147 @@ QWebEngineClientHints *QQuickWebEngineProfile::clientHints() const return d->m_clientHints.data(); } +/*! + \fn QQuickWebEngineProfile::getPermission(const QUrl &securityOrigin, QWebEnginePermission::Feature feature) const + + Returns a QWebEnginePermission object corresponding to a single permission for the provided \a securityOrigin and + \a feature. The object may be used to query for the current state of the permission, or to change it. It is not required + for a permission to already exist; the returned object may also be used to pre-grant a permission if a website is + known to use it. + + \note This may only be used for permanent feature types. Calling it with a transient \a feature will return an invalid object. + \since 6.8 + \sa listPermissions(), QWebEnginePermission::Feature + */ + +/*! + \qmlmethod void WebEngineProfile::getPermission(url securityOrigin, WebEnginePermission.Feature feature) const + + Returns a webEnginePermission object corresponding to a single permission for the provided \a securityOrigin and + \a feature. The object may be used to query for the current state of the permission, or to change it. It is not required + for a permission to already exist; the returned object may also be used to pre-grant a permission if a website is + known to use it. + + \note This may only be used for permanent feature types. Calling it with a transient \a feature will return an invalid object. + \since 6.8 + \sa listPermissions() + */ +QWebEnginePermission QQuickWebEngineProfile::getPermission(const QUrl &securityOrigin, QWebEnginePermission::Feature feature) const +{ + Q_D(const QQuickWebEngineProfile); + + if (feature == QWebEnginePermission::Unsupported) { + qWarning("Attempting to get unsupported permission. Returned object will be in an invalid state."); + return QWebEnginePermission(new QWebEnginePermissionPrivate()); + } + + if (QWebEnginePermission::isTransient(feature)) { + qWarning() << "Attempting to get permission for feature" << feature << ". Returned object will be in an invalid state."; + return QWebEnginePermission(new QWebEnginePermissionPrivate()); + } + + auto *pvt = new QWebEnginePermissionPrivate(securityOrigin, feature, nullptr, d->profileAdapter()); + return QWebEnginePermission(pvt); +} + +/*! + \qmlmethod list<webEnginePermission> WebEngineProfile::listPermissions() const + + Returns a \l list of webEnginePermission objects, each one representing a single permission currently + present in the permissions store. The returned list contains all previously granted/denied permissions for this profile, + except for those of a transient feature type. + + \since 6.8 + \sa getPermission() + */ + +/*! + Returns a QList of QWebEnginePermission objects, each one representing a single permission currently + present in the permissions store. The returned list contains all previously granted/denied permissions for this profile, + except for those of a transient feature type. + + \since 6.8 + \sa getPermission() + */ +QList<QWebEnginePermission> QQuickWebEngineProfile::listPermissions() const +{ + Q_D(const QQuickWebEngineProfile); + if (persistentPermissionsPolicy() == NoPersistentPermissions) + return QList<QWebEnginePermission>(); + return d->profileAdapter()->listPermissions(); +} + +/*! + \qmlmethod list<webEnginePermission> WebEngineProfile::listPermissions(url securityOrigin) const + + Returns a \l list of webEnginePermission objects, each one representing a single permission currently + present in the permissions store. The returned list contains all previously granted/denied permissions associated with a + specific \a securityOrigin for this profile, except for those of a transient feature type. + + \note Since permissions are granted on a per-origin basis, the provided \a securityOrigin will be stripped to its + origin form, and the returned list will contain all permissions for the origin. Thus, passing https://www.example.com/some/page.html + is the same as passing just https://www.example.com/. + \since 6.8 + \sa getPermission() + */ + +/*! + Returns a QList of QWebEnginePermission objects, each one representing a single permission currently + present in the permissions store. The returned list contains all previously granted/denied permissions associated with a + specific \a securityOrigin for this profile, except for those of a transient feature type. + + \note Since permissions are granted on a per-origin basis, the provided \a securityOrigin will be stripped to its + origin form, and the returned list will contain all permissions for the origin. Thus, passing https://www.example.com/some/page.html + is the same as passing just https://www.example.com/. + \since 6.8 + \sa getPermission() + */ +QList<QWebEnginePermission> QQuickWebEngineProfile::listPermissions(const QUrl &securityOrigin) const +{ + Q_D(const QQuickWebEngineProfile); + if (persistentPermissionsPolicy() == NoPersistentPermissions) + return QList<QWebEnginePermission>(); + return d->profileAdapter()->listPermissions(securityOrigin); +} + +/*! + \qmlmethod list<webEnginePermission> WebEngineProfile::listPermissions(WebEnginePermission.Feature feature) const + + Returns a \l list of webEnginePermission objects, each one representing a single permission currently + present in the permissions store. The returned list contains all previously granted/denied permissions of the \a feature + type for this profile. If the feature is of a transient or unsupported type, the list will be empty. + + \since 6.8 + \sa getPermission() + */ + +/*! + Returns a QList of QWebEnginePermission objects, each one representing a single permission currently + present in the permissions store. The returned list contains all previously granted/denied permissions of the \a feature + type for this profile. If the feature is of a transient or unsupported type, the list will be empty. + + \since 6.8 + \sa getPermission(), QWebEnginePermission::Feature + */ +QList<QWebEnginePermission> QQuickWebEngineProfile::listPermissions(QWebEnginePermission::Feature feature) const +{ + Q_D(const QQuickWebEngineProfile); + if (persistentPermissionsPolicy() == NoPersistentPermissions) + return QList<QWebEnginePermission>(); + + if (feature == QWebEnginePermission::Unsupported) { + qWarning("Attempting to get permission list for an unsupported type. Returned list will be empty."); + return QList<QWebEnginePermission>(); + } + + if (QWebEnginePermission::isTransient(feature)) { + qWarning() << "Attempting to get permission list for feature" << feature << ". Returned list will be empty."; + return QList<QWebEnginePermission>(); + } + + return d->profileAdapter()->listPermissions(QUrl(), feature); +} + void QQuickWebEngineProfile::ensureQmlContext(const QObject *object) { if (!qmlContext(this)) { diff --git a/src/webenginequick/api/qquickwebengineprofile.h b/src/webenginequick/api/qquickwebengineprofile.h index cbeb91147..186a11d7b 100644 --- a/src/webenginequick/api/qquickwebengineprofile.h +++ b/src/webenginequick/api/qquickwebengineprofile.h @@ -5,6 +5,7 @@ #define QQUICKWEBENGINEPROFILE_H #include <QtWebEngineQuick/qtwebenginequickglobal.h> +#include <QtWebEngineCore/qwebenginepermission.h> #include <QtCore/qobject.h> #include <QtCore/qscopedpointer.h> #include <QtCore/qstring.h> @@ -33,6 +34,7 @@ class Q_WEBENGINEQUICK_EXPORT QQuickWebEngineProfile : public QObject { Q_PROPERTY(HttpCacheType httpCacheType READ httpCacheType WRITE setHttpCacheType NOTIFY httpCacheTypeChanged FINAL) Q_PROPERTY(QString httpAcceptLanguage READ httpAcceptLanguage WRITE setHttpAcceptLanguage NOTIFY httpAcceptLanguageChanged FINAL REVISION(1,1)) Q_PROPERTY(PersistentCookiesPolicy persistentCookiesPolicy READ persistentCookiesPolicy WRITE setPersistentCookiesPolicy NOTIFY persistentCookiesPolicyChanged FINAL) + Q_PROPERTY(PersistentPermissionsPolicy persistentPermissionsPolicy READ persistentPermissionsPolicy WRITE setPersistentPermissionsPolicy NOTIFY persistentPermissionsPolicyChanged FINAL) Q_PROPERTY(int httpCacheMaximumSize READ httpCacheMaximumSize WRITE setHttpCacheMaximumSize NOTIFY httpCacheMaximumSizeChanged FINAL) Q_PROPERTY(QStringList spellCheckLanguages READ spellCheckLanguages WRITE setSpellCheckLanguages NOTIFY spellCheckLanguagesChanged FINAL REVISION(1,3)) Q_PROPERTY(bool spellCheckEnabled READ isSpellCheckEnabled WRITE setSpellCheckEnabled NOTIFY spellCheckEnabledChanged FINAL REVISION(1,3)) @@ -61,6 +63,13 @@ public: }; Q_ENUM(PersistentCookiesPolicy) + enum PersistentPermissionsPolicy : quint8 { + NoPersistentPermissions, + PersistentPermissionsInMemory, + PersistentPermissionsOnDisk, + }; + Q_ENUM(PersistentPermissionsPolicy) + QString storageName() const; void setStorageName(const QString &name); @@ -82,6 +91,9 @@ public: PersistentCookiesPolicy persistentCookiesPolicy() const; void setPersistentCookiesPolicy(QQuickWebEngineProfile::PersistentCookiesPolicy); + PersistentPermissionsPolicy persistentPermissionsPolicy() const; + void setPersistentPermissionsPolicy(QQuickWebEngineProfile::PersistentPermissionsPolicy); + int httpCacheMaximumSize() const; void setHttpCacheMaximumSize(int maxSize); @@ -116,6 +128,11 @@ public: QWebEngineClientCertificateStore *clientCertificateStore(); QWebEngineClientHints *clientHints() const; + Q_REVISION(6,8) Q_INVOKABLE QWebEnginePermission getPermission(const QUrl &securityOrigin, QWebEnginePermission::Feature feature) const; + Q_REVISION(6,8) Q_INVOKABLE QList<QWebEnginePermission> listPermissions() const; + Q_REVISION(6,8) Q_INVOKABLE QList<QWebEnginePermission> listPermissions(const QUrl &securityOrigin) const; + Q_REVISION(6,8) Q_INVOKABLE QList<QWebEnginePermission> listPermissions(QWebEnginePermission::Feature feature) const; + static QQuickWebEngineProfile *defaultProfile(); Q_SIGNALS: @@ -133,6 +150,7 @@ Q_SIGNALS: Q_REVISION(1,5) void downloadPathChanged(); Q_REVISION(6,5) void pushServiceEnabledChanged(); Q_REVISION(6,7) void clearHttpCacheCompleted(); + Q_REVISION(6,8) void persistentPermissionsPolicyChanged(); void downloadRequested(QQuickWebEngineDownloadRequest *download); void downloadFinished(QQuickWebEngineDownloadRequest *download); diff --git a/src/webenginequick/api/qquickwebenginesettings.cpp b/src/webenginequick/api/qquickwebenginesettings.cpp index 31ed7a661..5dc093a44 100644 --- a/src/webenginequick/api/qquickwebenginesettings.cpp +++ b/src/webenginequick/api/qquickwebenginesettings.cpp @@ -79,7 +79,7 @@ bool QQuickWebEngineSettings::javascriptCanOpenWindows() const Since unrestricted clipboard access is a potential security concern, it is recommended that applications leave this disabled and instead respond to - \l{WebEngineView::ClipboardReadWrite}{ClipboardReadWrite} feature permission requests. + \l{WebEnginePermission::ClipboardReadWrite}{ClipboardReadWrite} feature permission requests. Disabled by default. */ @@ -389,7 +389,7 @@ bool QQuickWebEngineSettings::webRTCPublicInterfacesOnly() const Since unrestricted clipboard access is a potential security concern, it is recommended that applications leave this disabled and instead respond to - \l{WebEngineView::ClipboardReadWrite}{ClipboardReadWrite} feature permission requests. + \l{WebEnginePermission::ClipboardReadWrite}{ClipboardReadWrite} feature permission requests. Disabled by default. */ diff --git a/src/webenginequick/api/qquickwebengineview.cpp b/src/webenginequick/api/qquickwebengineview.cpp index 11ed33b5e..852d00c76 100644 --- a/src/webenginequick/api/qquickwebengineview.cpp +++ b/src/webenginequick/api/qquickwebengineview.cpp @@ -41,6 +41,7 @@ #include <QtWebEngineCore/qwebengineregisterprotocolhandlerrequest.h> #include <QtWebEngineCore/qwebenginescriptcollection.h> #include <QtWebEngineCore/qwebenginewebauthuxrequest.h> +#include <QtWebEngineCore/qwebenginepermission.h> #include <QtWebEngineCore/private/qwebenginecontextmenurequest_p.h> #include <QtWebEngineCore/private/qwebenginedesktopmediarequest_p.h> #include <QtWebEngineCore/private/qwebenginehistory_p.h> @@ -48,6 +49,7 @@ #include <QtWebEngineCore/private/qwebenginescriptcollection_p.h> #include <QtWebEngineCore/private/qwebenginepage_p.h> #include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h> +#include <QtWebEngineCore/private/qwebenginepermission_p.h> #include <QtCore/qloggingcategory.h> #include <QtCore/qmimedata.h> @@ -484,29 +486,67 @@ void QQuickWebEngineViewPrivate::selectClientCert( Q_EMIT q->selectClientCertificate(certSelection); } -static QQuickWebEngineView::Feature toFeature(QtWebEngineCore::ProfileAdapter::PermissionType type) +#if QT_DEPRECATED_SINCE(6, 8) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED +static QQuickWebEngineView::Feature toDeprecatedFeature(QWebEnginePermission::Feature feature) { - switch (type) { - case QtWebEngineCore::ProfileAdapter::NotificationPermission: + switch (feature) { + case QWebEnginePermission::Feature::Notifications: return QQuickWebEngineView::Notifications; - case QtWebEngineCore::ProfileAdapter::GeolocationPermission: + case QWebEnginePermission::Feature::Geolocation: return QQuickWebEngineView::Geolocation; - case QtWebEngineCore::ProfileAdapter::ClipboardReadWrite: + case QWebEnginePermission::Feature::ClipboardReadWrite: return QQuickWebEngineView::ClipboardReadWrite; - case QtWebEngineCore::ProfileAdapter::LocalFontsPermission: + case QWebEnginePermission::Feature::LocalFontsAccess: return QQuickWebEngineView::LocalFontsAccess; - default: + case QWebEnginePermission::Feature::MediaAudioCapture: + return QQuickWebEngineView::MediaAudioCapture; + case QWebEnginePermission::Feature::MediaVideoCapture: + return QQuickWebEngineView::MediaVideoCapture; + case QWebEnginePermission::Feature::MediaAudioVideoCapture: + return QQuickWebEngineView::MediaAudioVideoCapture; + case QWebEnginePermission::Feature::DesktopVideoCapture: + return QQuickWebEngineView::DesktopVideoCapture; + case QWebEnginePermission::Feature::DesktopAudioVideoCapture: + return QQuickWebEngineView::DesktopAudioVideoCapture; + case QWebEnginePermission::Feature::MouseLock: + case QWebEnginePermission::Feature::Unsupported: break; } + Q_UNREACHABLE(); return QQuickWebEngineView::Feature(-1); } +QT_WARNING_POP +#endif // QT_DEPRECATED_SINCE(6, 8) - -void QQuickWebEngineViewPrivate::runFeaturePermissionRequest(QtWebEngineCore::ProfileAdapter::PermissionType permission, const QUrl &url) +void QQuickWebEngineViewPrivate::runFeaturePermissionRequest(QWebEnginePermission::Feature feature, const QUrl &url) { Q_Q(QQuickWebEngineView); - Q_EMIT q->featurePermissionRequested(url, toFeature(permission)); + switch (feature) { + case QWebEnginePermission::Notifications: + case QWebEnginePermission::Geolocation: + case QWebEnginePermission::ClipboardReadWrite: + case QWebEnginePermission::LocalFontsAccess: + Q_EMIT q->permissionRequested(createFeaturePermissionObject(url, feature)); +#if QT_DEPRECATED_SINCE(6, 8) + QT_WARNING_PUSH + QT_WARNING_DISABLE_DEPRECATED + Q_EMIT q->featurePermissionRequested(url, toDeprecatedFeature(feature)); + QT_WARNING_POP +#endif // QT_DEPRECATED_SINCE(6, 8) + return; + case QWebEnginePermission::MouseLock: + case QWebEnginePermission::MediaAudioCapture: + case QWebEnginePermission::MediaVideoCapture: + case QWebEnginePermission::MediaAudioVideoCapture: + case QWebEnginePermission::DesktopAudioVideoCapture: + case QWebEnginePermission::DesktopVideoCapture: + case QWebEnginePermission::Unsupported: + Q_UNREACHABLE(); + return; + } } void QQuickWebEngineViewPrivate::showColorDialog(QSharedPointer<ColorChooserController> controller) @@ -572,6 +612,12 @@ void QQuickWebEngineViewPrivate::iconChanged(const QUrl &url) QTimer::singleShot(0, q, &QQuickWebEngineView::iconChanged); } +void QQuickWebEngineViewPrivate::zoomFactorChanged(qreal factor) +{ + Q_Q(QQuickWebEngineView); + Q_EMIT q->zoomFactorChanged(factor); +} + void QQuickWebEngineViewPrivate::loadProgressChanged(int progress) { Q_Q(QQuickWebEngineView); @@ -778,19 +824,41 @@ void QQuickWebEngineViewPrivate::runMediaAccessPermissionRequest(const QUrl &sec Q_Q(QQuickWebEngineView); if (!requestFlags) return; - QQuickWebEngineView::Feature feature; + QWebEnginePermission::Feature feature; if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture) && requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture)) - feature = QQuickWebEngineView::MediaAudioVideoCapture; + feature = QWebEnginePermission::MediaAudioVideoCapture; else if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture)) - feature = QQuickWebEngineView::MediaAudioCapture; + feature = QWebEnginePermission::MediaAudioCapture; else if (requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture)) - feature = QQuickWebEngineView::MediaVideoCapture; + feature = QWebEnginePermission::MediaVideoCapture; else if (requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopAudioCapture) && requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture)) - feature = QQuickWebEngineView::DesktopAudioVideoCapture; + feature = QWebEnginePermission::DesktopAudioVideoCapture; else // if (requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture)) - feature = QQuickWebEngineView::DesktopVideoCapture; - Q_EMIT q->featurePermissionRequested(securityOrigin, feature); + feature = QWebEnginePermission::DesktopVideoCapture; + Q_EMIT q->permissionRequested(createFeaturePermissionObject(securityOrigin, feature)); + +#if QT_DEPRECATED_SINCE(6, 8) + QT_WARNING_PUSH + QT_WARNING_DISABLE_DEPRECATED + QQuickWebEngineView::Feature deprecatedFeature; + + if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture) + && requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture)) + deprecatedFeature = QQuickWebEngineView::MediaAudioVideoCapture; + else if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture)) + deprecatedFeature = QQuickWebEngineView::MediaAudioCapture; + else if (requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture)) + deprecatedFeature = QQuickWebEngineView::MediaVideoCapture; + else if (requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopAudioCapture) + && requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture)) + deprecatedFeature = QQuickWebEngineView::DesktopAudioVideoCapture; + else // if (requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture)) + deprecatedFeature = QQuickWebEngineView::DesktopVideoCapture; + + Q_EMIT q->featurePermissionRequested(securityOrigin, deprecatedFeature); + QT_WARNING_POP +#endif // QT_DEPRECATED_SINCE(6, 8) } void QQuickWebEngineViewPrivate::runMouseLockPermissionRequest(const QUrl &securityOrigin) @@ -836,6 +904,14 @@ void QQuickWebEngineViewPrivate::printRequested() }); } +void QQuickWebEngineViewPrivate::printRequestedByFrame(quint64 frameId) +{ + Q_Q(QQuickWebEngineView); + QTimer::singleShot(0, q, [this, q, frameId]() { + Q_EMIT q->printRequestedByFrame(QWebEngineFrame(this, frameId)); + }); +} + void QQuickWebEngineViewPrivate::findTextFinished(const QWebEngineFindTextResult &result) { Q_Q(QQuickWebEngineView); @@ -1225,7 +1301,6 @@ void QQuickWebEngineView::setZoomFactor(qreal arg) d->adapter->setZoomFactor(arg); // MEMO: should reset if factor was not applied due to being invalid d->m_zoomFactor = zoomFactor(); - emit zoomFactorChanged(d->m_zoomFactor); } else { d->m_zoomFactor = arg; } @@ -1296,22 +1371,26 @@ bool QQuickWebEngineView::activeFocusOnPress() const return d->m_activeFocusOnPress; } -void QQuickWebEngineViewPrivate::didRunJavaScript(quint64 requestId, const QVariant &result) +void QQuickWebEngineViewPrivate::runJavaScript( + const QString &script, quint32 worldId, quint64 frameId, + const std::function<void(const QVariant &)> &callback) { - Q_Q(QQuickWebEngineView); - QJSValue callback = m_callbacks.take(requestId); - QJSValueList args; - args.append(qmlEngine(q)->toScriptValue(result)); - callback.call(args); + ensureContentsAdapter(); + adapter->runJavaScript(script, worldId, frameId, callback); } -void QQuickWebEngineViewPrivate::didPrintPage(quint64 requestId, QSharedPointer<QByteArray> result) +void QQuickWebEngineViewPrivate::printToPdf(const QString &filePath, const QPageLayout &layout, + const QPageRanges &ranges, quint64 frameId) { - Q_Q(QQuickWebEngineView); - QJSValue callback = m_callbacks.take(requestId); - QJSValueList args; - args.append(qmlEngine(q)->toScriptValue(*(result.data()))); - callback.call(args); + adapter->printToPDF(layout, ranges, filePath, frameId); +} + +void QQuickWebEngineViewPrivate::printToPdf( + std::function<void(QSharedPointer<QByteArray>)> &&callback, const QPageLayout &layout, + const QPageRanges &ranges, quint64 frameId) +{ + adapter->printToPDFCallbackResult(std::move(callback), layout, ranges, /*colorMode*/ true, + /*useCustomMargins*/ true, frameId); } void QQuickWebEngineViewPrivate::didPrintPageToPdf(const QString &filePath, bool success) @@ -1449,6 +1528,12 @@ void QQuickWebEngineViewPrivate::showWebAuthDialog(QWebEngineWebAuthUxRequest *r Q_EMIT q->webAuthUxRequested(request); } +QWebEnginePermission QQuickWebEngineViewPrivate::createFeaturePermissionObject(const QUrl &securityOrigin, QWebEnginePermission::Feature feature) +{ + auto *returnPrivate = new QWebEnginePermissionPrivate(securityOrigin, feature, adapter, profileAdapter()); + return QWebEnginePermission(returnPrivate); +} + bool QQuickWebEngineView::isLoading() const { Q_D(const QQuickWebEngineView); @@ -1487,16 +1572,15 @@ void QQuickWebEngineView::runJavaScript(const QString &script, const QJSValue &c void QQuickWebEngineView::runJavaScript(const QString &script, quint32 worldId, const QJSValue &callback) { Q_D(QQuickWebEngineView); - d->ensureContentsAdapter(); + std::function<void(const QVariant &)> wrappedCallback; if (!callback.isUndefined()) { - quint64 requestId = d_ptr->adapter->runJavaScriptCallbackResult(script, worldId); - if (requestId) { - d->m_callbacks.insert(requestId, callback); - } else { - callback.call(); - } - } else - d->adapter->runJavaScript(script, worldId); + wrappedCallback = [this, callback](const QVariant &result) { + QJSValueList args; + args.append(qmlEngine(this)->toScriptValue(result)); + callback.call(args); + }; + } + d->runJavaScript(script, worldId, WebContentsAdapter::kUseMainFrameId, wrappedCallback); } qreal QQuickWebEngineView::zoomFactor() const @@ -1571,7 +1655,7 @@ void QQuickWebEngineView::printToPdf(const QString& filePath, PrintedPageSizeId QPageLayout pageLayout(layoutSize, layoutOrientation, QMarginsF(0.0, 0.0, 0.0, 0.0)); QPageRanges ranges; d->ensureContentsAdapter(); - d->adapter->printToPDF(pageLayout, ranges, filePath); + d->printToPdf(filePath, pageLayout, ranges, WebContentsAdapter::kUseMainFrameId); #else Q_UNUSED(filePath); Q_UNUSED(pageSizeId); @@ -1592,8 +1676,14 @@ void QQuickWebEngineView::printToPdf(const QJSValue &callback, PrintedPageSizeId return; d->ensureContentsAdapter(); - quint64 requestId = d->adapter->printToPDFCallbackResult(pageLayout, ranges); - d->m_callbacks.insert(requestId, callback); + std::function wrappedCallback = [this, callback](QSharedPointer<QByteArray> result) { + QJSValueList args; + args.append(qmlEngine(this)->toScriptValue(*result)); + callback.call(args); + }; + + d->printToPdf(std::move(wrappedCallback), pageLayout, ranges, + WebContentsAdapter::kUseMainFrameId); #else Q_UNUSED(pageSizeId); Q_UNUSED(orientation); @@ -1739,55 +1829,49 @@ void QQuickWebEngineView::setDevToolsView(QQuickWebEngineView *devToolsView) Q_EMIT devToolsViewChanged(); } +#if QT_DEPRECATED_SINCE(6, 8) +QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED void QQuickWebEngineView::grantFeaturePermission(const QUrl &securityOrigin, QQuickWebEngineView::Feature feature, bool granted) { - if (!granted && ((feature >= MediaAudioCapture && feature <= MediaAudioVideoCapture) || - (feature >= DesktopVideoCapture && feature <= DesktopAudioVideoCapture))) { - d_ptr->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaNone); - return; - } + Q_D(QQuickWebEngineView); + QWebEnginePermission::Feature f; switch (feature) { - case MediaAudioCapture: - d_ptr->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaAudioCapture); + case QQuickWebEngineView::Notifications: + f = QWebEnginePermission::Notifications; break; - case MediaVideoCapture: - d_ptr->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaVideoCapture); + case QQuickWebEngineView::Geolocation: + f = QWebEnginePermission::Geolocation; break; - case MediaAudioVideoCapture: - d_ptr->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaRequestFlags(WebContentsAdapterClient::MediaAudioCapture | WebContentsAdapterClient::MediaVideoCapture)); + case QQuickWebEngineView::MediaAudioCapture: + f = QWebEnginePermission::MediaAudioCapture; break; - case DesktopVideoCapture: - d_ptr->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaDesktopVideoCapture); + case QQuickWebEngineView::MediaVideoCapture: + f = QWebEnginePermission::MediaVideoCapture; break; - case DesktopAudioVideoCapture: - d_ptr->adapter->grantMediaAccessPermission( - securityOrigin, - WebContentsAdapterClient::MediaRequestFlags( - WebContentsAdapterClient::MediaDesktopAudioCapture | - WebContentsAdapterClient::MediaDesktopVideoCapture)); + case QQuickWebEngineView::MediaAudioVideoCapture: + f = QWebEnginePermission::MediaAudioVideoCapture; break; - case Geolocation: - d_ptr->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::GeolocationPermission, - granted ? ProfileAdapter::AllowedPermission : ProfileAdapter::DeniedPermission); + case QQuickWebEngineView::DesktopVideoCapture: + f = QWebEnginePermission::DesktopVideoCapture; break; - case Notifications: - d_ptr->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::NotificationPermission, - granted ? ProfileAdapter::AllowedPermission : ProfileAdapter::DeniedPermission); + case QQuickWebEngineView::DesktopAudioVideoCapture: + f = QWebEnginePermission::DesktopAudioVideoCapture; break; - case ClipboardReadWrite: - d_ptr->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::ClipboardReadWrite, - granted ? ProfileAdapter::AllowedPermission - : ProfileAdapter::DeniedPermission); + case QQuickWebEngineView::ClipboardReadWrite: + f = QWebEnginePermission::ClipboardReadWrite; break; - case LocalFontsAccess: - d_ptr->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::LocalFontsPermission, - granted ? ProfileAdapter::AllowedPermission : ProfileAdapter::DeniedPermission); + case QQuickWebEngineView::LocalFontsAccess: + f = QWebEnginePermission::LocalFontsAccess; break; default: Q_UNREACHABLE(); } + + d->adapter->setFeaturePermission(securityOrigin, f, granted ? QWebEnginePermission::Granted : QWebEnginePermission::Denied); } +QT_WARNING_POP +#endif // QT_DEPRECATED_SINCE(6, 8) void QQuickWebEngineView::setActiveFocusOnPress(bool arg) { diff --git a/src/webenginequick/api/qquickwebengineview_p.h b/src/webenginequick/api/qquickwebengineview_p.h index 37e39dfed..ea09dff9f 100644 --- a/src/webenginequick/api/qquickwebengineview_p.h +++ b/src/webenginequick/api/qquickwebengineview_p.h @@ -20,6 +20,7 @@ #include <QtWebEngineCore/qwebenginedesktopmediarequest.h> #include <QtWebEngineCore/qwebenginedownloadrequest.h> #include <QtWebEngineCore/qwebengineframe.h> +#include <QtWebEngineCore/qwebenginepermission.h> #include <QtWebEngineQuick/private/qtwebenginequickglobal_p.h> #include <QtGui/qcolor.h> #include <QtQml/qqmlregistration.h> @@ -166,8 +167,12 @@ QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED Q_ENUM(NewViewDestination) QT_WARNING_POP #endif - - enum Feature { +#if QT_DEPRECATED_SINCE(6, 8) +QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED + enum QT_DEPRECATED_VERSION_X_6_8( + "WebEnginePage::Feature has been deprecated. " + "The updated permissions API uses WebEnginePermission::Feature.") + Feature { MediaAudioCapture, MediaVideoCapture, MediaAudioVideoCapture, @@ -179,6 +184,8 @@ QT_WARNING_POP LocalFontsAccess, }; Q_ENUM(Feature) +QT_WARNING_POP +#endif enum WebAction { NoWebAction = - 1, @@ -489,7 +496,17 @@ public Q_SLOTS: void stop(); Q_REVISION(1,1) void findText(const QString &subString, FindFlags options = { }, const QJSValue &callback = QJSValue()); Q_REVISION(1,1) void fullScreenCancelled(); +#if QT_DEPRECATED_SINCE(6, 8) +#if !defined(Q_MOC_RUN) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED +#endif // !defined(Q_MOC_RUN) + QT_DEPRECATED_VERSION_X_6_8("Setting permissions through WebEngineView has been deprecated. Please use WebEnginePermission instead.") Q_REVISION(1,1) void grantFeaturePermission(const QUrl &securityOrigin, QQuickWebEngineView::Feature, bool granted); +#if !defined(Q_MOC_RUN) +QT_WARNING_POP +#endif // !defined(Q_MOC_RUN) +#endif // QT_DEPRECATED_SINCE(6, 8) Q_REVISION(1,2) void setActiveFocusOnPress(bool arg); Q_REVISION(1,2) void triggerWebAction(WebAction action); Q_REVISION(1,3) void printToPdf(const QString &filePath, PrintedPageSizeId pageSizeId = PrintedPageSizeId::A4, PrintedPageOrientation orientation = PrintedPageOrientation::Portrait); @@ -515,9 +532,19 @@ Q_SIGNALS: Q_REVISION(1,1) void certificateError(const QWebEngineCertificateError &error); Q_REVISION(1,1) void fullScreenRequested(const QWebEngineFullScreenRequest &request); Q_REVISION(1,1) void isFullScreenChanged(); +#if QT_DEPRECATED_SINCE(6, 8) +#if !defined(Q_MOC_RUN) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED +#endif // !defined(Q_MOC_RUN) + QT_MOC_COMPAT QT_DEPRECATED_VERSION_X_6_8("The signal has been deprecated; please use permissionRequested instead.") Q_REVISION(1, 1) void featurePermissionRequested(const QUrl &securityOrigin, QQuickWebEngineView::Feature feature); +#if !defined(Q_MOC_RUN) +QT_WARNING_POP +#endif // !defined(Q_MOC_RUN) +#endif // QT_DEPRECATED_SINCE(6, 8) Q_REVISION(1,1) void zoomFactorChanged(qreal arg); Q_REVISION(1,1) void profileChanged(); Q_REVISION(1,1) void webChannelChanged(); @@ -561,6 +588,8 @@ Q_SIGNALS: Q_REVISION(6,4) void fileSystemAccessRequested(const QWebEngineFileSystemAccessRequest &request); Q_REVISION(6, 7) void webAuthUxRequested(QWebEngineWebAuthUxRequest *request); Q_REVISION(6,7) void desktopMediaRequested(const QWebEngineDesktopMediaRequest &request); + Q_REVISION(6, 8) void printRequestedByFrame(QWebEngineFrame frame); + Q_REVISION(6,8) void permissionRequested(QWebEnginePermission permissionRequest); protected: void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; diff --git a/src/webenginequick/api/qquickwebengineview_p_p.h b/src/webenginequick/api/qquickwebengineview_p_p.h index cf4da7c40..e61f32bcb 100644 --- a/src/webenginequick/api/qquickwebengineview_p_p.h +++ b/src/webenginequick/api/qquickwebengineview_p_p.h @@ -64,6 +64,7 @@ public: void titleChanged(const QString&) override; void urlChanged() override; void iconChanged(const QUrl&) override; + void zoomFactorChanged(qreal factor) override; void loadProgressChanged(int progress) override; void didUpdateTargetURL(const QUrl&) override; void selectionChanged() override; @@ -92,10 +93,14 @@ public: void runFileChooser(QSharedPointer<QtWebEngineCore::FilePickerController>) override; void desktopMediaRequested(QtWebEngineCore::DesktopMediaController *) override; void showColorDialog(QSharedPointer<QtWebEngineCore::ColorChooserController>) override; - void didRunJavaScript(quint64, const QVariant&) override; + void runJavaScript(const QString &script, quint32 worldId, quint64 frameId, + const std::function<void(const QVariant &)> &callback) override; void didFetchDocumentMarkup(quint64, const QString&) override { } void didFetchDocumentInnerText(quint64, const QString&) override { } - void didPrintPage(quint64 requestId, QSharedPointer<QByteArray>) override; + void printToPdf(const QString &filePath, const QPageLayout &layout, const QPageRanges &ranges, + quint64 frameId) override; + void printToPdf(std::function<void(QSharedPointer<QByteArray>)> &&callback, + const QPageLayout &layout, const QPageRanges &ranges, quint64 frameId) override; void didPrintPageToPdf(const QString &filePath, bool success) override; bool passOnFocus(bool reverse) override; void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID) override; @@ -109,7 +114,7 @@ public: void allowCertificateError(const QWebEngineCertificateError &error) override; void selectClientCert(const QSharedPointer<QtWebEngineCore::ClientCertSelectController> &selectController) override; - void runFeaturePermissionRequest(QtWebEngineCore::ProfileAdapter::PermissionType permission, const QUrl &securityOrigin) override; + void runFeaturePermissionRequest(QWebEnginePermission::Feature feature, const QUrl &securityOrigin) override; void renderProcessTerminated(RenderProcessTerminationStatus terminationStatus, int exitCode) override; void requestGeometryChange(const QRect &geometry, const QRect &frameGeometry) override; void updateScrollPosition(const QPointF &position) override; @@ -128,11 +133,13 @@ public: QtWebEngineCore::ProfileAdapter *profileAdapter() override; QtWebEngineCore::WebContentsAdapter *webContentsAdapter() override; void printRequested() override; + void printRequestedByFrame(quint64 frameId) override; void findTextFinished(const QWebEngineFindTextResult &result) override; void showAutofillPopup(QtWebEngineCore::AutofillPopupController *controller, const QRect &bounds, bool autoselectFirstSuggestion) override; void hideAutofillPopup() override; void showWebAuthDialog(QWebEngineWebAuthUxRequest *request) override; + QWebEnginePermission createFeaturePermissionObject(const QUrl &securityOrigin, QWebEnginePermission::Feature feature) override; void updateAction(QQuickWebEngineView::WebAction) const; bool adoptWebContents(QtWebEngineCore::WebContentsAdapter *webContents); @@ -157,7 +164,6 @@ public: bool m_fullscreenMode; bool isLoading; bool m_activeFocusOnPress; - QMap<quint64, QJSValue> m_callbacks; QQmlWebChannel *m_webChannel; QPointer<QQuickWebEngineView> inspectedView; QPointer<QQuickWebEngineView> devToolsView; diff --git a/src/webenginequick/doc/src/webengine_permission.qdoc b/src/webenginequick/doc/src/webengine_permission.qdoc new file mode 100644 index 000000000..f59f57fa0 --- /dev/null +++ b/src/webenginequick/doc/src/webengine_permission.qdoc @@ -0,0 +1,137 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only + +/*! + \qmltype webEnginePermission + \instantiates QWebEnginePermission + \inqmlmodule QtWebEngine + \brief An object used to access and modify the state of a single permission that's been + granted or denied to a specific origin URL. + + The typical usage pattern is as follows: + \list 1 + \li A website requests a specific feature, triggering the WebEngineView::permissionRequested signal; + \li The signal handler triggers a prompt asking the user whether they want to grant the permission; + \li When the user has made their decision, the application calls \l grant() or \l deny(); + \endlist + + Alternatively, an application interested in modifying already granted permissions may use WebEngineProfile::listPermissions() + to get a list of existing permissions associated with a profile, or WebEngineProfile::getPermission() to get + a webEnginePermission object for a specific permission. + + The \l origin property can be used to query which origin the webEnginePermission is associated with, while the + \l feature property describes the associated feature. A website origin is the combination of its scheme, hostname, + and port. Permissions are granted on a per-origin basis; thus, if the web page \c{https://www.example.com:12345/some/page.html} + requests a permission, it will be granted to the origin \c{https://www.example.com:12345/}. + + The usability lifetime of a webEnginePermission is tied either to its associated WebEngineView + (for transient feature types), or WebEngineProfile (for permanent feature types). A transient permission is one which + needs to be explicitly granted or denied every time it's needed (e.g. webcam/screen sharing permission), whereas a permanent + one might be stored inside the current profile, depending on the value of WebEngineProfile::persistentPermissionsPolicy. + You can check whether a webEnginePermission is in a valid state using its \l isValid() property. For invalid objects, calls to \l grant(), + \l deny(), or \l reset() will do nothing, and their \l state() will always be WebEnginePermission.Invalid. + + The feature types Qt WebEngine supports are described in \l feature. + + \sa WebEngineView::permissionRequested, WebEngineProfile::getPermission(), + WebEngineProfile::listPermissions() +*/ + +/*! + \qmlproperty url webEnginePermission::origin + \brief The URL of the permission's associated origin. + + A website origin is the combination of its scheme, hostname, and port. Permissions are granted on a + per-origin basis; thus, if the web page \c{https://www.example.com:12345/some/page.html} + requests a permission, it will be granted to the origin \c{https://www.example.com:12345/}. +*/ + +/*! + \qmlproperty enumeration webEnginePermission::feature + \brief The feature type associated with this permission. + + \value WebEnginePermission.MediaAudioCapture Access to a microphone, or another audio source. This feature is transient. + \value WebEnginePermission.MediaVideoCapture Access to a webcam, or another video source. This feature is transient. + \value WebEnginePermission.MediaAudioVideoCapture Combination of \l MediaAudioCapture and \l MediaVideoCapture. This feature is transient. + \value WebEnginePermission.DesktopVideoCapture Access to the contents of the user's screen. This feature is transient. + \value WebEnginePermission.DesktopAudioVideoCapture Access to the contents of the user's screen, and application audio. This feature is transient. + \value WebEnginePermission.MouseLock Locks the pointer inside an element on the web page. This feature is transient. + \value WebEnginePermission.Notifications Allows the website to send notifications to the user. + \value WebEnginePermission.Geolocation Access to the user's physical location. + \value WebEnginePermission.ClipboardReadWrite Access to the user's clipboard. + \value WebEnginePermission.LocalFontsAccess Access to the fonts installed on the user's machine. Only available on desktops. + \value WebEnginePermission.Unsupported An unsupported feature type. + + \note Transient feature types are ones that will never be remembered by the underlying storage, and will trigger + a permission request every time a website tries to use them. +*/ + +/*! + \qmlproperty enumeration webEnginePermission::state + \brief The current state of the permission. + + \value WebEnginePermission.Invalid Object is in an invalid state, and any attempts to modify the described permission will fail. + \value WebEnginePermission.Ask Either the permission has not been requested before, or the feature() is transient. + \value WebEnginePermission.Granted Permission has already been granted. + \value WebEnginePermission.Denied Permission has already been denied. + + If a permission for the specified \l feature and \l origin has already been granted or denied, + the return value is WebEnginePermission.Granted, or WebEnginePermission.Denied, respectively. + When this is the first time the permission is requested, or if the \l feature is transient, + the return value is WebEnginePermission.Ask. If the object is in an invalid state, the returned + value is WebEnginePermission.Invalid. + + \sa isValid, isTransient +*/ + +/*! + \qmlproperty bool webEnginePermission::isValid + \brief Indicates whether attempts to change the permission's state will be successful. + + An invalid webEnginePermission is either: + \list + \li One whose \l feature is unsupported; + \li One whose \l feature is transient, and the associated page/view has been destroyed; + \li One whose \l feature is permanent, but the associated profile has been destroyed; + \li One whose \l origin is invalid. + \endlist + + \sa isTransient +*/ + +/*! + \qmlmethod void webEnginePermission::grant() + + Allows the associated origin to access the requested feature. Does nothing when \l isValid evaluates to false. + + \sa deny, reset, isValid +*/ + +/*! + \qmlmethod void webEnginePermission::deny() + + Stops the associated origin from accessing the requested feature. Does nothing when \l isValid evaluates to false. + + \sa grant, reset, isValid +*/ + +/*! + \qmlmethod void webEnginePermission::reset() + + Removes the permission from the profile's underlying storage. By default, permissions are stored on disk (except for + off-the-record profiles, where permissions are stored in memory and are destroyed with the profile). + This means that an already granted/denied permission will not be requested twice, but will get automatically + granted/denied every subsequent time a website requests it. Calling reset() allows the query to be asked + again the next time the website requests it. + + Does nothing when \l isValid evaluates to false. + + \sa grant, deny, isValid, WebEngineProfile::persistentPermissionsPolicy +*/ + +/*! + \qmlmethod void webEnginePermission::isTransient(WebEnginePermission.Feature feature) + + Returns whether \a feature is transient, meaning that a permission will be requested + every time the associated functionality is used by a web page. +*/ diff --git a/src/webenginequick/doc/src/webengineframe.qdoc b/src/webenginequick/doc/src/webengineframe.qdoc index ef2a5c33d..8f852501e 100644 --- a/src/webenginequick/doc/src/webengineframe.qdoc +++ b/src/webenginequick/doc/src/webengineframe.qdoc @@ -63,3 +63,67 @@ If the frame could not be found, returns a default size with dimensions (-1, -1). */ + +/*! + \qmlproperty bool webEngineFrame::isMainFrame + + Returns \c{true} if this object represents the page's main frame; \c{false} otherwise. +*/ + +/*! + \qmlmethod void webEngineFrame::runJavaScript(string script, variant callback) + \qmlmethod void webEngineFrame::runJavaScript(string script, uint worldId, variant callback) + + Runs the JavaScript code contained in \a script on this frame, without checking + whether the DOM of the page has been constructed. + + To avoid conflicts with other scripts executed on the page, the world in + which the script is run is specified by \a worldId. The world ID values are + the same as provided by QWebEngineScript::ScriptWorldId, and between \c 0 + and \c 256. If you leave out the \c world ID, the script is run in the + \c MainWorld. + + The \a callback parameter is optional. If a callback function is provided, it will be + invoked after the script finishes running. + \code + frame.runJavaScript("document.title", function(result) { console.log(result); }); + \endcode + + Only plain data can be returned from JavaScript as the result value. + Supported data types include all of the JSON data types as well as, for + example, \c{Date} and \c{ArrayBuffer}. Unsupported data types include, for + example, \c{Function} and \c{Promise}. + + The script will run in the same \e world as other scripts that are + part of the loaded site. + + \warning Do not execute lengthy routines in the callback function, because it might block the + rendering of the web content. + + For more information about injecting scripts, see \l {Script Injection}. + For an alternative way to inject scripts, see WebEngineView::userScripts. +*/ + +/*! + \qmlmethod void webEngineFrame::printToPdf(string filePath) + + Prints the frame's current content to a PDF document and stores it + under \a filePath. The resulting document will have A4 page size and + portrait orientation. + + This method issues an asynchronous request for printing the web page into a + PDF and returns immediately. To be informed about the result of the + request, connect to the signal \l WebEngineView::pdfPrintingFinished(). + + \sa WebEngineView::pdfPrintingFinished() +*/ + +/*! + \qmlmethod void webEngineFrame::printToPdf(variant callback) + + Prints the frame's current content to a PDF document and returns it in a byte array. The + resulting document will have A4 page size and portrait orientation. + + The \a callback must take a string parameter. This string will contain the document's data upon + successful printing and an empty string otherwise. +*/ diff --git a/src/webenginequick/doc/src/webengineview_lgpl.qdoc b/src/webenginequick/doc/src/webengineview_lgpl.qdoc index dbaea62e4..f7b17fa7b 100644 --- a/src/webenginequick/doc/src/webengineview_lgpl.qdoc +++ b/src/webenginequick/doc/src/webengineview_lgpl.qdoc @@ -111,10 +111,9 @@ \section2 Platform Features Web pages can request access to platform features, such as geolocation or audio and video - capture devices. The \l featurePermissionRequested() signal is emitted when a web page requests - to make use of a resource. The supported platform features are described by the \l Feature - property. If users grant the permission, the \l grantFeaturePermission() method is used to set - it to \e granted. + capture devices. The \l permissionRequested() signal is emitted when a web page requests + to make use of a resource. The supported platform features are described by the QWebEnginePermission::Feature + property. \section2 Rendering to OpenGL Surface @@ -367,6 +366,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 +382,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. @@ -441,6 +444,7 @@ /*! \qmlmethod void WebEngineView::grantFeaturePermission(url securityOrigin, Feature feature, bool granted) \since QtWebEngine 1.1 + \deprecated [6.8] Use webEnginePermission.grant() or webEnginePermission.deny() instead. Sets or unsets the permission, depending on \a granted, for the web site identified by \a securityOrigin to use \a feature. @@ -497,6 +501,7 @@ /*! \qmlsignal WebEngineView::featurePermissionRequested(url securityOrigin, Feature feature) \since QtWebEngine 1.1 + \deprecated [6.8] Use \l permissionRequested() instead. This signal is emitted when the web site identified by \a securityOrigin requests to make use of the resource or device identified by \a feature. @@ -505,6 +510,15 @@ */ /*! + \qmlsignal WebEngineView::permissionRequested(webEnginePermission permission) + \since QtWebEngine 6.8 + + This signal is emitted when a web site requests to make use of a feature (e.g. geolocation access, + permission to send notifications). The \a permission object can queried for the requesting URL + and the \c{WebEnginePermission.Feature} it's asking for, as well as to grant or deny permission. +*/ + +/*! \qmlsignal WebEngineView::loadingChanged(WebEngineLoadingInfo loadingInfo) This signal is emitted when a page load begins, ends, or fails. @@ -840,6 +854,7 @@ /*! \qmlproperty enumeration WebEngineView::Feature + \deprecated [6.8] Replaced by WebEnginePermission.Feature. Describes the platform feature access categories that the user may be asked to grant or deny access to: @@ -1343,14 +1358,27 @@ \qmlsignal WebEngineView::printRequested \since QtWebEngine 1.8 - This signal is emitted when the JavaScript \c{window.print()} method is called or the user pressed the print - button of PDF viewer plugin. + This signal is emitted when the JavaScript \c{window.print()} method is called on the main + frame, or the user pressed the print button of PDF viewer plugin. Typically, the signal handler can simply call printToPdf(). + Since QtWebEngine 6.8, this signal is only emitted for the main frame, instead of being emitted + for any frame that requests printing. + \sa printToPdf */ /*! + \qmlsignal WebEngineView::printRequestedByFrame(webEngineFrame frame) + \since QtWebEngine 6.8 + + This signal is emitted when the JavaScript \c{window.print()} method is called on \a frame. + If the frame is the main frame, \c{printRequested} is emitted instead. + + \sa printRequested +*/ + +/*! \qmlsignal WebEngineView::selectClientCertificate(WebEngineClientCertificateSelection clientCertificateSelection) \since QtWebEngine 1.9 @@ -1598,5 +1626,14 @@ \sa QWebEngineWebAuthUxRequest */ +/*! + \qmlsignal WebEngineView::zoomFactorChanged(qreal factor); + \since QtWebEngine 6.8 + + This signal is emitted whenever the zoom \a factor for the page changes. + + \sa zoomFactor +*/ + \sa {WebEngine Qt Quick Custom Touch Handle Example} */ diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp index 5b47d67bf..ebb818cbd 100644 --- a/src/webenginewidgets/api/qwebengineview.cpp +++ b/src/webenginewidgets/api/qwebengineview.cpp @@ -30,6 +30,7 @@ #include <QStyle> #include <QGuiApplication> #include <QQuickWidget> +#include <QtWidgets/private/qapplication_p.h> #if QT_CONFIG(accessibility) #include "qwebengine_accessible_p.h" @@ -187,6 +188,8 @@ public: { auto parentWidget = QQuickWidget::parentWidget(); if (parentWidget) { + if (QApplicationPrivate::wheel_widget) + QApplicationPrivate::wheel_widget = nullptr; QSpontaneKeyEvent::makeSpontaneous(ev); qApp->notify(parentWidget, ev); } @@ -884,6 +887,12 @@ void QWebEngineViewPrivate::printRequested() }); } +void QWebEngineViewPrivate::printRequestedByFrame(QWebEngineFrame frame) +{ + Q_Q(QWebEngineView); + QTimer::singleShot(0, q, [q, frame]() { Q_EMIT q->printRequestedByFrame(frame); }); +} + bool QWebEngineViewPrivate::isVisible() const { Q_Q(const QWebEngineView); @@ -1427,7 +1436,20 @@ void QWebEngineView::printToPdf(const std::function<void(const QByteArray&)> &re button of PDF viewer plugin. Typically, the signal handler can simply call print(). - \sa print() + Since 6.8, this signal is only emitted for the main frame, instead of being emitted + for any frame that requests printing. + + \sa printRequestedByFrame(), print() +*/ + +/*! + \fn void QWebEngineView::printRequestedByFrame(QWebEngineFrame frame) + \since 6.8 + + This signal is emitted when the JavaScript \c{window.print()} method is called on \a frame. + If the frame is the main frame, \c{printRequested} is emitted instead. + + \sa printRequested(), print() */ /*! @@ -1465,17 +1487,21 @@ void QWebEngineView::printToPdf(const std::function<void(const QByteArray&)> &re void QWebEngineView::print(QPrinter *printer) { #if QT_CONFIG(webengine_printing_and_pdf) - if (page()->d_ptr->currentPrinter) { + auto *dPage = page()->d_ptr.get(); + if (dPage->currentPrinter) { qWarning("Cannot print page on printer %ls: Already printing on a device.", qUtf16Printable(printer->printerName())); return; } - page()->d_ptr->currentPrinter = printer; - page()->d_ptr->ensureInitialized(); - page()->d_ptr->adapter->printToPDFCallbackResult(printer->pageLayout(), - printer->pageRanges(), - printer->colorMode() == QPrinter::Color, - false); + dPage->currentPrinter = printer; + dPage->ensureInitialized(); + std::function callback = [dPage](QSharedPointer<QByteArray> result) { + dPage->didPrintPage(std::move(result)); + }; + dPage->adapter->printToPDFCallbackResult(std::move(callback), printer->pageLayout(), + printer->pageRanges(), + printer->colorMode() == QPrinter::Color, false, + QtWebEngineCore::WebContentsAdapter::kUseMainFrameId); #else Q_UNUSED(printer); Q_EMIT printFinished(false); diff --git a/src/webenginewidgets/api/qwebengineview.h b/src/webenginewidgets/api/qwebengineview.h index f93d61b12..008aaa032 100644 --- a/src/webenginewidgets/api/qwebengineview.h +++ b/src/webenginewidgets/api/qwebengineview.h @@ -114,6 +114,7 @@ Q_SIGNALS: int exitCode); void pdfPrintingFinished(const QString &filePath, bool success); void printRequested(); + void printRequestedByFrame(QWebEngineFrame frame); void printFinished(bool success); protected: diff --git a/src/webenginewidgets/api/qwebengineview_p.h b/src/webenginewidgets/api/qwebengineview_p.h index aa330ac23..389bc4a66 100644 --- a/src/webenginewidgets/api/qwebengineview_p.h +++ b/src/webenginewidgets/api/qwebengineview_p.h @@ -73,6 +73,7 @@ public: void didPrintPage(QPrinter *&printer, QSharedPointer<QByteArray> result) override; void didPrintPageToPdf(const QString &filePath, bool success) override; void printRequested() override; + void printRequestedByFrame(QWebEngineFrame frame) override; void showAutofillPopup(QtWebEngineCore::AutofillPopupController *controller, const QRect &bounds, bool autoselectFirstSuggestion) override; void hideAutofillPopup() override; diff --git a/src/webenginewidgets/doc/snippets/push-notifications/commands b/src/webenginewidgets/doc/snippets/push-notifications/commands index aee9761c1..077538e2e 100644 --- a/src/webenginewidgets/doc/snippets/push-notifications/commands +++ b/src/webenginewidgets/doc/snippets/push-notifications/commands @@ -11,7 +11,7 @@ npm install web-push express //! [1] //! [2] -./node_odules/.bin/web-push generate-vapid-keys +./node_modules/.bin/web-push generate-vapid-keys //! [2] //! [3] |